Home | History | Annotate | Download | only in pkg_resources
      1 # coding: utf-8
      2 """
      3 Package resource API
      4 --------------------
      5 
      6 A resource is a logical file contained within a package, or a logical
      7 subdirectory thereof.  The package resource API expects resource names
      8 to have their path parts separated with ``/``, *not* whatever the local
      9 path separator is.  Do not use os.path operations to manipulate resource
     10 names being passed into the API.
     11 
     12 The package resource API is designed to work with normal filesystem packages,
     13 .egg files, and unpacked .egg files.  It can also work in a limited way with
     14 .zip files and with custom PEP 302 loaders that support the ``get_data()``
     15 method.
     16 """
     17 
     18 from __future__ import absolute_import
     19 
     20 import sys
     21 import os
     22 import io
     23 import time
     24 import re
     25 import types
     26 import zipfile
     27 import zipimport
     28 import warnings
     29 import stat
     30 import functools
     31 import pkgutil
     32 import operator
     33 import platform
     34 import collections
     35 import plistlib
     36 import email.parser
     37 import errno
     38 import tempfile
     39 import textwrap
     40 import itertools
     41 import inspect
     42 from pkgutil import get_importer
     43 
     44 try:
     45     import _imp
     46 except ImportError:
     47     # Python 3.2 compatibility
     48     import imp as _imp
     49 
     50 from pkg_resources.extern import six
     51 from pkg_resources.extern.six.moves import urllib, map, filter
     52 
     53 # capture these to bypass sandboxing
     54 from os import utime
     55 try:
     56     from os import mkdir, rename, unlink
     57     WRITE_SUPPORT = True
     58 except ImportError:
     59     # no write support, probably under GAE
     60     WRITE_SUPPORT = False
     61 
     62 from os import open as os_open
     63 from os.path import isdir, split
     64 
     65 try:
     66     import importlib.machinery as importlib_machinery
     67     # access attribute to force import under delayed import mechanisms.
     68     importlib_machinery.__name__
     69 except ImportError:
     70     importlib_machinery = None
     71 
     72 from . import py31compat
     73 from pkg_resources.extern import appdirs
     74 from pkg_resources.extern import packaging
     75 __import__('pkg_resources.extern.packaging.version')
     76 __import__('pkg_resources.extern.packaging.specifiers')
     77 __import__('pkg_resources.extern.packaging.requirements')
     78 __import__('pkg_resources.extern.packaging.markers')
     79 
     80 
     81 if (3, 0) < sys.version_info < (3, 3):
     82     raise RuntimeError("Python 3.3 or later is required")
     83 
     84 if six.PY2:
     85     # Those builtin exceptions are only defined in Python 3
     86     PermissionError = None
     87     NotADirectoryError = None
     88 
     89 # declare some globals that will be defined later to
     90 # satisfy the linters.
     91 require = None
     92 working_set = None
     93 add_activation_listener = None
     94 resources_stream = None
     95 cleanup_resources = None
     96 resource_dir = None
     97 resource_stream = None
     98 set_extraction_path = None
     99 resource_isdir = None
    100 resource_string = None
    101 iter_entry_points = None
    102 resource_listdir = None
    103 resource_filename = None
    104 resource_exists = None
    105 _distribution_finders = None
    106 _namespace_handlers = None
    107 _namespace_packages = None
    108 
    109 
    110 class PEP440Warning(RuntimeWarning):
    111     """
    112     Used when there is an issue with a version or specifier not complying with
    113     PEP 440.
    114     """
    115 
    116 
    117 def parse_version(v):
    118     try:
    119         return packaging.version.Version(v)
    120     except packaging.version.InvalidVersion:
    121         return packaging.version.LegacyVersion(v)
    122 
    123 
    124 _state_vars = {}
    125 
    126 
    127 def _declare_state(vartype, **kw):
    128     globals().update(kw)
    129     _state_vars.update(dict.fromkeys(kw, vartype))
    130 
    131 
    132 def __getstate__():
    133     state = {}
    134     g = globals()
    135     for k, v in _state_vars.items():
    136         state[k] = g['_sget_' + v](g[k])
    137     return state
    138 
    139 
    140 def __setstate__(state):
    141     g = globals()
    142     for k, v in state.items():
    143         g['_sset_' + _state_vars[k]](k, g[k], v)
    144     return state
    145 
    146 
    147 def _sget_dict(val):
    148     return val.copy()
    149 
    150 
    151 def _sset_dict(key, ob, state):
    152     ob.clear()
    153     ob.update(state)
    154 
    155 
    156 def _sget_object(val):
    157     return val.__getstate__()
    158 
    159 
    160 def _sset_object(key, ob, state):
    161     ob.__setstate__(state)
    162 
    163 
    164 _sget_none = _sset_none = lambda *args: None
    165 
    166 
    167 def get_supported_platform():
    168     """Return this platform's maximum compatible version.
    169 
    170     distutils.util.get_platform() normally reports the minimum version
    171     of Mac OS X that would be required to *use* extensions produced by
    172     distutils.  But what we want when checking compatibility is to know the
    173     version of Mac OS X that we are *running*.  To allow usage of packages that
    174     explicitly require a newer version of Mac OS X, we must also know the
    175     current version of the OS.
    176 
    177     If this condition occurs for any other platform with a version in its
    178     platform strings, this function should be extended accordingly.
    179     """
    180     plat = get_build_platform()
    181     m = macosVersionString.match(plat)
    182     if m is not None and sys.platform == "darwin":
    183         try:
    184             plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3))
    185         except ValueError:
    186             # not Mac OS X
    187             pass
    188     return plat
    189 
    190 
    191 __all__ = [
    192     # Basic resource access and distribution/entry point discovery
    193     'require', 'run_script', 'get_provider', 'get_distribution',
    194     'load_entry_point', 'get_entry_map', 'get_entry_info',
    195     'iter_entry_points',
    196     'resource_string', 'resource_stream', 'resource_filename',
    197     'resource_listdir', 'resource_exists', 'resource_isdir',
    198 
    199     # Environmental control
    200     'declare_namespace', 'working_set', 'add_activation_listener',
    201     'find_distributions', 'set_extraction_path', 'cleanup_resources',
    202     'get_default_cache',
    203 
    204     # Primary implementation classes
    205     'Environment', 'WorkingSet', 'ResourceManager',
    206     'Distribution', 'Requirement', 'EntryPoint',
    207 
    208     # Exceptions
    209     'ResolutionError', 'VersionConflict', 'DistributionNotFound',
    210     'UnknownExtra', 'ExtractionError',
    211 
    212     # Warnings
    213     'PEP440Warning',
    214 
    215     # Parsing functions and string utilities
    216     'parse_requirements', 'parse_version', 'safe_name', 'safe_version',
    217     'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections',
    218     'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker',
    219 
    220     # filesystem utilities
    221     'ensure_directory', 'normalize_path',
    222 
    223     # Distribution "precedence" constants
    224     'EGG_DIST', 'BINARY_DIST', 'SOURCE_DIST', 'CHECKOUT_DIST', 'DEVELOP_DIST',
    225 
    226     # "Provider" interfaces, implementations, and registration/lookup APIs
    227     'IMetadataProvider', 'IResourceProvider', 'FileMetadata',
    228     'PathMetadata', 'EggMetadata', 'EmptyProvider', 'empty_provider',
    229     'NullProvider', 'EggProvider', 'DefaultProvider', 'ZipProvider',
    230     'register_finder', 'register_namespace_handler', 'register_loader_type',
    231     'fixup_namespace_packages', 'get_importer',
    232 
    233     # Deprecated/backward compatibility only
    234     'run_main', 'AvailableDistributions',
    235 ]
    236 
    237 
    238 class ResolutionError(Exception):
    239     """Abstract base for dependency resolution errors"""
    240 
    241     def __repr__(self):
    242         return self.__class__.__name__ + repr(self.args)
    243 
    244 
    245 class VersionConflict(ResolutionError):
    246     """
    247     An already-installed version conflicts with the requested version.
    248 
    249     Should be initialized with the installed Distribution and the requested
    250     Requirement.
    251     """
    252 
    253     _template = "{self.dist} is installed but {self.req} is required"
    254 
    255     @property
    256     def dist(self):
    257         return self.args[0]
    258 
    259     @property
    260     def req(self):
    261         return self.args[1]
    262 
    263     def report(self):
    264         return self._template.format(**locals())
    265 
    266     def with_context(self, required_by):
    267         """
    268         If required_by is non-empty, return a version of self that is a
    269         ContextualVersionConflict.
    270         """
    271         if not required_by:
    272             return self
    273         args = self.args + (required_by,)
    274         return ContextualVersionConflict(*args)
    275 
    276 
    277 class ContextualVersionConflict(VersionConflict):
    278     """
    279     A VersionConflict that accepts a third parameter, the set of the
    280     requirements that required the installed Distribution.
    281     """
    282 
    283     _template = VersionConflict._template + ' by {self.required_by}'
    284 
    285     @property
    286     def required_by(self):
    287         return self.args[2]
    288 
    289 
    290 class DistributionNotFound(ResolutionError):
    291     """A requested distribution was not found"""
    292 
    293     _template = ("The '{self.req}' distribution was not found "
    294                  "and is required by {self.requirers_str}")
    295 
    296     @property
    297     def req(self):
    298         return self.args[0]
    299 
    300     @property
    301     def requirers(self):
    302         return self.args[1]
    303 
    304     @property
    305     def requirers_str(self):
    306         if not self.requirers:
    307             return 'the application'
    308         return ', '.join(self.requirers)
    309 
    310     def report(self):
    311         return self._template.format(**locals())
    312 
    313     def __str__(self):
    314         return self.report()
    315 
    316 
    317 class UnknownExtra(ResolutionError):
    318     """Distribution doesn't have an "extra feature" of the given name"""
    319 
    320 
    321 _provider_factories = {}
    322 
    323 PY_MAJOR = sys.version[:3]
    324 EGG_DIST = 3
    325 BINARY_DIST = 2
    326 SOURCE_DIST = 1
    327 CHECKOUT_DIST = 0
    328 DEVELOP_DIST = -1
    329 
    330 
    331 def register_loader_type(loader_type, provider_factory):
    332     """Register `provider_factory` to make providers for `loader_type`
    333 
    334     `loader_type` is the type or class of a PEP 302 ``module.__loader__``,
    335     and `provider_factory` is a function that, passed a *module* object,
    336     returns an ``IResourceProvider`` for that module.
    337     """
    338     _provider_factories[loader_type] = provider_factory
    339 
    340 
    341 def get_provider(moduleOrReq):
    342     """Return an IResourceProvider for the named module or requirement"""
    343     if isinstance(moduleOrReq, Requirement):
    344         return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]
    345     try:
    346         module = sys.modules[moduleOrReq]
    347     except KeyError:
    348         __import__(moduleOrReq)
    349         module = sys.modules[moduleOrReq]
    350     loader = getattr(module, '__loader__', None)
    351     return _find_adapter(_provider_factories, loader)(module)
    352 
    353 
    354 def _macosx_vers(_cache=[]):
    355     if not _cache:
    356         version = platform.mac_ver()[0]
    357         # fallback for MacPorts
    358         if version == '':
    359             plist = '/System/Library/CoreServices/SystemVersion.plist'
    360             if os.path.exists(plist):
    361                 if hasattr(plistlib, 'readPlist'):
    362                     plist_content = plistlib.readPlist(plist)
    363                     if 'ProductVersion' in plist_content:
    364                         version = plist_content['ProductVersion']
    365 
    366         _cache.append(version.split('.'))
    367     return _cache[0]
    368 
    369 
    370 def _macosx_arch(machine):
    371     return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine)
    372 
    373 
    374 def get_build_platform():
    375     """Return this platform's string for platform-specific distributions
    376 
    377     XXX Currently this is the same as ``distutils.util.get_platform()``, but it
    378     needs some hacks for Linux and Mac OS X.
    379     """
    380     try:
    381         # Python 2.7 or >=3.2
    382         from sysconfig import get_platform
    383     except ImportError:
    384         from distutils.util import get_platform
    385 
    386     plat = get_platform()
    387     if sys.platform == "darwin" and not plat.startswith('macosx-'):
    388         try:
    389             version = _macosx_vers()
    390             machine = os.uname()[4].replace(" ", "_")
    391             return "macosx-%d.%d-%s" % (
    392                 int(version[0]), int(version[1]),
    393                 _macosx_arch(machine),
    394             )
    395         except ValueError:
    396             # if someone is running a non-Mac darwin system, this will fall
    397             # through to the default implementation
    398             pass
    399     return plat
    400 
    401 
    402 macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)")
    403 darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)")
    404 # XXX backward compat
    405 get_platform = get_build_platform
    406 
    407 
    408 def compatible_platforms(provided, required):
    409     """Can code for the `provided` platform run on the `required` platform?
    410 
    411     Returns true if either platform is ``None``, or the platforms are equal.
    412 
    413     XXX Needs compatibility checks for Linux and other unixy OSes.
    414     """
    415     if provided is None or required is None or provided == required:
    416         # easy case
    417         return True
    418 
    419     # Mac OS X special cases
    420     reqMac = macosVersionString.match(required)
    421     if reqMac:
    422         provMac = macosVersionString.match(provided)
    423 
    424         # is this a Mac package?
    425         if not provMac:
    426             # this is backwards compatibility for packages built before
    427             # setuptools 0.6. All packages built after this point will
    428             # use the new macosx designation.
    429             provDarwin = darwinVersionString.match(provided)
    430             if provDarwin:
    431                 dversion = int(provDarwin.group(1))
    432                 macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2))
    433                 if dversion == 7 and macosversion >= "10.3" or \
    434                         dversion == 8 and macosversion >= "10.4":
    435                     return True
    436             # egg isn't macosx or legacy darwin
    437             return False
    438 
    439         # are they the same major version and machine type?
    440         if provMac.group(1) != reqMac.group(1) or \
    441                 provMac.group(3) != reqMac.group(3):
    442             return False
    443 
    444         # is the required OS major update >= the provided one?
    445         if int(provMac.group(2)) > int(reqMac.group(2)):
    446             return False
    447 
    448         return True
    449 
    450     # XXX Linux and other platforms' special cases should go here
    451     return False
    452 
    453 
    454 def run_script(dist_spec, script_name):
    455     """Locate distribution `dist_spec` and run its `script_name` script"""
    456     ns = sys._getframe(1).f_globals
    457     name = ns['__name__']
    458     ns.clear()
    459     ns['__name__'] = name
    460     require(dist_spec)[0].run_script(script_name, ns)
    461 
    462 
    463 # backward compatibility
    464 run_main = run_script
    465 
    466 
    467 def get_distribution(dist):
    468     """Return a current distribution object for a Requirement or string"""
    469     if isinstance(dist, six.string_types):
    470         dist = Requirement.parse(dist)
    471     if isinstance(dist, Requirement):
    472         dist = get_provider(dist)
    473     if not isinstance(dist, Distribution):
    474         raise TypeError("Expected string, Requirement, or Distribution", dist)
    475     return dist
    476 
    477 
    478 def load_entry_point(dist, group, name):
    479     """Return `name` entry point of `group` for `dist` or raise ImportError"""
    480     return get_distribution(dist).load_entry_point(group, name)
    481 
    482 
    483 def get_entry_map(dist, group=None):
    484     """Return the entry point map for `group`, or the full entry map"""
    485     return get_distribution(dist).get_entry_map(group)
    486 
    487 
    488 def get_entry_info(dist, group, name):
    489     """Return the EntryPoint object for `group`+`name`, or ``None``"""
    490     return get_distribution(dist).get_entry_info(group, name)
    491 
    492 
    493 class IMetadataProvider:
    494     def has_metadata(name):
    495         """Does the package's distribution contain the named metadata?"""
    496 
    497     def get_metadata(name):
    498         """The named metadata resource as a string"""
    499 
    500     def get_metadata_lines(name):
    501         """Yield named metadata resource as list of non-blank non-comment lines
    502 
    503        Leading and trailing whitespace is stripped from each line, and lines
    504        with ``#`` as the first non-blank character are omitted."""
    505 
    506     def metadata_isdir(name):
    507         """Is the named metadata a directory?  (like ``os.path.isdir()``)"""
    508 
    509     def metadata_listdir(name):
    510         """List of metadata names in the directory (like ``os.listdir()``)"""
    511 
    512     def run_script(script_name, namespace):
    513         """Execute the named script in the supplied namespace dictionary"""
    514 
    515 
    516 class IResourceProvider(IMetadataProvider):
    517     """An object that provides access to package resources"""
    518 
    519     def get_resource_filename(manager, resource_name):
    520         """Return a true filesystem path for `resource_name`
    521 
    522         `manager` must be an ``IResourceManager``"""
    523 
    524     def get_resource_stream(manager, resource_name):
    525         """Return a readable file-like object for `resource_name`
    526 
    527         `manager` must be an ``IResourceManager``"""
    528 
    529     def get_resource_string(manager, resource_name):
    530         """Return a string containing the contents of `resource_name`
    531 
    532         `manager` must be an ``IResourceManager``"""
    533 
    534     def has_resource(resource_name):
    535         """Does the package contain the named resource?"""
    536 
    537     def resource_isdir(resource_name):
    538         """Is the named resource a directory?  (like ``os.path.isdir()``)"""
    539 
    540     def resource_listdir(resource_name):
    541         """List of resource names in the directory (like ``os.listdir()``)"""
    542 
    543 
    544 class WorkingSet(object):
    545     """A collection of active distributions on sys.path (or a similar list)"""
    546 
    547     def __init__(self, entries=None):
    548         """Create working set from list of path entries (default=sys.path)"""
    549         self.entries = []
    550         self.entry_keys = {}
    551         self.by_key = {}
    552         self.callbacks = []
    553 
    554         if entries is None:
    555             entries = sys.path
    556 
    557         for entry in entries:
    558             self.add_entry(entry)
    559 
    560     @classmethod
    561     def _build_master(cls):
    562         """
    563         Prepare the master working set.
    564         """
    565         ws = cls()
    566         try:
    567             from __main__ import __requires__
    568         except ImportError:
    569             # The main program does not list any requirements
    570             return ws
    571 
    572         # ensure the requirements are met
    573         try:
    574             ws.require(__requires__)
    575         except VersionConflict:
    576             return cls._build_from_requirements(__requires__)
    577 
    578         return ws
    579 
    580     @classmethod
    581     def _build_from_requirements(cls, req_spec):
    582         """
    583         Build a working set from a requirement spec. Rewrites sys.path.
    584         """
    585         # try it without defaults already on sys.path
    586         # by starting with an empty path
    587         ws = cls([])
    588         reqs = parse_requirements(req_spec)
    589         dists = ws.resolve(reqs, Environment())
    590         for dist in dists:
    591             ws.add(dist)
    592 
    593         # add any missing entries from sys.path
    594         for entry in sys.path:
    595             if entry not in ws.entries:
    596                 ws.add_entry(entry)
    597 
    598         # then copy back to sys.path
    599         sys.path[:] = ws.entries
    600         return ws
    601 
    602     def add_entry(self, entry):
    603         """Add a path item to ``.entries``, finding any distributions on it
    604 
    605         ``find_distributions(entry, True)`` is used to find distributions
    606         corresponding to the path entry, and they are added.  `entry` is
    607         always appended to ``.entries``, even if it is already present.
    608         (This is because ``sys.path`` can contain the same value more than
    609         once, and the ``.entries`` of the ``sys.path`` WorkingSet should always
    610         equal ``sys.path``.)
    611         """
    612         self.entry_keys.setdefault(entry, [])
    613         self.entries.append(entry)
    614         for dist in find_distributions(entry, True):
    615             self.add(dist, entry, False)
    616 
    617     def __contains__(self, dist):
    618         """True if `dist` is the active distribution for its project"""
    619         return self.by_key.get(dist.key) == dist
    620 
    621     def find(self, req):
    622         """Find a distribution matching requirement `req`
    623 
    624         If there is an active distribution for the requested project, this
    625         returns it as long as it meets the version requirement specified by
    626         `req`.  But, if there is an active distribution for the project and it
    627         does *not* meet the `req` requirement, ``VersionConflict`` is raised.
    628         If there is no active distribution for the requested project, ``None``
    629         is returned.
    630         """
    631         dist = self.by_key.get(req.key)
    632         if dist is not None and dist not in req:
    633             # XXX add more info
    634             raise VersionConflict(dist, req)
    635         return dist
    636 
    637     def iter_entry_points(self, group, name=None):
    638         """Yield entry point objects from `group` matching `name`
    639 
    640         If `name` is None, yields all entry points in `group` from all
    641         distributions in the working set, otherwise only ones matching
    642         both `group` and `name` are yielded (in distribution order).
    643         """
    644         for dist in self:
    645             entries = dist.get_entry_map(group)
    646             if name is None:
    647                 for ep in entries.values():
    648                     yield ep
    649             elif name in entries:
    650                 yield entries[name]
    651 
    652     def run_script(self, requires, script_name):
    653         """Locate distribution for `requires` and run `script_name` script"""
    654         ns = sys._getframe(1).f_globals
    655         name = ns['__name__']
    656         ns.clear()
    657         ns['__name__'] = name
    658         self.require(requires)[0].run_script(script_name, ns)
    659 
    660     def __iter__(self):
    661         """Yield distributions for non-duplicate projects in the working set
    662 
    663         The yield order is the order in which the items' path entries were
    664         added to the working set.
    665         """
    666         seen = {}
    667         for item in self.entries:
    668             if item not in self.entry_keys:
    669                 # workaround a cache issue
    670                 continue
    671 
    672             for key in self.entry_keys[item]:
    673                 if key not in seen:
    674                     seen[key] = 1
    675                     yield self.by_key[key]
    676 
    677     def add(self, dist, entry=None, insert=True, replace=False):
    678         """Add `dist` to working set, associated with `entry`
    679 
    680         If `entry` is unspecified, it defaults to the ``.location`` of `dist`.
    681         On exit from this routine, `entry` is added to the end of the working
    682         set's ``.entries`` (if it wasn't already present).
    683 
    684         `dist` is only added to the working set if it's for a project that
    685         doesn't already have a distribution in the set, unless `replace=True`.
    686         If it's added, any callbacks registered with the ``subscribe()`` method
    687         will be called.
    688         """
    689         if insert:
    690             dist.insert_on(self.entries, entry, replace=replace)
    691 
    692         if entry is None:
    693             entry = dist.location
    694         keys = self.entry_keys.setdefault(entry, [])
    695         keys2 = self.entry_keys.setdefault(dist.location, [])
    696         if not replace and dist.key in self.by_key:
    697             # ignore hidden distros
    698             return
    699 
    700         self.by_key[dist.key] = dist
    701         if dist.key not in keys:
    702             keys.append(dist.key)
    703         if dist.key not in keys2:
    704             keys2.append(dist.key)
    705         self._added_new(dist)
    706 
    707     def resolve(self, requirements, env=None, installer=None,
    708                 replace_conflicting=False, extras=None):
    709         """List all distributions needed to (recursively) meet `requirements`
    710 
    711         `requirements` must be a sequence of ``Requirement`` objects.  `env`,
    712         if supplied, should be an ``Environment`` instance.  If
    713         not supplied, it defaults to all distributions available within any
    714         entry or distribution in the working set.  `installer`, if supplied,
    715         will be invoked with each requirement that cannot be met by an
    716         already-installed distribution; it should return a ``Distribution`` or
    717         ``None``.
    718 
    719         Unless `replace_conflicting=True`, raises a VersionConflict exception
    720         if
    721         any requirements are found on the path that have the correct name but
    722         the wrong version.  Otherwise, if an `installer` is supplied it will be
    723         invoked to obtain the correct version of the requirement and activate
    724         it.
    725 
    726         `extras` is a list of the extras to be used with these requirements.
    727         This is important because extra requirements may look like `my_req;
    728         extra = "my_extra"`, which would otherwise be interpreted as a purely
    729         optional requirement.  Instead, we want to be able to assert that these
    730         requirements are truly required.
    731         """
    732 
    733         # set up the stack
    734         requirements = list(requirements)[::-1]
    735         # set of processed requirements
    736         processed = {}
    737         # key -> dist
    738         best = {}
    739         to_activate = []
    740 
    741         req_extras = _ReqExtras()
    742 
    743         # Mapping of requirement to set of distributions that required it;
    744         # useful for reporting info about conflicts.
    745         required_by = collections.defaultdict(set)
    746 
    747         while requirements:
    748             # process dependencies breadth-first
    749             req = requirements.pop(0)
    750             if req in processed:
    751                 # Ignore cyclic or redundant dependencies
    752                 continue
    753 
    754             if not req_extras.markers_pass(req, extras):
    755                 continue
    756 
    757             dist = best.get(req.key)
    758             if dist is None:
    759                 # Find the best distribution and add it to the map
    760                 dist = self.by_key.get(req.key)
    761                 if dist is None or (dist not in req and replace_conflicting):
    762                     ws = self
    763                     if env is None:
    764                         if dist is None:
    765                             env = Environment(self.entries)
    766                         else:
    767                             # Use an empty environment and workingset to avoid
    768                             # any further conflicts with the conflicting
    769                             # distribution
    770                             env = Environment([])
    771                             ws = WorkingSet([])
    772                     dist = best[req.key] = env.best_match(
    773                         req, ws, installer,
    774                         replace_conflicting=replace_conflicting
    775                     )
    776                     if dist is None:
    777                         requirers = required_by.get(req, None)
    778                         raise DistributionNotFound(req, requirers)
    779                 to_activate.append(dist)
    780             if dist not in req:
    781                 # Oops, the "best" so far conflicts with a dependency
    782                 dependent_req = required_by[req]
    783                 raise VersionConflict(dist, req).with_context(dependent_req)
    784 
    785             # push the new requirements onto the stack
    786             new_requirements = dist.requires(req.extras)[::-1]
    787             requirements.extend(new_requirements)
    788 
    789             # Register the new requirements needed by req
    790             for new_requirement in new_requirements:
    791                 required_by[new_requirement].add(req.project_name)
    792                 req_extras[new_requirement] = req.extras
    793 
    794             processed[req] = True
    795 
    796         # return list of distros to activate
    797         return to_activate
    798 
    799     def find_plugins(
    800             self, plugin_env, full_env=None, installer=None, fallback=True):
    801         """Find all activatable distributions in `plugin_env`
    802 
    803         Example usage::
    804 
    805             distributions, errors = working_set.find_plugins(
    806                 Environment(plugin_dirlist)
    807             )
    808             # add plugins+libs to sys.path
    809             map(working_set.add, distributions)
    810             # display errors
    811             print('Could not load', errors)
    812 
    813         The `plugin_env` should be an ``Environment`` instance that contains
    814         only distributions that are in the project's "plugin directory" or
    815         directories. The `full_env`, if supplied, should be an ``Environment``
    816         contains all currently-available distributions.  If `full_env` is not
    817         supplied, one is created automatically from the ``WorkingSet`` this
    818         method is called on, which will typically mean that every directory on
    819         ``sys.path`` will be scanned for distributions.
    820 
    821         `installer` is a standard installer callback as used by the
    822         ``resolve()`` method. The `fallback` flag indicates whether we should
    823         attempt to resolve older versions of a plugin if the newest version
    824         cannot be resolved.
    825 
    826         This method returns a 2-tuple: (`distributions`, `error_info`), where
    827         `distributions` is a list of the distributions found in `plugin_env`
    828         that were loadable, along with any other distributions that are needed
    829         to resolve their dependencies.  `error_info` is a dictionary mapping
    830         unloadable plugin distributions to an exception instance describing the
    831         error that occurred. Usually this will be a ``DistributionNotFound`` or
    832         ``VersionConflict`` instance.
    833         """
    834 
    835         plugin_projects = list(plugin_env)
    836         # scan project names in alphabetic order
    837         plugin_projects.sort()
    838 
    839         error_info = {}
    840         distributions = {}
    841 
    842         if full_env is None:
    843             env = Environment(self.entries)
    844             env += plugin_env
    845         else:
    846             env = full_env + plugin_env
    847 
    848         shadow_set = self.__class__([])
    849         # put all our entries in shadow_set
    850         list(map(shadow_set.add, self))
    851 
    852         for project_name in plugin_projects:
    853 
    854             for dist in plugin_env[project_name]:
    855 
    856                 req = [dist.as_requirement()]
    857 
    858                 try:
    859                     resolvees = shadow_set.resolve(req, env, installer)
    860 
    861                 except ResolutionError as v:
    862                     # save error info
    863                     error_info[dist] = v
    864                     if fallback:
    865                         # try the next older version of project
    866                         continue
    867                     else:
    868                         # give up on this project, keep going
    869                         break
    870 
    871                 else:
    872                     list(map(shadow_set.add, resolvees))
    873                     distributions.update(dict.fromkeys(resolvees))
    874 
    875                     # success, no need to try any more versions of this project
    876                     break
    877 
    878         distributions = list(distributions)
    879         distributions.sort()
    880 
    881         return distributions, error_info
    882 
    883     def require(self, *requirements):
    884         """Ensure that distributions matching `requirements` are activated
    885 
    886         `requirements` must be a string or a (possibly-nested) sequence
    887         thereof, specifying the distributions and versions required.  The
    888         return value is a sequence of the distributions that needed to be
    889         activated to fulfill the requirements; all relevant distributions are
    890         included, even if they were already activated in this working set.
    891         """
    892         needed = self.resolve(parse_requirements(requirements))
    893 
    894         for dist in needed:
    895             self.add(dist)
    896 
    897         return needed
    898 
    899     def subscribe(self, callback, existing=True):
    900         """Invoke `callback` for all distributions
    901 
    902         If `existing=True` (default),
    903         call on all existing ones, as well.
    904         """
    905         if callback in self.callbacks:
    906             return
    907         self.callbacks.append(callback)
    908         if not existing:
    909             return
    910         for dist in self:
    911             callback(dist)
    912 
    913     def _added_new(self, dist):
    914         for callback in self.callbacks:
    915             callback(dist)
    916 
    917     def __getstate__(self):
    918         return (
    919             self.entries[:], self.entry_keys.copy(), self.by_key.copy(),
    920             self.callbacks[:]
    921         )
    922 
    923     def __setstate__(self, e_k_b_c):
    924         entries, keys, by_key, callbacks = e_k_b_c
    925         self.entries = entries[:]
    926         self.entry_keys = keys.copy()
    927         self.by_key = by_key.copy()
    928         self.callbacks = callbacks[:]
    929 
    930 
    931 class _ReqExtras(dict):
    932     """
    933     Map each requirement to the extras that demanded it.
    934     """
    935 
    936     def markers_pass(self, req, extras=None):
    937         """
    938         Evaluate markers for req against each extra that
    939         demanded it.
    940 
    941         Return False if the req has a marker and fails
    942         evaluation. Otherwise, return True.
    943         """
    944         extra_evals = (
    945             req.marker.evaluate({'extra': extra})
    946             for extra in self.get(req, ()) + (extras or (None,))
    947         )
    948         return not req.marker or any(extra_evals)
    949 
    950 
    951 class Environment(object):
    952     """Searchable snapshot of distributions on a search path"""
    953 
    954     def __init__(
    955             self, search_path=None, platform=get_supported_platform(),
    956             python=PY_MAJOR):
    957         """Snapshot distributions available on a search path
    958 
    959         Any distributions found on `search_path` are added to the environment.
    960         `search_path` should be a sequence of ``sys.path`` items.  If not
    961         supplied, ``sys.path`` is used.
    962 
    963         `platform` is an optional string specifying the name of the platform
    964         that platform-specific distributions must be compatible with.  If
    965         unspecified, it defaults to the current platform.  `python` is an
    966         optional string naming the desired version of Python (e.g. ``'3.3'``);
    967         it defaults to the current version.
    968 
    969         You may explicitly set `platform` (and/or `python`) to ``None`` if you
    970         wish to map *all* distributions, not just those compatible with the
    971         running platform or Python version.
    972         """
    973         self._distmap = {}
    974         self.platform = platform
    975         self.python = python
    976         self.scan(search_path)
    977 
    978     def can_add(self, dist):
    979         """Is distribution `dist` acceptable for this environment?
    980 
    981         The distribution must match the platform and python version
    982         requirements specified when this environment was created, or False
    983         is returned.
    984         """
    985         py_compat = (
    986             self.python is None
    987             or dist.py_version is None
    988             or dist.py_version == self.python
    989         )
    990         return py_compat and compatible_platforms(dist.platform, self.platform)
    991 
    992     def remove(self, dist):
    993         """Remove `dist` from the environment"""
    994         self._distmap[dist.key].remove(dist)
    995 
    996     def scan(self, search_path=None):
    997         """Scan `search_path` for distributions usable in this environment
    998 
    999         Any distributions found are added to the environment.
   1000         `search_path` should be a sequence of ``sys.path`` items.  If not
   1001         supplied, ``sys.path`` is used.  Only distributions conforming to
   1002         the platform/python version defined at initialization are added.
   1003         """
   1004         if search_path is None:
   1005             search_path = sys.path
   1006 
   1007         for item in search_path:
   1008             for dist in find_distributions(item):
   1009                 self.add(dist)
   1010 
   1011     def __getitem__(self, project_name):
   1012         """Return a newest-to-oldest list of distributions for `project_name`
   1013 
   1014         Uses case-insensitive `project_name` comparison, assuming all the
   1015         project's distributions use their project's name converted to all
   1016         lowercase as their key.
   1017 
   1018         """
   1019         distribution_key = project_name.lower()
   1020         return self._distmap.get(distribution_key, [])
   1021 
   1022     def add(self, dist):
   1023         """Add `dist` if we ``can_add()`` it and it has not already been added
   1024         """
   1025         if self.can_add(dist) and dist.has_version():
   1026             dists = self._distmap.setdefault(dist.key, [])
   1027             if dist not in dists:
   1028                 dists.append(dist)
   1029                 dists.sort(key=operator.attrgetter('hashcmp'), reverse=True)
   1030 
   1031     def best_match(
   1032             self, req, working_set, installer=None, replace_conflicting=False):
   1033         """Find distribution best matching `req` and usable on `working_set`
   1034 
   1035         This calls the ``find(req)`` method of the `working_set` to see if a
   1036         suitable distribution is already active.  (This may raise
   1037         ``VersionConflict`` if an unsuitable version of the project is already
   1038         active in the specified `working_set`.)  If a suitable distribution
   1039         isn't active, this method returns the newest distribution in the
   1040         environment that meets the ``Requirement`` in `req`.  If no suitable
   1041         distribution is found, and `installer` is supplied, then the result of
   1042         calling the environment's ``obtain(req, installer)`` method will be
   1043         returned.
   1044         """
   1045         try:
   1046             dist = working_set.find(req)
   1047         except VersionConflict:
   1048             if not replace_conflicting:
   1049                 raise
   1050             dist = None
   1051         if dist is not None:
   1052             return dist
   1053         for dist in self[req.key]:
   1054             if dist in req:
   1055                 return dist
   1056         # try to download/install
   1057         return self.obtain(req, installer)
   1058 
   1059     def obtain(self, requirement, installer=None):
   1060         """Obtain a distribution matching `requirement` (e.g. via download)
   1061 
   1062         Obtain a distro that matches requirement (e.g. via download).  In the
   1063         base ``Environment`` class, this routine just returns
   1064         ``installer(requirement)``, unless `installer` is None, in which case
   1065         None is returned instead.  This method is a hook that allows subclasses
   1066         to attempt other ways of obtaining a distribution before falling back
   1067         to the `installer` argument."""
   1068         if installer is not None:
   1069             return installer(requirement)
   1070 
   1071     def __iter__(self):
   1072         """Yield the unique project names of the available distributions"""
   1073         for key in self._distmap.keys():
   1074             if self[key]:
   1075                 yield key
   1076 
   1077     def __iadd__(self, other):
   1078         """In-place addition of a distribution or environment"""
   1079         if isinstance(other, Distribution):
   1080             self.add(other)
   1081         elif isinstance(other, Environment):
   1082             for project in other:
   1083                 for dist in other[project]:
   1084                     self.add(dist)
   1085         else:
   1086             raise TypeError("Can't add %r to environment" % (other,))
   1087         return self
   1088 
   1089     def __add__(self, other):
   1090         """Add an environment or distribution to an environment"""
   1091         new = self.__class__([], platform=None, python=None)
   1092         for env in self, other:
   1093             new += env
   1094         return new
   1095 
   1096 
   1097 # XXX backward compatibility
   1098 AvailableDistributions = Environment
   1099 
   1100 
   1101 class ExtractionError(RuntimeError):
   1102     """An error occurred extracting a resource
   1103 
   1104     The following attributes are available from instances of this exception:
   1105 
   1106     manager
   1107         The resource manager that raised this exception
   1108 
   1109     cache_path
   1110         The base directory for resource extraction
   1111 
   1112     original_error
   1113         The exception instance that caused extraction to fail
   1114     """
   1115 
   1116 
   1117 class ResourceManager:
   1118     """Manage resource extraction and packages"""
   1119     extraction_path = None
   1120 
   1121     def __init__(self):
   1122         self.cached_files = {}
   1123 
   1124     def resource_exists(self, package_or_requirement, resource_name):
   1125         """Does the named resource exist?"""
   1126         return get_provider(package_or_requirement).has_resource(resource_name)
   1127 
   1128     def resource_isdir(self, package_or_requirement, resource_name):
   1129         """Is the named resource an existing directory?"""
   1130         return get_provider(package_or_requirement).resource_isdir(
   1131             resource_name
   1132         )
   1133 
   1134     def resource_filename(self, package_or_requirement, resource_name):
   1135         """Return a true filesystem path for specified resource"""
   1136         return get_provider(package_or_requirement).get_resource_filename(
   1137             self, resource_name
   1138         )
   1139 
   1140     def resource_stream(self, package_or_requirement, resource_name):
   1141         """Return a readable file-like object for specified resource"""
   1142         return get_provider(package_or_requirement).get_resource_stream(
   1143             self, resource_name
   1144         )
   1145 
   1146     def resource_string(self, package_or_requirement, resource_name):
   1147         """Return specified resource as a string"""
   1148         return get_provider(package_or_requirement).get_resource_string(
   1149             self, resource_name
   1150         )
   1151 
   1152     def resource_listdir(self, package_or_requirement, resource_name):
   1153         """List the contents of the named resource directory"""
   1154         return get_provider(package_or_requirement).resource_listdir(
   1155             resource_name
   1156         )
   1157 
   1158     def extraction_error(self):
   1159         """Give an error message for problems extracting file(s)"""
   1160 
   1161         old_exc = sys.exc_info()[1]
   1162         cache_path = self.extraction_path or get_default_cache()
   1163 
   1164         tmpl = textwrap.dedent("""
   1165             Can't extract file(s) to egg cache
   1166 
   1167             The following error occurred while trying to extract file(s)
   1168             to the Python egg cache:
   1169 
   1170               {old_exc}
   1171 
   1172             The Python egg cache directory is currently set to:
   1173 
   1174               {cache_path}
   1175 
   1176             Perhaps your account does not have write access to this directory?
   1177             You can change the cache directory by setting the PYTHON_EGG_CACHE
   1178             environment variable to point to an accessible directory.
   1179             """).lstrip()
   1180         err = ExtractionError(tmpl.format(**locals()))
   1181         err.manager = self
   1182         err.cache_path = cache_path
   1183         err.original_error = old_exc
   1184         raise err
   1185 
   1186     def get_cache_path(self, archive_name, names=()):
   1187         """Return absolute location in cache for `archive_name` and `names`
   1188 
   1189         The parent directory of the resulting path will be created if it does
   1190         not already exist.  `archive_name` should be the base filename of the
   1191         enclosing egg (which may not be the name of the enclosing zipfile!),
   1192         including its ".egg" extension.  `names`, if provided, should be a
   1193         sequence of path name parts "under" the egg's extraction location.
   1194 
   1195         This method should only be called by resource providers that need to
   1196         obtain an extraction location, and only for names they intend to
   1197         extract, as it tracks the generated names for possible cleanup later.
   1198         """
   1199         extract_path = self.extraction_path or get_default_cache()
   1200         target_path = os.path.join(extract_path, archive_name + '-tmp', *names)
   1201         try:
   1202             _bypass_ensure_directory(target_path)
   1203         except Exception:
   1204             self.extraction_error()
   1205 
   1206         self._warn_unsafe_extraction_path(extract_path)
   1207 
   1208         self.cached_files[target_path] = 1
   1209         return target_path
   1210 
   1211     @staticmethod
   1212     def _warn_unsafe_extraction_path(path):
   1213         """
   1214         If the default extraction path is overridden and set to an insecure
   1215         location, such as /tmp, it opens up an opportunity for an attacker to
   1216         replace an extracted file with an unauthorized payload. Warn the user
   1217         if a known insecure location is used.
   1218 
   1219         See Distribute #375 for more details.
   1220         """
   1221         if os.name == 'nt' and not path.startswith(os.environ['windir']):
   1222             # On Windows, permissions are generally restrictive by default
   1223             #  and temp directories are not writable by other users, so
   1224             #  bypass the warning.
   1225             return
   1226         mode = os.stat(path).st_mode
   1227         if mode & stat.S_IWOTH or mode & stat.S_IWGRP:
   1228             msg = (
   1229                 "%s is writable by group/others and vulnerable to attack "
   1230                 "when "
   1231                 "used with get_resource_filename. Consider a more secure "
   1232                 "location (set with .set_extraction_path or the "
   1233                 "PYTHON_EGG_CACHE environment variable)." % path
   1234             )
   1235             warnings.warn(msg, UserWarning)
   1236 
   1237     def postprocess(self, tempname, filename):
   1238         """Perform any platform-specific postprocessing of `tempname`
   1239 
   1240         This is where Mac header rewrites should be done; other platforms don't
   1241         have anything special they should do.
   1242 
   1243         Resource providers should call this method ONLY after successfully
   1244         extracting a compressed resource.  They must NOT call it on resources
   1245         that are already in the filesystem.
   1246 
   1247         `tempname` is the current (temporary) name of the file, and `filename`
   1248         is the name it will be renamed to by the caller after this routine
   1249         returns.
   1250         """
   1251 
   1252         if os.name == 'posix':
   1253             # Make the resource executable
   1254             mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777
   1255             os.chmod(tempname, mode)
   1256 
   1257     def set_extraction_path(self, path):
   1258         """Set the base path where resources will be extracted to, if needed.
   1259 
   1260         If you do not call this routine before any extractions take place, the
   1261         path defaults to the return value of ``get_default_cache()``.  (Which
   1262         is based on the ``PYTHON_EGG_CACHE`` environment variable, with various
   1263         platform-specific fallbacks.  See that routine's documentation for more
   1264         details.)
   1265 
   1266         Resources are extracted to subdirectories of this path based upon
   1267         information given by the ``IResourceProvider``.  You may set this to a
   1268         temporary directory, but then you must call ``cleanup_resources()`` to
   1269         delete the extracted files when done.  There is no guarantee that
   1270         ``cleanup_resources()`` will be able to remove all extracted files.
   1271 
   1272         (Note: you may not change the extraction path for a given resource
   1273         manager once resources have been extracted, unless you first call
   1274         ``cleanup_resources()``.)
   1275         """
   1276         if self.cached_files:
   1277             raise ValueError(
   1278                 "Can't change extraction path, files already extracted"
   1279             )
   1280 
   1281         self.extraction_path = path
   1282 
   1283     def cleanup_resources(self, force=False):
   1284         """
   1285         Delete all extracted resource files and directories, returning a list
   1286         of the file and directory names that could not be successfully removed.
   1287         This function does not have any concurrency protection, so it should
   1288         generally only be called when the extraction path is a temporary
   1289         directory exclusive to a single process.  This method is not
   1290         automatically called; you must call it explicitly or register it as an
   1291         ``atexit`` function if you wish to ensure cleanup of a temporary
   1292         directory used for extractions.
   1293         """
   1294         # XXX
   1295 
   1296 
   1297 def get_default_cache():
   1298     """
   1299     Return the ``PYTHON_EGG_CACHE`` environment variable
   1300     or a platform-relevant user cache dir for an app
   1301     named "Python-Eggs".
   1302     """
   1303     return (
   1304         os.environ.get('PYTHON_EGG_CACHE')
   1305         or appdirs.user_cache_dir(appname='Python-Eggs')
   1306     )
   1307 
   1308 
   1309 def safe_name(name):
   1310     """Convert an arbitrary string to a standard distribution name
   1311 
   1312     Any runs of non-alphanumeric/. characters are replaced with a single '-'.
   1313     """
   1314     return re.sub('[^A-Za-z0-9.]+', '-', name)
   1315 
   1316 
   1317 def safe_version(version):
   1318     """
   1319     Convert an arbitrary string to a standard version string
   1320     """
   1321     try:
   1322         # normalize the version
   1323         return str(packaging.version.Version(version))
   1324     except packaging.version.InvalidVersion:
   1325         version = version.replace(' ', '.')
   1326         return re.sub('[^A-Za-z0-9.]+', '-', version)
   1327 
   1328 
   1329 def safe_extra(extra):
   1330     """Convert an arbitrary string to a standard 'extra' name
   1331 
   1332     Any runs of non-alphanumeric characters are replaced with a single '_',
   1333     and the result is always lowercased.
   1334     """
   1335     return re.sub('[^A-Za-z0-9.-]+', '_', extra).lower()
   1336 
   1337 
   1338 def to_filename(name):
   1339     """Convert a project or version name to its filename-escaped form
   1340 
   1341     Any '-' characters are currently replaced with '_'.
   1342     """
   1343     return name.replace('-', '_')
   1344 
   1345 
   1346 def invalid_marker(text):
   1347     """
   1348     Validate text as a PEP 508 environment marker; return an exception
   1349     if invalid or False otherwise.
   1350     """
   1351     try:
   1352         evaluate_marker(text)
   1353     except SyntaxError as e:
   1354         e.filename = None
   1355         e.lineno = None
   1356         return e
   1357     return False
   1358 
   1359 
   1360 def evaluate_marker(text, extra=None):
   1361     """
   1362     Evaluate a PEP 508 environment marker.
   1363     Return a boolean indicating the marker result in this environment.
   1364     Raise SyntaxError if marker is invalid.
   1365 
   1366     This implementation uses the 'pyparsing' module.
   1367     """
   1368     try:
   1369         marker = packaging.markers.Marker(text)
   1370         return marker.evaluate()
   1371     except packaging.markers.InvalidMarker as e:
   1372         raise SyntaxError(e)
   1373 
   1374 
   1375 class NullProvider:
   1376     """Try to implement resources and metadata for arbitrary PEP 302 loaders"""
   1377 
   1378     egg_name = None
   1379     egg_info = None
   1380     loader = None
   1381 
   1382     def __init__(self, module):
   1383         self.loader = getattr(module, '__loader__', None)
   1384         self.module_path = os.path.dirname(getattr(module, '__file__', ''))
   1385 
   1386     def get_resource_filename(self, manager, resource_name):
   1387         return self._fn(self.module_path, resource_name)
   1388 
   1389     def get_resource_stream(self, manager, resource_name):
   1390         return io.BytesIO(self.get_resource_string(manager, resource_name))
   1391 
   1392     def get_resource_string(self, manager, resource_name):
   1393         return self._get(self._fn(self.module_path, resource_name))
   1394 
   1395     def has_resource(self, resource_name):
   1396         return self._has(self._fn(self.module_path, resource_name))
   1397 
   1398     def has_metadata(self, name):
   1399         return self.egg_info and self._has(self._fn(self.egg_info, name))
   1400 
   1401     def get_metadata(self, name):
   1402         if not self.egg_info:
   1403             return ""
   1404         value = self._get(self._fn(self.egg_info, name))
   1405         return value.decode('utf-8') if six.PY3 else value
   1406 
   1407     def get_metadata_lines(self, name):
   1408         return yield_lines(self.get_metadata(name))
   1409 
   1410     def resource_isdir(self, resource_name):
   1411         return self._isdir(self._fn(self.module_path, resource_name))
   1412 
   1413     def metadata_isdir(self, name):
   1414         return self.egg_info and self._isdir(self._fn(self.egg_info, name))
   1415 
   1416     def resource_listdir(self, resource_name):
   1417         return self._listdir(self._fn(self.module_path, resource_name))
   1418 
   1419     def metadata_listdir(self, name):
   1420         if self.egg_info:
   1421             return self._listdir(self._fn(self.egg_info, name))
   1422         return []
   1423 
   1424     def run_script(self, script_name, namespace):
   1425         script = 'scripts/' + script_name
   1426         if not self.has_metadata(script):
   1427             raise ResolutionError(
   1428                 "Script {script!r} not found in metadata at {self.egg_info!r}"
   1429                 .format(**locals()),
   1430             )
   1431         script_text = self.get_metadata(script).replace('\r\n', '\n')
   1432         script_text = script_text.replace('\r', '\n')
   1433         script_filename = self._fn(self.egg_info, script)
   1434         namespace['__file__'] = script_filename
   1435         if os.path.exists(script_filename):
   1436             source = open(script_filename).read()
   1437             code = compile(source, script_filename, 'exec')
   1438             exec(code, namespace, namespace)
   1439         else:
   1440             from linecache import cache
   1441             cache[script_filename] = (
   1442                 len(script_text), 0, script_text.split('\n'), script_filename
   1443             )
   1444             script_code = compile(script_text, script_filename, 'exec')
   1445             exec(script_code, namespace, namespace)
   1446 
   1447     def _has(self, path):
   1448         raise NotImplementedError(
   1449             "Can't perform this operation for unregistered loader type"
   1450         )
   1451 
   1452     def _isdir(self, path):
   1453         raise NotImplementedError(
   1454             "Can't perform this operation for unregistered loader type"
   1455         )
   1456 
   1457     def _listdir(self, path):
   1458         raise NotImplementedError(
   1459             "Can't perform this operation for unregistered loader type"
   1460         )
   1461 
   1462     def _fn(self, base, resource_name):
   1463         if resource_name:
   1464             return os.path.join(base, *resource_name.split('/'))
   1465         return base
   1466 
   1467     def _get(self, path):
   1468         if hasattr(self.loader, 'get_data'):
   1469             return self.loader.get_data(path)
   1470         raise NotImplementedError(
   1471             "Can't perform this operation for loaders without 'get_data()'"
   1472         )
   1473 
   1474 
   1475 register_loader_type(object, NullProvider)
   1476 
   1477 
   1478 class EggProvider(NullProvider):
   1479     """Provider based on a virtual filesystem"""
   1480 
   1481     def __init__(self, module):
   1482         NullProvider.__init__(self, module)
   1483         self._setup_prefix()
   1484 
   1485     def _setup_prefix(self):
   1486         # we assume here that our metadata may be nested inside a "basket"
   1487         # of multiple eggs; that's why we use module_path instead of .archive
   1488         path = self.module_path
   1489         old = None
   1490         while path != old:
   1491             if _is_egg_path(path):
   1492                 self.egg_name = os.path.basename(path)
   1493                 self.egg_info = os.path.join(path, 'EGG-INFO')
   1494                 self.egg_root = path
   1495                 break
   1496             old = path
   1497             path, base = os.path.split(path)
   1498 
   1499 
   1500 class DefaultProvider(EggProvider):
   1501     """Provides access to package resources in the filesystem"""
   1502 
   1503     def _has(self, path):
   1504         return os.path.exists(path)
   1505 
   1506     def _isdir(self, path):
   1507         return os.path.isdir(path)
   1508 
   1509     def _listdir(self, path):
   1510         return os.listdir(path)
   1511 
   1512     def get_resource_stream(self, manager, resource_name):
   1513         return open(self._fn(self.module_path, resource_name), 'rb')
   1514 
   1515     def _get(self, path):
   1516         with open(path, 'rb') as stream:
   1517             return stream.read()
   1518 
   1519     @classmethod
   1520     def _register(cls):
   1521         loader_names = 'SourceFileLoader', 'SourcelessFileLoader',
   1522         for name in loader_names:
   1523             loader_cls = getattr(importlib_machinery, name, type(None))
   1524             register_loader_type(loader_cls, cls)
   1525 
   1526 
   1527 DefaultProvider._register()
   1528 
   1529 
   1530 class EmptyProvider(NullProvider):
   1531     """Provider that returns nothing for all requests"""
   1532 
   1533     module_path = None
   1534 
   1535     _isdir = _has = lambda self, path: False
   1536 
   1537     def _get(self, path):
   1538         return ''
   1539 
   1540     def _listdir(self, path):
   1541         return []
   1542 
   1543     def __init__(self):
   1544         pass
   1545 
   1546 
   1547 empty_provider = EmptyProvider()
   1548 
   1549 
   1550 class ZipManifests(dict):
   1551     """
   1552     zip manifest builder
   1553     """
   1554 
   1555     @classmethod
   1556     def build(cls, path):
   1557         """
   1558         Build a dictionary similar to the zipimport directory
   1559         caches, except instead of tuples, store ZipInfo objects.
   1560 
   1561         Use a platform-specific path separator (os.sep) for the path keys
   1562         for compatibility with pypy on Windows.
   1563         """
   1564         with zipfile.ZipFile(path) as zfile:
   1565             items = (
   1566                 (
   1567                     name.replace('/', os.sep),
   1568                     zfile.getinfo(name),
   1569                 )
   1570                 for name in zfile.namelist()
   1571             )
   1572             return dict(items)
   1573 
   1574     load = build
   1575 
   1576 
   1577 class MemoizedZipManifests(ZipManifests):
   1578     """
   1579     Memoized zipfile manifests.
   1580     """
   1581     manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime')
   1582 
   1583     def load(self, path):
   1584         """
   1585         Load a manifest at path or return a suitable manifest already loaded.
   1586         """
   1587         path = os.path.normpath(path)
   1588         mtime = os.stat(path).st_mtime
   1589 
   1590         if path not in self or self[path].mtime != mtime:
   1591             manifest = self.build(path)
   1592             self[path] = self.manifest_mod(manifest, mtime)
   1593 
   1594         return self[path].manifest
   1595 
   1596 
   1597 class ZipProvider(EggProvider):
   1598     """Resource support for zips and eggs"""
   1599 
   1600     eagers = None
   1601     _zip_manifests = MemoizedZipManifests()
   1602 
   1603     def __init__(self, module):
   1604         EggProvider.__init__(self, module)
   1605         self.zip_pre = self.loader.archive + os.sep
   1606 
   1607     def _zipinfo_name(self, fspath):
   1608         # Convert a virtual filename (full path to file) into a zipfile subpath
   1609         # usable with the zipimport directory cache for our target archive
   1610         fspath = fspath.rstrip(os.sep)
   1611         if fspath == self.loader.archive:
   1612             return ''
   1613         if fspath.startswith(self.zip_pre):
   1614             return fspath[len(self.zip_pre):]
   1615         raise AssertionError(
   1616             "%s is not a subpath of %s" % (fspath, self.zip_pre)
   1617         )
   1618 
   1619     def _parts(self, zip_path):
   1620         # Convert a zipfile subpath into an egg-relative path part list.
   1621         # pseudo-fs path
   1622         fspath = self.zip_pre + zip_path
   1623         if fspath.startswith(self.egg_root + os.sep):
   1624             return fspath[len(self.egg_root) + 1:].split(os.sep)
   1625         raise AssertionError(
   1626             "%s is not a subpath of %s" % (fspath, self.egg_root)
   1627         )
   1628 
   1629     @property
   1630     def zipinfo(self):
   1631         return self._zip_manifests.load(self.loader.archive)
   1632 
   1633     def get_resource_filename(self, manager, resource_name):
   1634         if not self.egg_name:
   1635             raise NotImplementedError(
   1636                 "resource_filename() only supported for .egg, not .zip"
   1637             )
   1638         # no need to lock for extraction, since we use temp names
   1639         zip_path = self._resource_to_zip(resource_name)
   1640         eagers = self._get_eager_resources()
   1641         if '/'.join(self._parts(zip_path)) in eagers:
   1642             for name in eagers:
   1643                 self._extract_resource(manager, self._eager_to_zip(name))
   1644         return self._extract_resource(manager, zip_path)
   1645 
   1646     @staticmethod
   1647     def _get_date_and_size(zip_stat):
   1648         size = zip_stat.file_size
   1649         # ymdhms+wday, yday, dst
   1650         date_time = zip_stat.date_time + (0, 0, -1)
   1651         # 1980 offset already done
   1652         timestamp = time.mktime(date_time)
   1653         return timestamp, size
   1654 
   1655     def _extract_resource(self, manager, zip_path):
   1656 
   1657         if zip_path in self._index():
   1658             for name in self._index()[zip_path]:
   1659                 last = self._extract_resource(
   1660                     manager, os.path.join(zip_path, name)
   1661                 )
   1662             # return the extracted directory name
   1663             return os.path.dirname(last)
   1664 
   1665         timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
   1666 
   1667         if not WRITE_SUPPORT:
   1668             raise IOError('"os.rename" and "os.unlink" are not supported '
   1669                           'on this platform')
   1670         try:
   1671 
   1672             real_path = manager.get_cache_path(
   1673                 self.egg_name, self._parts(zip_path)
   1674             )
   1675 
   1676             if self._is_current(real_path, zip_path):
   1677                 return real_path
   1678 
   1679             outf, tmpnam = _mkstemp(
   1680                 ".$extract",
   1681                 dir=os.path.dirname(real_path),
   1682             )
   1683             os.write(outf, self.loader.get_data(zip_path))
   1684             os.close(outf)
   1685             utime(tmpnam, (timestamp, timestamp))
   1686             manager.postprocess(tmpnam, real_path)
   1687 
   1688             try:
   1689                 rename(tmpnam, real_path)
   1690 
   1691             except os.error:
   1692                 if os.path.isfile(real_path):
   1693                     if self._is_current(real_path, zip_path):
   1694                         # the file became current since it was checked above,
   1695                         #  so proceed.
   1696                         return real_path
   1697                     # Windows, del old file and retry
   1698                     elif os.name == 'nt':
   1699                         unlink(real_path)
   1700                         rename(tmpnam, real_path)
   1701                         return real_path
   1702                 raise
   1703 
   1704         except os.error:
   1705             # report a user-friendly error
   1706             manager.extraction_error()
   1707 
   1708         return real_path
   1709 
   1710     def _is_current(self, file_path, zip_path):
   1711         """
   1712         Return True if the file_path is current for this zip_path
   1713         """
   1714         timestamp, size = self._get_date_and_size(self.zipinfo[zip_path])
   1715         if not os.path.isfile(file_path):
   1716             return False
   1717         stat = os.stat(file_path)
   1718         if stat.st_size != size or stat.st_mtime != timestamp:
   1719             return False
   1720         # check that the contents match
   1721         zip_contents = self.loader.get_data(zip_path)
   1722         with open(file_path, 'rb') as f:
   1723             file_contents = f.read()
   1724         return zip_contents == file_contents
   1725 
   1726     def _get_eager_resources(self):
   1727         if self.eagers is None:
   1728             eagers = []
   1729             for name in ('native_libs.txt', 'eager_resources.txt'):
   1730                 if self.has_metadata(name):
   1731                     eagers.extend(self.get_metadata_lines(name))
   1732             self.eagers = eagers
   1733         return self.eagers
   1734 
   1735     def _index(self):
   1736         try:
   1737             return self._dirindex
   1738         except AttributeError:
   1739             ind = {}
   1740             for path in self.zipinfo:
   1741                 parts = path.split(os.sep)
   1742                 while parts:
   1743                     parent = os.sep.join(parts[:-1])
   1744                     if parent in ind:
   1745                         ind[parent].append(parts[-1])
   1746                         break
   1747                     else:
   1748                         ind[parent] = [parts.pop()]
   1749             self._dirindex = ind
   1750             return ind
   1751 
   1752     def _has(self, fspath):
   1753         zip_path = self._zipinfo_name(fspath)
   1754         return zip_path in self.zipinfo or zip_path in self._index()
   1755 
   1756     def _isdir(self, fspath):
   1757         return self._zipinfo_name(fspath) in self._index()
   1758 
   1759     def _listdir(self, fspath):
   1760         return list(self._index().get(self._zipinfo_name(fspath), ()))
   1761 
   1762     def _eager_to_zip(self, resource_name):
   1763         return self._zipinfo_name(self._fn(self.egg_root, resource_name))
   1764 
   1765     def _resource_to_zip(self, resource_name):
   1766         return self._zipinfo_name(self._fn(self.module_path, resource_name))
   1767 
   1768 
   1769 register_loader_type(zipimport.zipimporter, ZipProvider)
   1770 
   1771 
   1772 class FileMetadata(EmptyProvider):
   1773     """Metadata handler for standalone PKG-INFO files
   1774 
   1775     Usage::
   1776 
   1777         metadata = FileMetadata("/path/to/PKG-INFO")
   1778 
   1779     This provider rejects all data and metadata requests except for PKG-INFO,
   1780     which is treated as existing, and will be the contents of the file at
   1781     the provided location.
   1782     """
   1783 
   1784     def __init__(self, path):
   1785         self.path = path
   1786 
   1787     def has_metadata(self, name):
   1788         return name == 'PKG-INFO' and os.path.isfile(self.path)
   1789 
   1790     def get_metadata(self, name):
   1791         if name != 'PKG-INFO':
   1792             raise KeyError("No metadata except PKG-INFO is available")
   1793 
   1794         with io.open(self.path, encoding='utf-8', errors="replace") as f:
   1795             metadata = f.read()
   1796         self._warn_on_replacement(metadata)
   1797         return metadata
   1798 
   1799     def _warn_on_replacement(self, metadata):
   1800         # Python 2.7 compat for: replacement_char = ''
   1801         replacement_char = b'\xef\xbf\xbd'.decode('utf-8')
   1802         if replacement_char in metadata:
   1803             tmpl = "{self.path} could not be properly decoded in UTF-8"
   1804             msg = tmpl.format(**locals())
   1805             warnings.warn(msg)
   1806 
   1807     def get_metadata_lines(self, name):
   1808         return yield_lines(self.get_metadata(name))
   1809 
   1810 
   1811 class PathMetadata(DefaultProvider):
   1812     """Metadata provider for egg directories
   1813 
   1814     Usage::
   1815 
   1816         # Development eggs:
   1817 
   1818         egg_info = "/path/to/PackageName.egg-info"
   1819         base_dir = os.path.dirname(egg_info)
   1820         metadata = PathMetadata(base_dir, egg_info)
   1821         dist_name = os.path.splitext(os.path.basename(egg_info))[0]
   1822         dist = Distribution(basedir, project_name=dist_name, metadata=metadata)
   1823 
   1824         # Unpacked egg directories:
   1825 
   1826         egg_path = "/path/to/PackageName-ver-pyver-etc.egg"
   1827         metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO'))
   1828         dist = Distribution.from_filename(egg_path, metadata=metadata)
   1829     """
   1830 
   1831     def __init__(self, path, egg_info):
   1832         self.module_path = path
   1833         self.egg_info = egg_info
   1834 
   1835 
   1836 class EggMetadata(ZipProvider):
   1837     """Metadata provider for .egg files"""
   1838 
   1839     def __init__(self, importer):
   1840         """Create a metadata provider from a zipimporter"""
   1841 
   1842         self.zip_pre = importer.archive + os.sep
   1843         self.loader = importer
   1844         if importer.prefix:
   1845             self.module_path = os.path.join(importer.archive, importer.prefix)
   1846         else:
   1847             self.module_path = importer.archive
   1848         self._setup_prefix()
   1849 
   1850 
   1851 _declare_state('dict', _distribution_finders={})
   1852 
   1853 
   1854 def register_finder(importer_type, distribution_finder):
   1855     """Register `distribution_finder` to find distributions in sys.path items
   1856 
   1857     `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
   1858     handler), and `distribution_finder` is a callable that, passed a path
   1859     item and the importer instance, yields ``Distribution`` instances found on
   1860     that path item.  See ``pkg_resources.find_on_path`` for an example."""
   1861     _distribution_finders[importer_type] = distribution_finder
   1862 
   1863 
   1864 def find_distributions(path_item, only=False):
   1865     """Yield distributions accessible via `path_item`"""
   1866     importer = get_importer(path_item)
   1867     finder = _find_adapter(_distribution_finders, importer)
   1868     return finder(importer, path_item, only)
   1869 
   1870 
   1871 def find_eggs_in_zip(importer, path_item, only=False):
   1872     """
   1873     Find eggs in zip files; possibly multiple nested eggs.
   1874     """
   1875     if importer.archive.endswith('.whl'):
   1876         # wheels are not supported with this finder
   1877         # they don't have PKG-INFO metadata, and won't ever contain eggs
   1878         return
   1879     metadata = EggMetadata(importer)
   1880     if metadata.has_metadata('PKG-INFO'):
   1881         yield Distribution.from_filename(path_item, metadata=metadata)
   1882     if only:
   1883         # don't yield nested distros
   1884         return
   1885     for subitem in metadata.resource_listdir('/'):
   1886         if _is_egg_path(subitem):
   1887             subpath = os.path.join(path_item, subitem)
   1888             dists = find_eggs_in_zip(zipimport.zipimporter(subpath), subpath)
   1889             for dist in dists:
   1890                 yield dist
   1891         elif subitem.lower().endswith('.dist-info'):
   1892             subpath = os.path.join(path_item, subitem)
   1893             submeta = EggMetadata(zipimport.zipimporter(subpath))
   1894             submeta.egg_info = subpath
   1895             yield Distribution.from_location(path_item, subitem, submeta)
   1896 
   1897 
   1898 register_finder(zipimport.zipimporter, find_eggs_in_zip)
   1899 
   1900 
   1901 def find_nothing(importer, path_item, only=False):
   1902     return ()
   1903 
   1904 
   1905 register_finder(object, find_nothing)
   1906 
   1907 
   1908 def _by_version_descending(names):
   1909     """
   1910     Given a list of filenames, return them in descending order
   1911     by version number.
   1912 
   1913     >>> names = 'bar', 'foo', 'Python-2.7.10.egg', 'Python-2.7.2.egg'
   1914     >>> _by_version_descending(names)
   1915     ['Python-2.7.10.egg', 'Python-2.7.2.egg', 'foo', 'bar']
   1916     >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.egg'
   1917     >>> _by_version_descending(names)
   1918     ['Setuptools-1.2.3.egg', 'Setuptools-1.2.3b1.egg']
   1919     >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.post1.egg'
   1920     >>> _by_version_descending(names)
   1921     ['Setuptools-1.2.3.post1.egg', 'Setuptools-1.2.3b1.egg']
   1922     """
   1923     def _by_version(name):
   1924         """
   1925         Parse each component of the filename
   1926         """
   1927         name, ext = os.path.splitext(name)
   1928         parts = itertools.chain(name.split('-'), [ext])
   1929         return [packaging.version.parse(part) for part in parts]
   1930 
   1931     return sorted(names, key=_by_version, reverse=True)
   1932 
   1933 
   1934 def find_on_path(importer, path_item, only=False):
   1935     """Yield distributions accessible on a sys.path directory"""
   1936     path_item = _normalize_cached(path_item)
   1937 
   1938     if _is_unpacked_egg(path_item):
   1939         yield Distribution.from_filename(
   1940             path_item, metadata=PathMetadata(
   1941                 path_item, os.path.join(path_item, 'EGG-INFO')
   1942             )
   1943         )
   1944         return
   1945 
   1946     entries = safe_listdir(path_item)
   1947 
   1948     # for performance, before sorting by version,
   1949     # screen entries for only those that will yield
   1950     # distributions
   1951     filtered = (
   1952         entry
   1953         for entry in entries
   1954         if dist_factory(path_item, entry, only)
   1955     )
   1956 
   1957     # scan for .egg and .egg-info in directory
   1958     path_item_entries = _by_version_descending(filtered)
   1959     for entry in path_item_entries:
   1960         fullpath = os.path.join(path_item, entry)
   1961         factory = dist_factory(path_item, entry, only)
   1962         for dist in factory(fullpath):
   1963             yield dist
   1964 
   1965 
   1966 def dist_factory(path_item, entry, only):
   1967     """
   1968     Return a dist_factory for a path_item and entry
   1969     """
   1970     lower = entry.lower()
   1971     is_meta = any(map(lower.endswith, ('.egg-info', '.dist-info')))
   1972     return (
   1973         distributions_from_metadata
   1974         if is_meta else
   1975         find_distributions
   1976         if not only and _is_egg_path(entry) else
   1977         resolve_egg_link
   1978         if not only and lower.endswith('.egg-link') else
   1979         NoDists()
   1980     )
   1981 
   1982 
   1983 class NoDists:
   1984     """
   1985     >>> bool(NoDists())
   1986     False
   1987 
   1988     >>> list(NoDists()('anything'))
   1989     []
   1990     """
   1991     def __bool__(self):
   1992         return False
   1993     if six.PY2:
   1994         __nonzero__ = __bool__
   1995 
   1996     def __call__(self, fullpath):
   1997         return iter(())
   1998 
   1999 
   2000 def safe_listdir(path):
   2001     """
   2002     Attempt to list contents of path, but suppress some exceptions.
   2003     """
   2004     try:
   2005         return os.listdir(path)
   2006     except (PermissionError, NotADirectoryError):
   2007         pass
   2008     except OSError as e:
   2009         # Ignore the directory if does not exist, not a directory or
   2010         # permission denied
   2011         ignorable = (
   2012             e.errno in (errno.ENOTDIR, errno.EACCES, errno.ENOENT)
   2013             # Python 2 on Windows needs to be handled this way :(
   2014             or getattr(e, "winerror", None) == 267
   2015         )
   2016         if not ignorable:
   2017             raise
   2018     return ()
   2019 
   2020 
   2021 def distributions_from_metadata(path):
   2022     root = os.path.dirname(path)
   2023     if os.path.isdir(path):
   2024         if len(os.listdir(path)) == 0:
   2025             # empty metadata dir; skip
   2026             return
   2027         metadata = PathMetadata(root, path)
   2028     else:
   2029         metadata = FileMetadata(path)
   2030     entry = os.path.basename(path)
   2031     yield Distribution.from_location(
   2032         root, entry, metadata, precedence=DEVELOP_DIST,
   2033     )
   2034 
   2035 
   2036 def non_empty_lines(path):
   2037     """
   2038     Yield non-empty lines from file at path
   2039     """
   2040     with open(path) as f:
   2041         for line in f:
   2042             line = line.strip()
   2043             if line:
   2044                 yield line
   2045 
   2046 
   2047 def resolve_egg_link(path):
   2048     """
   2049     Given a path to an .egg-link, resolve distributions
   2050     present in the referenced path.
   2051     """
   2052     referenced_paths = non_empty_lines(path)
   2053     resolved_paths = (
   2054         os.path.join(os.path.dirname(path), ref)
   2055         for ref in referenced_paths
   2056     )
   2057     dist_groups = map(find_distributions, resolved_paths)
   2058     return next(dist_groups, ())
   2059 
   2060 
   2061 register_finder(pkgutil.ImpImporter, find_on_path)
   2062 
   2063 if hasattr(importlib_machinery, 'FileFinder'):
   2064     register_finder(importlib_machinery.FileFinder, find_on_path)
   2065 
   2066 _declare_state('dict', _namespace_handlers={})
   2067 _declare_state('dict', _namespace_packages={})
   2068 
   2069 
   2070 def register_namespace_handler(importer_type, namespace_handler):
   2071     """Register `namespace_handler` to declare namespace packages
   2072 
   2073     `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item
   2074     handler), and `namespace_handler` is a callable like this::
   2075 
   2076         def namespace_handler(importer, path_entry, moduleName, module):
   2077             # return a path_entry to use for child packages
   2078 
   2079     Namespace handlers are only called if the importer object has already
   2080     agreed that it can handle the relevant path item, and they should only
   2081     return a subpath if the module __path__ does not already contain an
   2082     equivalent subpath.  For an example namespace handler, see
   2083     ``pkg_resources.file_ns_handler``.
   2084     """
   2085     _namespace_handlers[importer_type] = namespace_handler
   2086 
   2087 
   2088 def _handle_ns(packageName, path_item):
   2089     """Ensure that named package includes a subpath of path_item (if needed)"""
   2090 
   2091     importer = get_importer(path_item)
   2092     if importer is None:
   2093         return None
   2094     loader = importer.find_module(packageName)
   2095     if loader is None:
   2096         return None
   2097     module = sys.modules.get(packageName)
   2098     if module is None:
   2099         module = sys.modules[packageName] = types.ModuleType(packageName)
   2100         module.__path__ = []
   2101         _set_parent_ns(packageName)
   2102     elif not hasattr(module, '__path__'):
   2103         raise TypeError("Not a package:", packageName)
   2104     handler = _find_adapter(_namespace_handlers, importer)
   2105     subpath = handler(importer, path_item, packageName, module)
   2106     if subpath is not None:
   2107         path = module.__path__
   2108         path.append(subpath)
   2109         loader.load_module(packageName)
   2110         _rebuild_mod_path(path, packageName, module)
   2111     return subpath
   2112 
   2113 
   2114 def _rebuild_mod_path(orig_path, package_name, module):
   2115     """
   2116     Rebuild module.__path__ ensuring that all entries are ordered
   2117     corresponding to their sys.path order
   2118     """
   2119     sys_path = [_normalize_cached(p) for p in sys.path]
   2120 
   2121     def safe_sys_path_index(entry):
   2122         """
   2123         Workaround for #520 and #513.
   2124         """
   2125         try:
   2126             return sys_path.index(entry)
   2127         except ValueError:
   2128             return float('inf')
   2129 
   2130     def position_in_sys_path(path):
   2131         """
   2132         Return the ordinal of the path based on its position in sys.path
   2133         """
   2134         path_parts = path.split(os.sep)
   2135         module_parts = package_name.count('.') + 1
   2136         parts = path_parts[:-module_parts]
   2137         return safe_sys_path_index(_normalize_cached(os.sep.join(parts)))
   2138 
   2139     if not isinstance(orig_path, list):
   2140         # Is this behavior useful when module.__path__ is not a list?
   2141         return
   2142 
   2143     orig_path.sort(key=position_in_sys_path)
   2144     module.__path__[:] = [_normalize_cached(p) for p in orig_path]
   2145 
   2146 
   2147 def declare_namespace(packageName):
   2148     """Declare that package 'packageName' is a namespace package"""
   2149 
   2150     _imp.acquire_lock()
   2151     try:
   2152         if packageName in _namespace_packages:
   2153             return
   2154 
   2155         path, parent = sys.path, None
   2156         if '.' in packageName:
   2157             parent = '.'.join(packageName.split('.')[:-1])
   2158             declare_namespace(parent)
   2159             if parent not in _namespace_packages:
   2160                 __import__(parent)
   2161             try:
   2162                 path = sys.modules[parent].__path__
   2163             except AttributeError:
   2164                 raise TypeError("Not a package:", parent)
   2165 
   2166         # Track what packages are namespaces, so when new path items are added,
   2167         # they can be updated
   2168         _namespace_packages.setdefault(parent, []).append(packageName)
   2169         _namespace_packages.setdefault(packageName, [])
   2170 
   2171         for path_item in path:
   2172             # Ensure all the parent's path items are reflected in the child,
   2173             # if they apply
   2174             _handle_ns(packageName, path_item)
   2175 
   2176     finally:
   2177         _imp.release_lock()
   2178 
   2179 
   2180 def fixup_namespace_packages(path_item, parent=None):
   2181     """Ensure that previously-declared namespace packages include path_item"""
   2182     _imp.acquire_lock()
   2183     try:
   2184         for package in _namespace_packages.get(parent, ()):
   2185             subpath = _handle_ns(package, path_item)
   2186             if subpath:
   2187                 fixup_namespace_packages(subpath, package)
   2188     finally:
   2189         _imp.release_lock()
   2190 
   2191 
   2192 def file_ns_handler(importer, path_item, packageName, module):
   2193     """Compute an ns-package subpath for a filesystem or zipfile importer"""
   2194 
   2195     subpath = os.path.join(path_item, packageName.split('.')[-1])
   2196     normalized = _normalize_cached(subpath)
   2197     for item in module.__path__:
   2198         if _normalize_cached(item) == normalized:
   2199             break
   2200     else:
   2201         # Only return the path if it's not already there
   2202         return subpath
   2203 
   2204 
   2205 register_namespace_handler(pkgutil.ImpImporter, file_ns_handler)
   2206 register_namespace_handler(zipimport.zipimporter, file_ns_handler)
   2207 
   2208 if hasattr(importlib_machinery, 'FileFinder'):
   2209     register_namespace_handler(importlib_machinery.FileFinder, file_ns_handler)
   2210 
   2211 
   2212 def null_ns_handler(importer, path_item, packageName, module):
   2213     return None
   2214 
   2215 
   2216 register_namespace_handler(object, null_ns_handler)
   2217 
   2218 
   2219 def normalize_path(filename):
   2220     """Normalize a file/dir name for comparison purposes"""
   2221     return os.path.normcase(os.path.realpath(filename))
   2222 
   2223 
   2224 def _normalize_cached(filename, _cache={}):
   2225     try:
   2226         return _cache[filename]
   2227     except KeyError:
   2228         _cache[filename] = result = normalize_path(filename)
   2229         return result
   2230 
   2231 
   2232 def _is_egg_path(path):
   2233     """
   2234     Determine if given path appears to be an egg.
   2235     """
   2236     return path.lower().endswith('.egg')
   2237 
   2238 
   2239 def _is_unpacked_egg(path):
   2240     """
   2241     Determine if given path appears to be an unpacked egg.
   2242     """
   2243     return (
   2244         _is_egg_path(path) and
   2245         os.path.isfile(os.path.join(path, 'EGG-INFO', 'PKG-INFO'))
   2246     )
   2247 
   2248 
   2249 def _set_parent_ns(packageName):
   2250     parts = packageName.split('.')
   2251     name = parts.pop()
   2252     if parts:
   2253         parent = '.'.join(parts)
   2254         setattr(sys.modules[parent], name, sys.modules[packageName])
   2255 
   2256 
   2257 def yield_lines(strs):
   2258     """Yield non-empty/non-comment lines of a string or sequence"""
   2259     if isinstance(strs, six.string_types):
   2260         for s in strs.splitlines():
   2261             s = s.strip()
   2262             # skip blank lines/comments
   2263             if s and not s.startswith('#'):
   2264                 yield s
   2265     else:
   2266         for ss in strs:
   2267             for s in yield_lines(ss):
   2268                 yield s
   2269 
   2270 
   2271 MODULE = re.compile(r"\w+(\.\w+)*$").match
   2272 EGG_NAME = re.compile(
   2273     r"""
   2274     (?P<name>[^-]+) (
   2275         -(?P<ver>[^-]+) (
   2276             -py(?P<pyver>[^-]+) (
   2277                 -(?P<plat>.+)
   2278             )?
   2279         )?
   2280     )?
   2281     """,
   2282     re.VERBOSE | re.IGNORECASE,
   2283 ).match
   2284 
   2285 
   2286 class EntryPoint(object):
   2287     """Object representing an advertised importable object"""
   2288 
   2289     def __init__(self, name, module_name, attrs=(), extras=(), dist=None):
   2290         if not MODULE(module_name):
   2291             raise ValueError("Invalid module name", module_name)
   2292         self.name = name
   2293         self.module_name = module_name
   2294         self.attrs = tuple(attrs)
   2295         self.extras = tuple(extras)
   2296         self.dist = dist
   2297 
   2298     def __str__(self):
   2299         s = "%s = %s" % (self.name, self.module_name)
   2300         if self.attrs:
   2301             s += ':' + '.'.join(self.attrs)
   2302         if self.extras:
   2303             s += ' [%s]' % ','.join(self.extras)
   2304         return s
   2305 
   2306     def __repr__(self):
   2307         return "EntryPoint.parse(%r)" % str(self)
   2308 
   2309     def load(self, require=True, *args, **kwargs):
   2310         """
   2311         Require packages for this EntryPoint, then resolve it.
   2312         """
   2313         if not require or args or kwargs:
   2314             warnings.warn(
   2315                 "Parameters to load are deprecated.  Call .resolve and "
   2316                 ".require separately.",
   2317                 DeprecationWarning,
   2318                 stacklevel=2,
   2319             )
   2320         if require:
   2321             self.require(*args, **kwargs)
   2322         return self.resolve()
   2323 
   2324     def resolve(self):
   2325         """
   2326         Resolve the entry point from its module and attrs.
   2327         """
   2328         module = __import__(self.module_name, fromlist=['__name__'], level=0)
   2329         try:
   2330             return functools.reduce(getattr, self.attrs, module)
   2331         except AttributeError as exc:
   2332             raise ImportError(str(exc))
   2333 
   2334     def require(self, env=None, installer=None):
   2335         if self.extras and not self.dist:
   2336             raise UnknownExtra("Can't require() without a distribution", self)
   2337 
   2338         # Get the requirements for this entry point with all its extras and
   2339         # then resolve them. We have to pass `extras` along when resolving so
   2340         # that the working set knows what extras we want. Otherwise, for
   2341         # dist-info distributions, the working set will assume that the
   2342         # requirements for that extra are purely optional and skip over them.
   2343         reqs = self.dist.requires(self.extras)
   2344         items = working_set.resolve(reqs, env, installer, extras=self.extras)
   2345         list(map(working_set.add, items))
   2346 
   2347     pattern = re.compile(
   2348         r'\s*'
   2349         r'(?P<name>.+?)\s*'
   2350         r'=\s*'
   2351         r'(?P<module>[\w.]+)\s*'
   2352         r'(:\s*(?P<attr>[\w.]+))?\s*'
   2353         r'(?P<extras>\[.*\])?\s*$'
   2354     )
   2355 
   2356     @classmethod
   2357     def parse(cls, src, dist=None):
   2358         """Parse a single entry point from string `src`
   2359 
   2360         Entry point syntax follows the form::
   2361 
   2362             name = some.module:some.attr [extra1, extra2]
   2363 
   2364         The entry name and module name are required, but the ``:attrs`` and
   2365         ``[extras]`` parts are optional
   2366         """
   2367         m = cls.pattern.match(src)
   2368         if not m:
   2369             msg = "EntryPoint must be in 'name=module:attrs [extras]' format"
   2370             raise ValueError(msg, src)
   2371         res = m.groupdict()
   2372         extras = cls._parse_extras(res['extras'])
   2373         attrs = res['attr'].split('.') if res['attr'] else ()
   2374         return cls(res['name'], res['module'], attrs, extras, dist)
   2375 
   2376     @classmethod
   2377     def _parse_extras(cls, extras_spec):
   2378         if not extras_spec:
   2379             return ()
   2380         req = Requirement.parse('x' + extras_spec)
   2381         if req.specs:
   2382             raise ValueError()
   2383         return req.extras
   2384 
   2385     @classmethod
   2386     def parse_group(cls, group, lines, dist=None):
   2387         """Parse an entry point group"""
   2388         if not MODULE(group):
   2389             raise ValueError("Invalid group name", group)
   2390         this = {}
   2391         for line in yield_lines(lines):
   2392             ep = cls.parse(line, dist)
   2393             if ep.name in this:
   2394                 raise ValueError("Duplicate entry point", group, ep.name)
   2395             this[ep.name] = ep
   2396         return this
   2397 
   2398     @classmethod
   2399     def parse_map(cls, data, dist=None):
   2400         """Parse a map of entry point groups"""
   2401         if isinstance(data, dict):
   2402             data = data.items()
   2403         else:
   2404             data = split_sections(data)
   2405         maps = {}
   2406         for group, lines in data:
   2407             if group is None:
   2408                 if not lines:
   2409                     continue
   2410                 raise ValueError("Entry points must be listed in groups")
   2411             group = group.strip()
   2412             if group in maps:
   2413                 raise ValueError("Duplicate group name", group)
   2414             maps[group] = cls.parse_group(group, lines, dist)
   2415         return maps
   2416 
   2417 
   2418 def _remove_md5_fragment(location):
   2419     if not location:
   2420         return ''
   2421     parsed = urllib.parse.urlparse(location)
   2422     if parsed[-1].startswith('md5='):
   2423         return urllib.parse.urlunparse(parsed[:-1] + ('',))
   2424     return location
   2425 
   2426 
   2427 def _version_from_file(lines):
   2428     """
   2429     Given an iterable of lines from a Metadata file, return
   2430     the value of the Version field, if present, or None otherwise.
   2431     """
   2432     def is_version_line(line):
   2433         return line.lower().startswith('version:')
   2434     version_lines = filter(is_version_line, lines)
   2435     line = next(iter(version_lines), '')
   2436     _, _, value = line.partition(':')
   2437     return safe_version(value.strip()) or None
   2438 
   2439 
   2440 class Distribution(object):
   2441     """Wrap an actual or potential sys.path entry w/metadata"""
   2442     PKG_INFO = 'PKG-INFO'
   2443 
   2444     def __init__(
   2445             self, location=None, metadata=None, project_name=None,
   2446             version=None, py_version=PY_MAJOR, platform=None,
   2447             precedence=EGG_DIST):
   2448         self.project_name = safe_name(project_name or 'Unknown')
   2449         if version is not None:
   2450             self._version = safe_version(version)
   2451         self.py_version = py_version
   2452         self.platform = platform
   2453         self.location = location
   2454         self.precedence = precedence
   2455         self._provider = metadata or empty_provider
   2456 
   2457     @classmethod
   2458     def from_location(cls, location, basename, metadata=None, **kw):
   2459         project_name, version, py_version, platform = [None] * 4
   2460         basename, ext = os.path.splitext(basename)
   2461         if ext.lower() in _distributionImpl:
   2462             cls = _distributionImpl[ext.lower()]
   2463 
   2464             match = EGG_NAME(basename)
   2465             if match:
   2466                 project_name, version, py_version, platform = match.group(
   2467                     'name', 'ver', 'pyver', 'plat'
   2468                 )
   2469         return cls(
   2470             location, metadata, project_name=project_name, version=version,
   2471             py_version=py_version, platform=platform, **kw
   2472         )._reload_version()
   2473 
   2474     def _reload_version(self):
   2475         return self
   2476 
   2477     @property
   2478     def hashcmp(self):
   2479         return (
   2480             self.parsed_version,
   2481             self.precedence,
   2482             self.key,
   2483             _remove_md5_fragment(self.location),
   2484             self.py_version or '',
   2485             self.platform or '',
   2486         )
   2487 
   2488     def __hash__(self):
   2489         return hash(self.hashcmp)
   2490 
   2491     def __lt__(self, other):
   2492         return self.hashcmp < other.hashcmp
   2493 
   2494     def __le__(self, other):
   2495         return self.hashcmp <= other.hashcmp
   2496 
   2497     def __gt__(self, other):
   2498         return self.hashcmp > other.hashcmp
   2499 
   2500     def __ge__(self, other):
   2501         return self.hashcmp >= other.hashcmp
   2502 
   2503     def __eq__(self, other):
   2504         if not isinstance(other, self.__class__):
   2505             # It's not a Distribution, so they are not equal
   2506             return False
   2507         return self.hashcmp == other.hashcmp
   2508 
   2509     def __ne__(self, other):
   2510         return not self == other
   2511 
   2512     # These properties have to be lazy so that we don't have to load any
   2513     # metadata until/unless it's actually needed.  (i.e., some distributions
   2514     # may not know their name or version without loading PKG-INFO)
   2515 
   2516     @property
   2517     def key(self):
   2518         try:
   2519             return self._key
   2520         except AttributeError:
   2521             self._key = key = self.project_name.lower()
   2522             return key
   2523 
   2524     @property
   2525     def parsed_version(self):
   2526         if not hasattr(self, "_parsed_version"):
   2527             self._parsed_version = parse_version(self.version)
   2528 
   2529         return self._parsed_version
   2530 
   2531     def _warn_legacy_version(self):
   2532         LV = packaging.version.LegacyVersion
   2533         is_legacy = isinstance(self._parsed_version, LV)
   2534         if not is_legacy:
   2535             return
   2536 
   2537         # While an empty version is technically a legacy version and
   2538         # is not a valid PEP 440 version, it's also unlikely to
   2539         # actually come from someone and instead it is more likely that
   2540         # it comes from setuptools attempting to parse a filename and
   2541         # including it in the list. So for that we'll gate this warning
   2542         # on if the version is anything at all or not.
   2543         if not self.version:
   2544             return
   2545 
   2546         tmpl = textwrap.dedent("""
   2547             '{project_name} ({version})' is being parsed as a legacy,
   2548             non PEP 440,
   2549             version. You may find odd behavior and sort order.
   2550             In particular it will be sorted as less than 0.0. It
   2551             is recommended to migrate to PEP 440 compatible
   2552             versions.
   2553             """).strip().replace('\n', ' ')
   2554 
   2555         warnings.warn(tmpl.format(**vars(self)), PEP440Warning)
   2556 
   2557     @property
   2558     def version(self):
   2559         try:
   2560             return self._version
   2561         except AttributeError:
   2562             version = _version_from_file(self._get_metadata(self.PKG_INFO))
   2563             if version is None:
   2564                 tmpl = "Missing 'Version:' header and/or %s file"
   2565                 raise ValueError(tmpl % self.PKG_INFO, self)
   2566             return version
   2567 
   2568     @property
   2569     def _dep_map(self):
   2570         """
   2571         A map of extra to its list of (direct) requirements
   2572         for this distribution, including the null extra.
   2573         """
   2574         try:
   2575             return self.__dep_map
   2576         except AttributeError:
   2577             self.__dep_map = self._filter_extras(self._build_dep_map())
   2578         return self.__dep_map
   2579 
   2580     @staticmethod
   2581     def _filter_extras(dm):
   2582         """
   2583         Given a mapping of extras to dependencies, strip off
   2584         environment markers and filter out any dependencies
   2585         not matching the markers.
   2586         """
   2587         for extra in list(filter(None, dm)):
   2588             new_extra = extra
   2589             reqs = dm.pop(extra)
   2590             new_extra, _, marker = extra.partition(':')
   2591             fails_marker = marker and (
   2592                 invalid_marker(marker)
   2593                 or not evaluate_marker(marker)
   2594             )
   2595             if fails_marker:
   2596                 reqs = []
   2597             new_extra = safe_extra(new_extra) or None
   2598 
   2599             dm.setdefault(new_extra, []).extend(reqs)
   2600         return dm
   2601 
   2602     def _build_dep_map(self):
   2603         dm = {}
   2604         for name in 'requires.txt', 'depends.txt':
   2605             for extra, reqs in split_sections(self._get_metadata(name)):
   2606                 dm.setdefault(extra, []).extend(parse_requirements(reqs))
   2607         return dm
   2608 
   2609     def requires(self, extras=()):
   2610         """List of Requirements needed for this distro if `extras` are used"""
   2611         dm = self._dep_map
   2612         deps = []
   2613         deps.extend(dm.get(None, ()))
   2614         for ext in extras:
   2615             try:
   2616                 deps.extend(dm[safe_extra(ext)])
   2617             except KeyError:
   2618                 raise UnknownExtra(
   2619                     "%s has no such extra feature %r" % (self, ext)
   2620                 )
   2621         return deps
   2622 
   2623     def _get_metadata(self, name):
   2624         if self.has_metadata(name):
   2625             for line in self.get_metadata_lines(name):
   2626                 yield line
   2627 
   2628     def activate(self, path=None, replace=False):
   2629         """Ensure distribution is importable on `path` (default=sys.path)"""
   2630         if path is None:
   2631             path = sys.path
   2632         self.insert_on(path, replace=replace)
   2633         if path is sys.path:
   2634             fixup_namespace_packages(self.location)
   2635             for pkg in self._get_metadata('namespace_packages.txt'):
   2636                 if pkg in sys.modules:
   2637                     declare_namespace(pkg)
   2638 
   2639     def egg_name(self):
   2640         """Return what this distribution's standard .egg filename should be"""
   2641         filename = "%s-%s-py%s" % (
   2642             to_filename(self.project_name), to_filename(self.version),
   2643             self.py_version or PY_MAJOR
   2644         )
   2645 
   2646         if self.platform:
   2647             filename += '-' + self.platform
   2648         return filename
   2649 
   2650     def __repr__(self):
   2651         if self.location:
   2652             return "%s (%s)" % (self, self.location)
   2653         else:
   2654             return str(self)
   2655 
   2656     def __str__(self):
   2657         try:
   2658             version = getattr(self, 'version', None)
   2659         except ValueError:
   2660             version = None
   2661         version = version or "[unknown version]"
   2662         return "%s %s" % (self.project_name, version)
   2663 
   2664     def __getattr__(self, attr):
   2665         """Delegate all unrecognized public attributes to .metadata provider"""
   2666         if attr.startswith('_'):
   2667             raise AttributeError(attr)
   2668         return getattr(self._provider, attr)
   2669 
   2670     @classmethod
   2671     def from_filename(cls, filename, metadata=None, **kw):
   2672         return cls.from_location(
   2673             _normalize_cached(filename), os.path.basename(filename), metadata,
   2674             **kw
   2675         )
   2676 
   2677     def as_requirement(self):
   2678         """Return a ``Requirement`` that matches this distribution exactly"""
   2679         if isinstance(self.parsed_version, packaging.version.Version):
   2680             spec = "%s==%s" % (self.project_name, self.parsed_version)
   2681         else:
   2682             spec = "%s===%s" % (self.project_name, self.parsed_version)
   2683 
   2684         return Requirement.parse(spec)
   2685 
   2686     def load_entry_point(self, group, name):
   2687         """Return the `name` entry point of `group` or raise ImportError"""
   2688         ep = self.get_entry_info(group, name)
   2689         if ep is None:
   2690             raise ImportError("Entry point %r not found" % ((group, name),))
   2691         return ep.load()
   2692 
   2693     def get_entry_map(self, group=None):
   2694         """Return the entry point map for `group`, or the full entry map"""
   2695         try:
   2696             ep_map = self._ep_map
   2697         except AttributeError:
   2698             ep_map = self._ep_map = EntryPoint.parse_map(
   2699                 self._get_metadata('entry_points.txt'), self
   2700             )
   2701         if group is not None:
   2702             return ep_map.get(group, {})
   2703         return ep_map
   2704 
   2705     def get_entry_info(self, group, name):
   2706         """Return the EntryPoint object for `group`+`name`, or ``None``"""
   2707         return self.get_entry_map(group).get(name)
   2708 
   2709     def insert_on(self, path, loc=None, replace=False):
   2710         """Ensure self.location is on path
   2711 
   2712         If replace=False (default):
   2713             - If location is already in path anywhere, do nothing.
   2714             - Else:
   2715               - If it's an egg and its parent directory is on path,
   2716                 insert just ahead of the parent.
   2717               - Else: add to the end of path.
   2718         If replace=True:
   2719             - If location is already on path anywhere (not eggs)
   2720               or higher priority than its parent (eggs)
   2721               do nothing.
   2722             - Else:
   2723               - If it's an egg and its parent directory is on path,
   2724                 insert just ahead of the parent,
   2725                 removing any lower-priority entries.
   2726               - Else: add it to the front of path.
   2727         """
   2728 
   2729         loc = loc or self.location
   2730         if not loc:
   2731             return
   2732 
   2733         nloc = _normalize_cached(loc)
   2734         bdir = os.path.dirname(nloc)
   2735         npath = [(p and _normalize_cached(p) or p) for p in path]
   2736 
   2737         for p, item in enumerate(npath):
   2738             if item == nloc:
   2739                 if replace:
   2740                     break
   2741                 else:
   2742                     # don't modify path (even removing duplicates) if
   2743                     # found and not replace
   2744                     return
   2745             elif item == bdir and self.precedence == EGG_DIST:
   2746                 # if it's an .egg, give it precedence over its directory
   2747                 # UNLESS it's already been added to sys.path and replace=False
   2748                 if (not replace) and nloc in npath[p:]:
   2749                     return
   2750                 if path is sys.path:
   2751                     self.check_version_conflict()
   2752                 path.insert(p, loc)
   2753                 npath.insert(p, nloc)
   2754                 break
   2755         else:
   2756             if path is sys.path:
   2757                 self.check_version_conflict()
   2758             if replace:
   2759                 path.insert(0, loc)
   2760             else:
   2761                 path.append(loc)
   2762             return
   2763 
   2764         # p is the spot where we found or inserted loc; now remove duplicates
   2765         while True:
   2766             try:
   2767                 np = npath.index(nloc, p + 1)
   2768             except ValueError:
   2769                 break
   2770             else:
   2771                 del npath[np], path[np]
   2772                 # ha!
   2773                 p = np
   2774 
   2775         return
   2776 
   2777     def check_version_conflict(self):
   2778         if self.key == 'setuptools':
   2779             # ignore the inevitable setuptools self-conflicts  :(
   2780             return
   2781 
   2782         nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt'))
   2783         loc = normalize_path(self.location)
   2784         for modname in self._get_metadata('top_level.txt'):
   2785             if (modname not in sys.modules or modname in nsp
   2786                     or modname in _namespace_packages):
   2787                 continue
   2788             if modname in ('pkg_resources', 'setuptools', 'site'):
   2789                 continue
   2790             fn = getattr(sys.modules[modname], '__file__', None)
   2791             if fn and (normalize_path(fn).startswith(loc) or
   2792                        fn.startswith(self.location)):
   2793                 continue
   2794             issue_warning(
   2795                 "Module %s was already imported from %s, but %s is being added"
   2796                 " to sys.path" % (modname, fn, self.location),
   2797             )
   2798 
   2799     def has_version(self):
   2800         try:
   2801             self.version
   2802         except ValueError:
   2803             issue_warning("Unbuilt egg for " + repr(self))
   2804             return False
   2805         return True
   2806 
   2807     def clone(self, **kw):
   2808         """Copy this distribution, substituting in any changed keyword args"""
   2809         names = 'project_name version py_version platform location precedence'
   2810         for attr in names.split():
   2811             kw.setdefault(attr, getattr(self, attr, None))
   2812         kw.setdefault('metadata', self._provider)
   2813         return self.__class__(**kw)
   2814 
   2815     @property
   2816     def extras(self):
   2817         return [dep for dep in self._dep_map if dep]
   2818 
   2819 
   2820 class EggInfoDistribution(Distribution):
   2821     def _reload_version(self):
   2822         """
   2823         Packages installed by distutils (e.g. numpy or scipy),
   2824         which uses an old safe_version, and so
   2825         their version numbers can get mangled when
   2826         converted to filenames (e.g., 1.11.0.dev0+2329eae to
   2827         1.11.0.dev0_2329eae). These distributions will not be
   2828         parsed properly
   2829         downstream by Distribution and safe_version, so
   2830         take an extra step and try to get the version number from
   2831         the metadata file itself instead of the filename.
   2832         """
   2833         md_version = _version_from_file(self._get_metadata(self.PKG_INFO))
   2834         if md_version:
   2835             self._version = md_version
   2836         return self
   2837 
   2838 
   2839 class DistInfoDistribution(Distribution):
   2840     """
   2841     Wrap an actual or potential sys.path entry
   2842     w/metadata, .dist-info style.
   2843     """
   2844     PKG_INFO = 'METADATA'
   2845     EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])")
   2846 
   2847     @property
   2848     def _parsed_pkg_info(self):
   2849         """Parse and cache metadata"""
   2850         try:
   2851             return self._pkg_info
   2852         except AttributeError:
   2853             metadata = self.get_metadata(self.PKG_INFO)
   2854             self._pkg_info = email.parser.Parser().parsestr(metadata)
   2855             return self._pkg_info
   2856 
   2857     @property
   2858     def _dep_map(self):
   2859         try:
   2860             return self.__dep_map
   2861         except AttributeError:
   2862             self.__dep_map = self._compute_dependencies()
   2863             return self.__dep_map
   2864 
   2865     def _compute_dependencies(self):
   2866         """Recompute this distribution's dependencies."""
   2867         dm = self.__dep_map = {None: []}
   2868 
   2869         reqs = []
   2870         # Including any condition expressions
   2871         for req in self._parsed_pkg_info.get_all('Requires-Dist') or []:
   2872             reqs.extend(parse_requirements(req))
   2873 
   2874         def reqs_for_extra(extra):
   2875             for req in reqs:
   2876                 if not req.marker or req.marker.evaluate({'extra': extra}):
   2877                     yield req
   2878 
   2879         common = frozenset(reqs_for_extra(None))
   2880         dm[None].extend(common)
   2881 
   2882         for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []:
   2883             s_extra = safe_extra(extra.strip())
   2884             dm[s_extra] = list(frozenset(reqs_for_extra(extra)) - common)
   2885 
   2886         return dm
   2887 
   2888 
   2889 _distributionImpl = {
   2890     '.egg': Distribution,
   2891     '.egg-info': EggInfoDistribution,
   2892     '.dist-info': DistInfoDistribution,
   2893 }
   2894 
   2895 
   2896 def issue_warning(*args, **kw):
   2897     level = 1
   2898     g = globals()
   2899     try:
   2900         # find the first stack frame that is *not* code in
   2901         # the pkg_resources module, to use for the warning
   2902         while sys._getframe(level).f_globals is g:
   2903             level += 1
   2904     except ValueError:
   2905         pass
   2906     warnings.warn(stacklevel=level + 1, *args, **kw)
   2907 
   2908 
   2909 class RequirementParseError(ValueError):
   2910     def __str__(self):
   2911         return ' '.join(self.args)
   2912 
   2913 
   2914 def parse_requirements(strs):
   2915     """Yield ``Requirement`` objects for each specification in `strs`
   2916 
   2917     `strs` must be a string, or a (possibly-nested) iterable thereof.
   2918     """
   2919     # create a steppable iterator, so we can handle \-continuations
   2920     lines = iter(yield_lines(strs))
   2921 
   2922     for line in lines:
   2923         # Drop comments -- a hash without a space may be in a URL.
   2924         if ' #' in line:
   2925             line = line[:line.find(' #')]
   2926         # If there is a line continuation, drop it, and append the next line.
   2927         if line.endswith('\\'):
   2928             line = line[:-2].strip()
   2929             try:
   2930                 line += next(lines)
   2931             except StopIteration:
   2932                 return
   2933         yield Requirement(line)
   2934 
   2935 
   2936 class Requirement(packaging.requirements.Requirement):
   2937     def __init__(self, requirement_string):
   2938         """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
   2939         try:
   2940             super(Requirement, self).__init__(requirement_string)
   2941         except packaging.requirements.InvalidRequirement as e:
   2942             raise RequirementParseError(str(e))
   2943         self.unsafe_name = self.name
   2944         project_name = safe_name(self.name)
   2945         self.project_name, self.key = project_name, project_name.lower()
   2946         self.specs = [
   2947             (spec.operator, spec.version) for spec in self.specifier]
   2948         self.extras = tuple(map(safe_extra, self.extras))
   2949         self.hashCmp = (
   2950             self.key,
   2951             self.specifier,
   2952             frozenset(self.extras),
   2953             str(self.marker) if self.marker else None,
   2954         )
   2955         self.__hash = hash(self.hashCmp)
   2956 
   2957     def __eq__(self, other):
   2958         return (
   2959             isinstance(other, Requirement) and
   2960             self.hashCmp == other.hashCmp
   2961         )
   2962 
   2963     def __ne__(self, other):
   2964         return not self == other
   2965 
   2966     def __contains__(self, item):
   2967         if isinstance(item, Distribution):
   2968             if item.key != self.key:
   2969                 return False
   2970 
   2971             item = item.version
   2972 
   2973         # Allow prereleases always in order to match the previous behavior of
   2974         # this method. In the future this should be smarter and follow PEP 440
   2975         # more accurately.
   2976         return self.specifier.contains(item, prereleases=True)
   2977 
   2978     def __hash__(self):
   2979         return self.__hash
   2980 
   2981     def __repr__(self):
   2982         return "Requirement.parse(%r)" % str(self)
   2983 
   2984     @staticmethod
   2985     def parse(s):
   2986         req, = parse_requirements(s)
   2987         return req
   2988 
   2989 
   2990 def _always_object(classes):
   2991     """
   2992     Ensure object appears in the mro even
   2993     for old-style classes.
   2994     """
   2995     if object not in classes:
   2996         return classes + (object,)
   2997     return classes
   2998 
   2999 
   3000 def _find_adapter(registry, ob):
   3001     """Return an adapter factory for `ob` from `registry`"""
   3002     types = _always_object(inspect.getmro(getattr(ob, '__class__', type(ob))))
   3003     for t in types:
   3004         if t in registry:
   3005             return registry[t]
   3006 
   3007 
   3008 def ensure_directory(path):
   3009     """Ensure that the parent directory of `path` exists"""
   3010     dirname = os.path.dirname(path)
   3011     py31compat.makedirs(dirname, exist_ok=True)
   3012 
   3013 
   3014 def _bypass_ensure_directory(path):
   3015     """Sandbox-bypassing version of ensure_directory()"""
   3016     if not WRITE_SUPPORT:
   3017         raise IOError('"os.mkdir" not supported on this platform.')
   3018     dirname, filename = split(path)
   3019     if dirname and filename and not isdir(dirname):
   3020         _bypass_ensure_directory(dirname)
   3021         mkdir(dirname, 0o755)
   3022 
   3023 
   3024 def split_sections(s):
   3025     """Split a string or iterable thereof into (section, content) pairs
   3026 
   3027     Each ``section`` is a stripped version of the section header ("[section]")
   3028     and each ``content`` is a list of stripped lines excluding blank lines and
   3029     comment-only lines.  If there are any such lines before the first section
   3030     header, they're returned in a first ``section`` of ``None``.
   3031     """
   3032     section = None
   3033     content = []
   3034     for line in yield_lines(s):
   3035         if line.startswith("["):
   3036             if line.endswith("]"):
   3037                 if section or content:
   3038                     yield section, content
   3039                 section = line[1:-1].strip()
   3040                 content = []
   3041             else:
   3042                 raise ValueError("Invalid section heading", line)
   3043         else:
   3044             content.append(line)
   3045 
   3046     # wrap up last segment
   3047     yield section, content
   3048 
   3049 
   3050 def _mkstemp(*args, **kw):
   3051     old_open = os.open
   3052     try:
   3053         # temporarily bypass sandboxing
   3054         os.open = os_open
   3055         return tempfile.mkstemp(*args, **kw)
   3056     finally:
   3057         # and then put it back
   3058         os.open = old_open
   3059 
   3060 
   3061 # Silence the PEP440Warning by default, so that end users don't get hit by it
   3062 # randomly just because they use pkg_resources. We want to append the rule
   3063 # because we want earlier uses of filterwarnings to take precedence over this
   3064 # one.
   3065 warnings.filterwarnings("ignore", category=PEP440Warning, append=True)
   3066 
   3067 
   3068 # from jaraco.functools 1.3
   3069 def _call_aside(f, *args, **kwargs):
   3070     f(*args, **kwargs)
   3071     return f
   3072 
   3073 
   3074 @_call_aside
   3075 def _initialize(g=globals()):
   3076     "Set up global resource manager (deliberately not state-saved)"
   3077     manager = ResourceManager()
   3078     g['_manager'] = manager
   3079     g.update(
   3080         (name, getattr(manager, name))
   3081         for name in dir(manager)
   3082         if not name.startswith('_')
   3083     )
   3084 
   3085 
   3086 @_call_aside
   3087 def _initialize_master_working_set():
   3088     """
   3089     Prepare the master working set and make the ``require()``
   3090     API available.
   3091 
   3092     This function has explicit effects on the global state
   3093     of pkg_resources. It is intended to be invoked once at
   3094     the initialization of this module.
   3095 
   3096     Invocation by other packages is unsupported and done
   3097     at their own risk.
   3098     """
   3099     working_set = WorkingSet._build_master()
   3100     _declare_state('object', working_set=working_set)
   3101 
   3102     require = working_set.require
   3103     iter_entry_points = working_set.iter_entry_points
   3104     add_activation_listener = working_set.subscribe
   3105     run_script = working_set.run_script
   3106     # backward compatibility
   3107     run_main = run_script
   3108     # Activate all distributions already on sys.path with replace=False and
   3109     # ensure that all distributions added to the working set in the future
   3110     # (e.g. by calling ``require()``) will get activated as well,
   3111     # with higher priority (replace=True).
   3112     tuple(
   3113         dist.activate(replace=False)
   3114         for dist in working_set
   3115     )
   3116     add_activation_listener(
   3117         lambda dist: dist.activate(replace=True),
   3118         existing=False,
   3119     )
   3120     working_set.entries = []
   3121     # match order
   3122     list(map(working_set.add_entry, sys.path))
   3123     globals().update(locals())
   3124