diff --git a/CHANGELOG.md b/CHANGELOG.md index eff85d24..4aa60e59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog -## v8.2.1 +## v8.3.0 + +### Fixed + +- fix #1013: use modern importlib_metadata in all cases to dedup distribution objects that must shadow based on pythonpath priority + starting with python 3.10 this is part of python itself + +## v8.2.1 (yanked due to legacy python issues) ### Fixed diff --git a/pyproject.toml b/pyproject.toml index 8b927f15..0d133f5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,7 @@ build-backend = "_own_version_helper:build_meta" requires = [ "setuptools>=61", 'tomli<=2.0.2; python_version < "3.11"', + 'importlib-metadata>=4.6; python_version < "3.10"', ] backend-path = [ ".", @@ -43,9 +44,10 @@ dynamic = [ dependencies = [ "packaging>=20", # https://github.com/pypa/setuptools-scm/issues/1112 - re-pin in a breaking release - "setuptools", # >=61", + "setuptools", # >= 61", 'tomli>=1; python_version < "3.11"', 'typing-extensions; python_version < "3.10"', + 'importlib-metadata>=4.6; python_version < "3.10"', ] [project.optional-dependencies] docs = [ @@ -69,38 +71,49 @@ test = [ ] toml = [ ] + [project.urls] documentation = "https://setuptools-scm.readthedocs.io/" repository = "https://github.com/pypa/setuptools-scm/" + [project.entry-points."distutils.setup_keywords"] use_scm_version = "setuptools_scm._integration.setuptools:version_keyword" + [project.entry-points."pipx.run"] setuptools-scm = "setuptools_scm._cli:main" setuptools_scm = "setuptools_scm._cli:main" + [project.entry-points."setuptools.file_finders"] setuptools_scm = "setuptools_scm._file_finders:find_files" + [project.entry-points."setuptools.finalize_distribution_options"] setuptools_scm = "setuptools_scm._integration.setuptools:infer_version" + [project.entry-points."setuptools_scm.files_command"] ".git" = "setuptools_scm._file_finders.git:git_find_files" ".hg" = "setuptools_scm._file_finders.hg:hg_find_files" + [project.entry-points."setuptools_scm.files_command_fallback"] ".git_archival.txt" = "setuptools_scm._file_finders.git:git_archive_find_files" ".hg_archival.txt" = "setuptools_scm._file_finders.hg:hg_archive_find_files" + [project.entry-points."setuptools_scm.local_scheme"] dirty-tag = "setuptools_scm.version:get_local_dirty_tag" no-local-version = "setuptools_scm.version:get_no_local_node" node-and-date = "setuptools_scm.version:get_local_node_and_date" node-and-timestamp = "setuptools_scm.version:get_local_node_and_timestamp" + [project.entry-points."setuptools_scm.parse_scm"] ".git" = "setuptools_scm.git:parse" ".hg" = "setuptools_scm.hg:parse" + [project.entry-points."setuptools_scm.parse_scm_fallback"] ".git_archival.txt" = "setuptools_scm.git:parse_archival" ".hg_archival.txt" = "setuptools_scm.hg:parse_archival" PKG-INFO = "setuptools_scm.fallbacks:parse_pkginfo" "pyproject.toml" = "setuptools_scm.fallbacks:fallback_version" "setup.py" = "setuptools_scm.fallbacks:fallback_version" + [project.entry-points."setuptools_scm.version_scheme"] "calver-by-date" = "setuptools_scm.version:calver_by_date" "guess-next-dev" = "setuptools_scm.version:guess_next_dev_version" @@ -133,7 +146,7 @@ order-by-type = true ignore = ["PP305", "GH103", "GH212", "MY100", "PC111", "PC160", "PC170", "PC180", "PC901"] [tool.pytest.ini_options] -minversion = "7" +minversion = "8" testpaths = ["testing"] filterwarnings = [ "error", diff --git a/src/setuptools_scm/_entrypoints.py b/src/setuptools_scm/_entrypoints.py index 811fb5f5..08e74b77 100644 --- a/src/setuptools_scm/_entrypoints.py +++ b/src/setuptools_scm/_entrypoints.py @@ -17,30 +17,12 @@ from ._config import Configuration from ._config import ParseFunction - -from importlib.metadata import EntryPoint as EntryPoint - if sys.version_info[:2] < (3, 10): - from importlib.metadata import entry_points as legacy_entry_points - - class EntryPoints: - _groupdata: list[EntryPoint] - - def __init__(self, groupdata: list[EntryPoint]) -> None: - self._groupdata = groupdata - - def select(self, name: str) -> EntryPoints: - return EntryPoints([x for x in self._groupdata if x.name == name]) - - def __iter__(self) -> Iterator[EntryPoint]: - return iter(self._groupdata) - - def entry_points(group: str) -> EntryPoints: - return EntryPoints(legacy_entry_points()[group]) - + from importlib_metadata import EntryPoint as EntryPoint + from importlib_metadata import entry_points as entry_points else: - from importlib.metadata import EntryPoints - from importlib.metadata import entry_points + from importlib.metadata import EntryPoint as EntryPoint + from importlib.metadata import entry_points as entry_points log = _log.log.getChild("entrypoints") @@ -61,15 +43,8 @@ def version_from_entrypoint( return None -def iter_entry_points(group: str, name: str | None = None) -> Iterator[EntryPoint]: - eps: EntryPoints = entry_points(group=group) - res = eps if name is None else eps.select(name=name) - - return iter(res) - - def _get_ep(group: str, name: str) -> Any | None: - for ep in iter_entry_points(group, name): + for ep in entry_points(group=group, name=name): log.debug("ep found: %s", ep.name) return ep.load() return None diff --git a/src/setuptools_scm/_file_finders/__init__.py b/src/setuptools_scm/_file_finders/__init__.py index 8201bae1..a3bf01c1 100644 --- a/src/setuptools_scm/_file_finders/__init__.py +++ b/src/setuptools_scm/_file_finders/__init__.py @@ -1,6 +1,5 @@ from __future__ import annotations -import itertools import os from typing import TYPE_CHECKING @@ -8,7 +7,8 @@ from .. import _log from .. import _types as _t -from .._entrypoints import iter_entry_points +from .._entrypoints import EntryPoint +from .._entrypoints import entry_points from .pathtools import norm_real if TYPE_CHECKING: @@ -102,10 +102,11 @@ def is_toplevel_acceptable(toplevel: str | None) -> TypeGuard[str]: def find_files(path: _t.PathT = "") -> list[str]: - for ep in itertools.chain( - iter_entry_points("setuptools_scm.files_command"), - iter_entry_points("setuptools_scm.files_command_fallback"), - ): + eps: list[EntryPoint] = [ + *entry_points(group="setuptools_scm.files_command"), + *entry_points(group="setuptools_scm.files_command_fallback"), + ] + for ep in eps: command: Callable[[_t.PathT], list[str]] = ep.load() res: list[str] = command(path) if res: diff --git a/src/setuptools_scm/discover.py b/src/setuptools_scm/discover.py index 7c1be381..e3dbda91 100644 --- a/src/setuptools_scm/discover.py +++ b/src/setuptools_scm/discover.py @@ -58,10 +58,9 @@ def iter_matching_entrypoints( """ log.debug("looking for ep %s in %s", entrypoint, root) - from ._entrypoints import iter_entry_points for wd in walk_potential_roots(root, config.search_parent_directories): - for ep in iter_entry_points(entrypoint): + for ep in _entrypoints.entry_points(group=entrypoint): if ep.value in _BLOCKED_EP_TARGETS: continue if match_entrypoint(wd, ep.name): diff --git a/src/setuptools_scm/version.py b/src/setuptools_scm/version.py index 633351c9..29803fcd 100644 --- a/src/setuptools_scm/version.py +++ b/src/setuptools_scm/version.py @@ -82,11 +82,10 @@ def callable_or_entrypoint(group: str, callable_or_name: str | Any) -> Any: if callable(callable_or_name): return callable_or_name - from ._entrypoints import iter_entry_points - for ep in iter_entry_points(group, callable_or_name): - log.debug("ep found: %s", ep.name) - return ep.load() + from ._entrypoints import _get_ep + + return _get_ep(group, callable_or_name) def tag_to_version(