__init__.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """Extensions to the 'distutils' for large or complex distributions"""
  2. import os
  3. import sys
  4. import distutils.core
  5. import distutils.filelist
  6. from distutils.core import Command as _Command
  7. from distutils.util import convert_path
  8. from fnmatch import fnmatchcase
  9. import setuptools.version
  10. from setuptools.extension import Extension
  11. from setuptools.dist import Distribution, Feature, _get_unpatched
  12. from setuptools.depends import Require
  13. from setuptools.compat import filterfalse
  14. __all__ = [
  15. 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
  16. 'find_packages'
  17. ]
  18. __version__ = setuptools.version.__version__
  19. bootstrap_install_from = None
  20. # If we run 2to3 on .py files, should we also convert docstrings?
  21. # Default: yes; assume that we can detect doctests reliably
  22. run_2to3_on_doctests = True
  23. # Standard package names for fixer packages
  24. lib2to3_fixer_packages = ['lib2to3.fixes']
  25. class PackageFinder(object):
  26. @classmethod
  27. def find(cls, where='.', exclude=(), include=('*',)):
  28. """Return a list all Python packages found within directory 'where'
  29. 'where' should be supplied as a "cross-platform" (i.e. URL-style)
  30. path; it will be converted to the appropriate local path syntax.
  31. 'exclude' is a sequence of package names to exclude; '*' can be used
  32. as a wildcard in the names, such that 'foo.*' will exclude all
  33. subpackages of 'foo' (but not 'foo' itself).
  34. 'include' is a sequence of package names to include. If it's
  35. specified, only the named packages will be included. If it's not
  36. specified, all found packages will be included. 'include' can contain
  37. shell style wildcard patterns just like 'exclude'.
  38. The list of included packages is built up first and then any
  39. explicitly excluded packages are removed from it.
  40. """
  41. out = cls._find_packages_iter(convert_path(where))
  42. out = cls.require_parents(out)
  43. includes = cls._build_filter(*include)
  44. excludes = cls._build_filter('ez_setup', '*__pycache__', *exclude)
  45. out = filter(includes, out)
  46. out = filterfalse(excludes, out)
  47. return list(out)
  48. @staticmethod
  49. def require_parents(packages):
  50. """
  51. Exclude any apparent package that apparently doesn't include its
  52. parent.
  53. For example, exclude 'foo.bar' if 'foo' is not present.
  54. """
  55. found = []
  56. for pkg in packages:
  57. base, sep, child = pkg.rpartition('.')
  58. if base and base not in found:
  59. continue
  60. found.append(pkg)
  61. yield pkg
  62. @staticmethod
  63. def _all_dirs(base_path):
  64. """
  65. Return all dirs in base_path, relative to base_path
  66. """
  67. for root, dirs, files in os.walk(base_path, followlinks=True):
  68. for dir in dirs:
  69. yield os.path.relpath(os.path.join(root, dir), base_path)
  70. @classmethod
  71. def _find_packages_iter(cls, base_path):
  72. dirs = cls._all_dirs(base_path)
  73. suitable = filterfalse(lambda n: '.' in n, dirs)
  74. return (
  75. path.replace(os.path.sep, '.')
  76. for path in suitable
  77. if cls._looks_like_package(os.path.join(base_path, path))
  78. )
  79. @staticmethod
  80. def _looks_like_package(path):
  81. return os.path.isfile(os.path.join(path, '__init__.py'))
  82. @staticmethod
  83. def _build_filter(*patterns):
  84. """
  85. Given a list of patterns, return a callable that will be true only if
  86. the input matches one of the patterns.
  87. """
  88. return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)
  89. class PEP420PackageFinder(PackageFinder):
  90. @staticmethod
  91. def _looks_like_package(path):
  92. return True
  93. find_packages = PackageFinder.find
  94. setup = distutils.core.setup
  95. _Command = _get_unpatched(_Command)
  96. class Command(_Command):
  97. __doc__ = _Command.__doc__
  98. command_consumes_arguments = False
  99. def __init__(self, dist, **kw):
  100. # Add support for keyword arguments
  101. _Command.__init__(self,dist)
  102. for k,v in kw.items():
  103. setattr(self,k,v)
  104. def reinitialize_command(self, command, reinit_subcommands=0, **kw):
  105. cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
  106. for k,v in kw.items():
  107. setattr(cmd,k,v) # update command with keywords
  108. return cmd
  109. distutils.core.Command = Command # we can't patch distutils.cmd, alas
  110. def findall(dir = os.curdir):
  111. """Find all files under 'dir' and return the list of full filenames
  112. (relative to 'dir').
  113. """
  114. all_files = []
  115. for base, dirs, files in os.walk(dir):
  116. if base==os.curdir or base.startswith(os.curdir+os.sep):
  117. base = base[2:]
  118. if base:
  119. files = [os.path.join(base, f) for f in files]
  120. all_files.extend(filter(os.path.isfile, files))
  121. return all_files
  122. distutils.filelist.findall = findall # fix findall bug in distutils.
  123. # sys.dont_write_bytecode was introduced in Python 2.6.
  124. _dont_write_bytecode = getattr(sys, 'dont_write_bytecode',
  125. bool(os.environ.get("PYTHONDONTWRITEBYTECODE")))