summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnderson Bravalheri <andersonbravalheri@gmail.com>2023-03-07 09:46:16 +0000
committerAnderson Bravalheri <andersonbravalheri@gmail.com>2023-03-07 10:13:20 +0000
commitd30dcf5296ecf93046abd46d4039f24704679734 (patch)
tree982001e5fbc4a4e344a95c6b14a3202a11002a10
parentf51eccd769cab0297c64e4d007bef42544326431 (diff)
downloadpython-setuptools-git-d30dcf5296ecf93046abd46d4039f24704679734.tar.gz
Add pruning heuristics to PackageFinder based on exclude
-rw-r--r--setuptools/discovery.py34
1 files changed, 22 insertions, 12 deletions
diff --git a/setuptools/discovery.py b/setuptools/discovery.py
index f053dba8..3110b727 100644
--- a/setuptools/discovery.py
+++ b/setuptools/discovery.py
@@ -44,7 +44,6 @@ from glob import glob
from pathlib import Path
from typing import (
TYPE_CHECKING,
- Callable,
Dict,
Iterable,
Iterator,
@@ -61,7 +60,6 @@ from distutils import log
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 @@ class _Finder:
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 @@ class _Finder:
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 @@ class PackageFinder(_Finder):
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)