Commit d3969808 authored by Jason R. Coombs's avatar Jason R. Coombs

Pulled find_package functionality into a PackageFinder class

parent 77b7c39d
...@@ -29,61 +29,70 @@ run_2to3_on_doctests = True ...@@ -29,61 +29,70 @@ run_2to3_on_doctests = True
# Standard package names for fixer packages # Standard package names for fixer packages
lib2to3_fixer_packages = ['lib2to3.fixes'] lib2to3_fixer_packages = ['lib2to3.fixes']
def find_packages(where='.', exclude=(), include=('*',)):
"""Return a list all Python packages found within directory 'where' class PackageFinder(object):
@classmethod
'where' should be supplied as a "cross-platform" (i.e. URL-style) path; it def find(cls, where='.', exclude=(), include=('*',)):
will be converted to the appropriate local path syntax. 'exclude' is a """Return a list all Python packages found within directory 'where'
sequence of package names to exclude; '*' can be used as a wildcard in the
names, such that 'foo.*' will exclude all subpackages of 'foo' (but not 'where' should be supplied as a "cross-platform" (i.e. URL-style) path; it
'foo' itself). will be converted to the appropriate local path syntax. 'exclude' is a
sequence of package names to exclude; '*' can be used as a wildcard in the
'include' is a sequence of package names to include. If it's specified, names, such that 'foo.*' will exclude all subpackages of 'foo' (but not
only the named packages will be included. If it's not specified, all found 'foo' itself).
packages will be included. 'include' can contain shell style wildcard
patterns just like 'exclude'. 'include' is a sequence of package names to include. If it's specified,
only the named packages will be included. If it's not specified, all found
The list of included packages is built up first and then any explicitly packages will be included. 'include' can contain shell style wildcard
excluded packages are removed from it. patterns just like 'exclude'.
"""
out = _find_packages_iter(convert_path(where)) The list of included packages is built up first and then any explicitly
includes = _build_filter(*include) excluded packages are removed from it.
excludes = _build_filter('ez_setup', '*__pycache__', *exclude) """
out = filter(includes, out) out = cls._find_packages_iter(convert_path(where))
out = filterfalse(excludes, out) includes = cls._build_filter(*include)
return list(out) excludes = cls._build_filter('ez_setup', '*__pycache__', *exclude)
out = filter(includes, out)
def _all_dirs(base_path): out = filterfalse(excludes, out)
""" return list(out)
Return all dirs in base_path, relative to base_path
""" @staticmethod
for root, dirs, files in os.walk(base_path): def _all_dirs(base_path):
for dir in dirs: """
yield os.path.relpath(os.path.join(root, dir), base_path) Return all dirs in base_path, relative to base_path
"""
def _find_packages_iter(base_path): for root, dirs, files in os.walk(base_path):
dirs = _all_dirs(base_path) for dir in dirs:
suitable = filterfalse(lambda n: '.' in n, dirs) yield os.path.relpath(os.path.join(root, dir), base_path)
packages = (
path @classmethod
for path in suitable def _find_packages_iter(cls, base_path):
if _looks_like_package(os.path.join(base_path, path)) dirs = cls._all_dirs(base_path)
) suitable = filterfalse(lambda n: '.' in n, dirs)
for pkg_path in packages: packages = (
yield pkg_path.replace(os.path.sep, '.') path
for path in suitable
def _looks_like_package(path): if cls._looks_like_package(os.path.join(base_path, path))
return ( )
os.path.isfile(os.path.join(path, '__init__.py')) for pkg_path in packages:
or sys.version_info[:2] >= (3, 3) # PEP 420 yield pkg_path.replace(os.path.sep, '.')
)
@staticmethod
def _build_filter(*patterns): def _looks_like_package(path):
""" return (
Given a list of patterns, return a callable that will be true only if os.path.isfile(os.path.join(path, '__init__.py'))
the input matches one of the patterns. or sys.version_info[:2] >= (3, 3) # PEP 420
""" )
return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)
@staticmethod
def _build_filter(*patterns):
"""
Given a list of patterns, return a callable that will be true only if
the input matches one of the patterns.
"""
return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)
find_packages = PackageFinder.find
setup = distutils.core.setup setup = distutils.core.setup
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment