From d30dcf5296ecf93046abd46d4039f24704679734 Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Tue, 7 Mar 2023 09:46:16 +0000 Subject: [PATCH 1/2] Add pruning heuristics to PackageFinder based on exclude --- setuptools/discovery.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/setuptools/discovery.py b/setuptools/discovery.py index f053dba837..3110b72794 100644 --- a/setuptools/discovery.py +++ b/setuptools/discovery.py @@ -44,7 +44,6 @@ from pathlib import Path from typing import ( TYPE_CHECKING, - Callable, Dict, Iterable, Iterator, @@ -61,7 +60,6 @@ from distutils.util import convert_path _Path = Union[str, os.PathLike] -_Filter = Callable[[str], bool] StrIter = Iterator[str] chain_iter = itertools.chain.from_iterable @@ -75,6 +73,22 @@ def _valid_name(path: _Path) -> bool: return os.path.basename(path).isidentifier() +class _Filter: + """ + Given a list of patterns, create a callable that will be true only if + the input matches at least one of the patterns. + """ + + def __init__(self, *patterns: str): + self._patterns = dict.fromkeys(patterns) + + def __call__(self, item: str) -> bool: + return any(fnmatchcase(item, pat) for pat in self._patterns) + + def __contains__(self, item: str) -> bool: + return item in self._patterns + + class _Finder: """Base class that exposes functionality for module/package finders""" @@ -111,8 +125,8 @@ def find( return list( cls._find_iter( convert_path(str(where)), - cls._build_filter(*cls.ALWAYS_EXCLUDE, *exclude), - cls._build_filter(*include), + _Filter(*cls.ALWAYS_EXCLUDE, *exclude), + _Filter(*include), ) ) @@ -120,14 +134,6 @@ def find( def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter: raise NotImplementedError - @staticmethod - def _build_filter(*patterns: str) -> _Filter: - """ - Given a list of patterns, return a callable that will be true only if - the input matches at least one of the patterns. - """ - return lambda name: any(fnmatchcase(name, pat) for pat in patterns) - class PackageFinder(_Finder): """ @@ -160,6 +166,10 @@ def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter if include(package) and not exclude(package): yield package + # Early pruning if there is nothing else to be scanned + if f"{package}*" in exclude or f"{package}.*" in exclude: + continue + # Keep searching subdirectories, as there may be more packages # down there, even if the parent was excluded. dirs.append(dir) From ea4a2050e5bb0d09b13fad73879777c745739f0f Mon Sep 17 00:00:00 2001 From: Anderson Bravalheri Date: Tue, 7 Mar 2023 10:16:39 +0000 Subject: [PATCH 2/2] Add news fragment --- changelog.d/3846.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/3846.misc.rst diff --git a/changelog.d/3846.misc.rst b/changelog.d/3846.misc.rst new file mode 100644 index 0000000000..7774cb4dcc --- /dev/null +++ b/changelog.d/3846.misc.rst @@ -0,0 +1 @@ +Add pruning heuristics to ``PackageFinder`` based on ``exclude``.