diff options
author | Jason R. Coombs <jaraco@jaraco.com> | 2013-06-18 08:44:39 -0500 |
---|---|---|
committer | Jason R. Coombs <jaraco@jaraco.com> | 2013-06-18 08:44:39 -0500 |
commit | fb8c7cf0abc9ce58b8a6f0621c0a9909fb9b8eff (patch) | |
tree | 95cae06260f49e011fc045000fc1531dbc0e0cf5 /pkg_resources.py | |
parent | 32ba6930fa97bbeac9392cac3ed49aac87fd1018 (diff) | |
parent | db678072da41b75408680dab3e23c1b76573bf1d (diff) | |
download | external_python_setuptools-fb8c7cf0abc9ce58b8a6f0621c0a9909fb9b8eff.tar.gz external_python_setuptools-fb8c7cf0abc9ce58b8a6f0621c0a9909fb9b8eff.tar.bz2 external_python_setuptools-fb8c7cf0abc9ce58b8a6f0621c0a9909fb9b8eff.zip |
Merge with upstream
--HG--
branch : distribute
Diffstat (limited to 'pkg_resources.py')
-rw-r--r-- | pkg_resources.py | 112 |
1 files changed, 105 insertions, 7 deletions
diff --git a/pkg_resources.py b/pkg_resources.py index ae1f6c4d..9f4c55bc 100644 --- a/pkg_resources.py +++ b/pkg_resources.py @@ -535,6 +535,10 @@ class WorkingSet(object): """ seen = {} for item in self.entries: + if item not in self.entry_keys: + # workaround a cache issue + continue + for key in self.entry_keys[item]: if key not in seen: seen[key]=1 @@ -1350,6 +1354,14 @@ class DefaultProvider(EggProvider): register_loader_type(type(None), DefaultProvider) +try: + # CPython >=3.3 + import _frozen_importlib +except ImportError: + pass +else: + register_loader_type(_frozen_importlib.SourceFileLoader, DefaultProvider) + class EmptyProvider(NullProvider): """Provider that returns nothing for all requests""" @@ -1763,7 +1775,7 @@ def find_on_path(importer, path_item, only=False): # scan for .egg and .egg-info in directory for entry in os.listdir(path_item): lower = entry.lower() - if lower.endswith('.egg-info'): + if lower.endswith('.egg-info') or lower.endswith('.dist-info'): fullpath = os.path.join(path_item, entry) if os.path.isdir(fullpath): # egg-info directory, allow getting metadata @@ -1784,6 +1796,14 @@ def find_on_path(importer, path_item, only=False): break register_finder(ImpWrapper,find_on_path) +try: + # CPython >=3.3 + import _frozen_importlib +except ImportError: + pass +else: + register_finder(_frozen_importlib.FileFinder, find_on_path) + _declare_state('dict', _namespace_handlers={}) _declare_state('dict', _namespace_packages={}) @@ -1883,6 +1903,14 @@ def file_ns_handler(importer, path_item, packageName, module): register_namespace_handler(ImpWrapper,file_ns_handler) register_namespace_handler(zipimport.zipimporter,file_ns_handler) +try: + # CPython >=3.3 + import _frozen_importlib +except ImportError: + pass +else: + register_namespace_handler(_frozen_importlib.FileFinder, file_ns_handler) + def null_ns_handler(importer, path_item, packageName, module): return None @@ -1941,7 +1969,7 @@ replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get def _parse_version_parts(s): for part in component_re.split(s): part = replace(part,part) - if not part or part=='.': + if part in ['', '.']: continue if part[:1] in '0123456789': yield part.zfill(8) # pad for numeric comparison @@ -1984,8 +2012,6 @@ def parse_version(s): parts = [] for part in _parse_version_parts(s.lower()): if part.startswith('*'): - if part<'*final': # remove '-' before a prerelease tag - while parts and parts[-1]=='*final-': parts.pop() # remove trailing zeros from each series of numeric parts while parts and parts[-1]=='00000000': parts.pop() @@ -2122,6 +2148,8 @@ def _remove_md5_fragment(location): class Distribution(object): """Wrap an actual or potential sys.path entry w/metadata""" + PKG_INFO = 'PKG-INFO' + def __init__(self, location=None, metadata=None, project_name=None, version=None, py_version=PY_MAJOR, platform=None, precedence = EGG_DIST @@ -2139,12 +2167,14 @@ class Distribution(object): def from_location(cls,location,basename,metadata=None,**kw): project_name, version, py_version, platform = [None]*4 basename, ext = os.path.splitext(basename) - if ext.lower() in (".egg",".egg-info"): + if ext.lower() in _distributionImpl: + # .dist-info gets much metadata differently match = EGG_NAME(basename) if match: project_name, version, py_version, platform = match.group( 'name','ver','pyver','plat' ) + cls = _distributionImpl[ext.lower()] return cls( location, metadata, project_name=project_name, version=version, py_version=py_version, platform=platform, **kw @@ -2207,13 +2237,13 @@ class Distribution(object): try: return self._version except AttributeError: - for line in self._get_metadata('PKG-INFO'): + for line in self._get_metadata(self.PKG_INFO): if line.lower().startswith('version:'): self._version = safe_version(line.split(':',1)[1].strip()) return self._version else: raise ValueError( - "Missing 'Version:' header and/or PKG-INFO file", self + "Missing 'Version:' header and/or %s file" % self.PKG_INFO, self ) version = property(version) @@ -2444,6 +2474,74 @@ class Distribution(object): extras = property(extras) +class DistInfoDistribution(Distribution): + """Wrap an actual or potential sys.path entry w/metadata, .dist-info style""" + PKG_INFO = 'METADATA' + EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])") + + @property + def _parsed_pkg_info(self): + """Parse and cache metadata""" + try: + return self._pkg_info + except AttributeError: + from email.parser import Parser + self._pkg_info = Parser().parsestr(self.get_metadata(self.PKG_INFO)) + return self._pkg_info + + @property + def _dep_map(self): + try: + return self.__dep_map + except AttributeError: + self.__dep_map = self._compute_dependencies() + return self.__dep_map + + def _preparse_requirement(self, requires_dist): + """Convert 'Foobar (1); baz' to ('Foobar ==1', 'baz') + Split environment marker, add == prefix to version specifiers as + necessary, and remove parenthesis. + """ + parts = requires_dist.split(';', 1) + [''] + distvers = parts[0].strip() + mark = parts[1].strip() + distvers = re.sub(self.EQEQ, r"\1==\2\3", distvers) + distvers = distvers.replace('(', '').replace(')', '') + return (distvers, mark) + + def _compute_dependencies(self): + """Recompute this distribution's dependencies.""" + from _markerlib import compile as compile_marker + dm = self.__dep_map = {None: []} + + reqs = [] + # Including any condition expressions + for req in self._parsed_pkg_info.get_all('Requires-Dist') or []: + distvers, mark = self._preparse_requirement(req) + parsed = parse_requirements(distvers).next() + parsed.marker_fn = compile_marker(mark) + reqs.append(parsed) + + def reqs_for_extra(extra): + for req in reqs: + if req.marker_fn(override={'extra':extra}): + yield req + + common = frozenset(reqs_for_extra(None)) + dm[None].extend(common) + + for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []: + extra = safe_extra(extra.strip()) + dm[extra] = list(frozenset(reqs_for_extra(extra)) - common) + + return dm + + +_distributionImpl = {'.egg': Distribution, + '.egg-info': Distribution, + '.dist-info': DistInfoDistribution } + + def issue_warning(*args,**kw): level = 1 g = globals() |