diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e3ce764e..cb10874f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,7 +3,7 @@ name: main on: push: branches: - - main + - "*" tags: - "*" @@ -20,7 +20,7 @@ jobs: matrix: name: [ "windows-py38", - "windows-py311", + "windows-py313", "windows-pypy3", "ubuntu-py38-pytestmain", @@ -29,6 +29,7 @@ jobs: "ubuntu-py310", "ubuntu-py311", "ubuntu-py312", + "ubuntu-py313", "ubuntu-pypy3", "ubuntu-benchmark", ] @@ -38,10 +39,10 @@ jobs: python: "3.8" os: windows-latest tox_env: "py38" - - name: "windows-py311" - python: "3.10" + - name: "windows-py313" + python: "3.13" os: windows-latest - tox_env: "py311" + tox_env: "py313" - name: "windows-pypy3" python: "pypy3.9" os: windows-latest @@ -71,10 +72,15 @@ jobs: tox_env: "py311" use_coverage: true - name: "ubuntu-py312" - python: "3.12-dev" + python: "3.12" os: ubuntu-latest tox_env: "py312" use_coverage: true + - name: "ubuntu-py313" + python: "3.13" + os: ubuntu-latest + tox_env: "py313" + use_coverage: true - name: "ubuntu-pypy3" python: "pypy3.9" os: ubuntu-latest @@ -94,6 +100,7 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} + allow-prereleases: true - name: Install dependencies run: | @@ -140,4 +147,6 @@ jobs: run: python -m build --sdist --wheel --outdir dist/ - name: Publish package - uses: pypa/gh-action-pypi-publish@v1.8.14 + uses: pypa/gh-action-pypi-publish@v1.11.0 + with: + attestations: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d4897454..6dd890e2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.4.8" + rev: "v0.7.2" hooks: - id: ruff args: ["--fix"] @@ -25,12 +25,12 @@ repos: hooks: - id: rst-backticks - repo: https://github.com/asottile/pyupgrade - rev: v3.16.0 + rev: v3.19.0 hooks: - id: pyupgrade args: [--py38-plus] - repo: https://github.com/asottile/blacken-docs - rev: 1.16.0 + rev: 1.19.1 hooks: - id: blacken-docs additional_dependencies: [black==24.2.0] @@ -43,7 +43,7 @@ repos: language: python additional_dependencies: [pygments, restructuredtext_lint] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.10.0 + rev: v1.13.0 hooks: - id: mypy files: ^(src/|testing/) diff --git a/pyproject.toml b/pyproject.toml index e286825c..eab66d9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,55 @@ [build-system] requires = [ # sync with setup.py until we discard non-pep-517/518 - "setuptools>=45.0", - "setuptools-scm[toml]>=6.2.3", + "setuptools>=65.0", + "setuptools-scm[toml]>=8.0", ] build-backend = "setuptools.build_meta" +[project] +name = "pluggy" +license = {text = "MIT"} +authors = [{name = "Holger Krekel", email = "holger@merlinux.eu"}] +classifiers = [ + "Development Status :: 6 - Mature", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: POSIX", + "Operating System :: Microsoft :: Windows", + "Operating System :: MacOS :: MacOS X", + "Topic :: Software Development :: Testing", + "Topic :: Software Development :: Libraries", + "Topic :: Utilities", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] +description = "plugin and hook calling mechanisms for python" +readme = {file = "README.rst", content-type = "text/x-rst"} +requires-python = ">=3.8" + +dynamic = ["version"] +[project.optional-dependencies] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[tool.setuptools] +packages = ["pluggy"] +package-dir = {""="src"} +package-data = {"pluggy" = ["py.typed"]} + [tool.ruff.lint] -select = [ - "I", # isort +extend-select = [ + "I", # isort + "UP", ] [tool.ruff.lint.isort] @@ -21,7 +61,7 @@ known-local-folder = ["pluggy"] lines-after-imports = 2 [tool.setuptools_scm] -write_to = "src/pluggy/_version.py" +version_file = "src/pluggy/_version.py" [tool.towncrier] package = "pluggy" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 1e34d361..00000000 --- a/setup.cfg +++ /dev/null @@ -1,49 +0,0 @@ -[metadata] -name = pluggy -description = plugin and hook calling mechanisms for python -long_description = file: README.rst -long_description_content_type = text/x-rst -license = MIT -platforms = unix, linux, osx, win32 -author = Holger Krekel -author_email = holger@merlinux.eu -url = https://github.com/pytest-dev/pluggy -classifiers = - Development Status :: 6 - Mature - Intended Audience :: Developers - License :: OSI Approved :: MIT License - Operating System :: POSIX - Operating System :: Microsoft :: Windows - Operating System :: MacOS :: MacOS X - Topic :: Software Development :: Testing - Topic :: Software Development :: Libraries - Topic :: Utilities - Programming Language :: Python :: Implementation :: CPython - Programming Language :: Python :: Implementation :: PyPy - Programming Language :: Python :: 3 - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - -[options] -packages = - pluggy -python_requires = >=3.8 -package_dir = - =src -setup_requires = - setuptools-scm -[options.extras_require] -dev = - pre-commit - tox -testing = - pytest - pytest-benchmark -[options.package_data] -pluggy = py.typed - -[devpi:upload] -formats=sdist.tgz,bdist_wheel diff --git a/setup.py b/setup.py deleted file mode 100644 index ed442375..00000000 --- a/setup.py +++ /dev/null @@ -1,5 +0,0 @@ -from setuptools import setup - - -if __name__ == "__main__": - setup(use_scm_version={"write_to": "src/pluggy/_version.py"}) diff --git a/src/pluggy/_hooks.py b/src/pluggy/_hooks.py index 362d7918..a81d2b28 100644 --- a/src/pluggy/_hooks.py +++ b/src/pluggy/_hooks.py @@ -489,8 +489,8 @@ def _verify_all_args_are_provided(self, kwargs: Mapping[str, object]) -> None: if argname not in kwargs.keys() ) warnings.warn( - "Argument(s) {} which are declared in the hookspec " - "cannot be found in this hook call".format(notincall), + f"Argument(s) {notincall} which are declared in the hookspec " + "cannot be found in this hook call", stacklevel=2, ) break diff --git a/src/pluggy/_manager.py b/src/pluggy/_manager.py index 9998dd81..d778334b 100644 --- a/src/pluggy/_manager.py +++ b/src/pluggy/_manager.py @@ -70,7 +70,7 @@ def project_name(self) -> str: name: str = self.metadata["name"] return name - def __getattr__(self, attr: str, default=None): + def __getattr__(self, attr: str, default: Any | None = None) -> Any: return getattr(self._dist, attr, default) def __dir__(self) -> list[str]: @@ -138,14 +138,14 @@ def register(self, plugin: _Plugin, name: str | None = None) -> str | None: if self._name2plugin.get(plugin_name, -1) is None: return None # blocked plugin, return None to indicate no registration raise ValueError( - "Plugin name already registered: %s=%s\n%s" - % (plugin_name, plugin, self._name2plugin) + "Plugin name already registered: " + f"{plugin_name}={plugin}\n{self._name2plugin}" ) if plugin in self._name2plugin.values(): raise ValueError( - "Plugin already registered under a different name: %s=%s\n%s" - % (plugin_name, plugin, self._name2plugin) + "Plugin already registered under a different name: " + f"{plugin_name}={plugin}\n{self._name2plugin}" ) # XXX if an error happens we should make sure no state has been @@ -329,8 +329,8 @@ def _verify_hook(self, hook: HookCaller, hookimpl: HookImpl) -> None: if hook.is_historic() and (hookimpl.hookwrapper or hookimpl.wrapper): raise PluginValidationError( hookimpl.plugin, - "Plugin %r\nhook %r\nhistoric incompatible with yield/wrapper/hookwrapper" - % (hookimpl.plugin_name, hook.name), + f"Plugin {hookimpl.plugin_name!r}\nhook {hook.name!r}\n" + "historic incompatible with yield/wrapper/hookwrapper", ) assert hook.spec is not None @@ -342,15 +342,10 @@ def _verify_hook(self, hook: HookCaller, hookimpl: HookImpl) -> None: if notinspec: raise PluginValidationError( hookimpl.plugin, - "Plugin %r for hook %r\nhookimpl definition: %s\n" - "Argument(s) %s are declared in the hookimpl but " - "can not be found in the hookspec" - % ( - hookimpl.plugin_name, - hook.name, - _formatdef(hookimpl.function), - notinspec, - ), + f"Plugin {hookimpl.plugin_name!r} for hook {hook.name!r}\n" + f"hookimpl definition: {_formatdef(hookimpl.function)}\n" + f"Argument(s) {notinspec} are declared in the hookimpl but " + "can not be found in the hookspec", ) if hook.spec.warn_on_impl_args: @@ -364,18 +359,18 @@ def _verify_hook(self, hook: HookCaller, hookimpl: HookImpl) -> None: ) and not inspect.isgeneratorfunction(hookimpl.function): raise PluginValidationError( hookimpl.plugin, - "Plugin %r for hook %r\nhookimpl definition: %s\n" + f"Plugin {hookimpl.plugin_name!r} for hook {hook.name!r}\n" + f"hookimpl definition: {_formatdef(hookimpl.function)}\n" "Declared as wrapper=True or hookwrapper=True " - "but function is not a generator function" - % (hookimpl.plugin_name, hook.name, _formatdef(hookimpl.function)), + "but function is not a generator function", ) if hookimpl.wrapper and hookimpl.hookwrapper: raise PluginValidationError( hookimpl.plugin, - "Plugin %r for hook %r\nhookimpl definition: %s\n" - "The wrapper=True and hookwrapper=True options are mutually exclusive" - % (hookimpl.plugin_name, hook.name, _formatdef(hookimpl.function)), + f"Plugin {hookimpl.plugin_name!r} for hook {hook.name!r}\n" + f"hookimpl definition: {_formatdef(hookimpl.function)}\n" + "The wrapper=True and hookwrapper=True options are mutually exclusive", ) def check_pending(self) -> None: @@ -390,8 +385,7 @@ def check_pending(self) -> None: if not hookimpl.optionalhook: raise PluginValidationError( hookimpl.plugin, - "unknown hook %r in plugin %r" - % (name, hookimpl.plugin), + f"unknown hook {name!r} in plugin {hookimpl.plugin!r}", ) def load_setuptools_entrypoints(self, group: str, name: str | None = None) -> int: diff --git a/tox.ini b/tox.ini index de464a07..f30f17b8 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=docs,py{38,39,310,311,py3},py{38}-pytest{main} +envlist=docs,py{38,39,310,311,312,313,py3},py{38}-pytest{main} [testenv] commands= @@ -31,7 +31,7 @@ commands = sphinx-build -W -b html {toxinidir}/docs {toxinidir}/build/html-docs -t changelog_towncrier_draft {posargs:} [pytest] -minversion=2.0 +minversion=8.0 testpaths = testing #--pyargs --doctest-modules --ignore=.tox addopts=-r a @@ -40,6 +40,7 @@ filterwarnings = [flake8] max-line-length=99 +min-python-version = 3.8 [testenv:release] description = do a release, required posarg of the version number