Skip to content

Commit

Permalink
Add pruning heuristics to PackageFinder based on exclude (#3846)
Browse files Browse the repository at this point in the history
  • Loading branch information
abravalheri committed Mar 8, 2023
2 parents 2f4a3c0 + ea4a205 commit e6f4bd7
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 12 deletions.
1 change: 1 addition & 0 deletions changelog.d/3846.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add pruning heuristics to ``PackageFinder`` based on ``exclude``.
34 changes: 22 additions & 12 deletions setuptools/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
from pathlib import Path
from typing import (
TYPE_CHECKING,
Callable,
Dict,
Iterable,
Iterator,
Expand All @@ -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
Expand All @@ -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"""

Expand Down Expand Up @@ -111,23 +125,15 @@ 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),
)
)

@classmethod
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):
"""
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit e6f4bd7

Please sign in to comment.