Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
__init__.py3326 linesDownload Raw Back to pkg_resources
1"""2Package resource API3--------------------4 5A resource is a logical file contained within a package, or a logical6subdirectory thereof.  The package resource API expects resource names7to have their path parts separated with ``/``, *not* whatever the local8path separator is.  Do not use os.path operations to manipulate resource9names being passed into the API.10 11The package resource API is designed to work with normal filesystem packages,12.egg files, and unpacked .egg files.  It can also work in a limited way with13.zip files and with custom PEP 302 loaders that support the ``get_data()``14method.15 16This module is deprecated. Users are directed to :mod:`importlib.resources`,17:mod:`importlib.metadata` and :pypi:`packaging` instead.18"""19 20import sys21 22if sys.version_info < (3, 8):23    raise RuntimeError("Python 3.8 or later is required")24 25import os26import io27import time28import re29import types30from typing import List, Protocol31import zipfile32import zipimport33import warnings34import stat35import functools36import pkgutil37import operator38import platform39import collections40import plistlib41import email.parser42import errno43import tempfile44import textwrap45import inspect46import ntpath47import posixpath48import importlib49import importlib.machinery50from pkgutil import get_importer51 52import _imp53 54# capture these to bypass sandboxing55from os import utime56 57try:58    from os import mkdir, rename, unlink59 60    WRITE_SUPPORT = True61except ImportError:62    # no write support, probably under GAE63    WRITE_SUPPORT = False64 65from os import open as os_open66from os.path import isdir, split67 68from pkg_resources.extern.jaraco.text import (69    yield_lines,70    drop_comment,71    join_continuation,72)73 74from pkg_resources.extern import platformdirs75from pkg_resources.extern import packaging76 77__import__('pkg_resources.extern.packaging.version')78__import__('pkg_resources.extern.packaging.specifiers')79__import__('pkg_resources.extern.packaging.requirements')80__import__('pkg_resources.extern.packaging.markers')81__import__('pkg_resources.extern.packaging.utils')82 83# declare some globals that will be defined later to84# satisfy the linters.85require = None86working_set = None87add_activation_listener = None88cleanup_resources = None89resource_stream = None90set_extraction_path = None91resource_isdir = None92resource_string = None93iter_entry_points = None94resource_listdir = None95resource_filename = None96resource_exists = None97_distribution_finders = None98_namespace_handlers = None99_namespace_packages = None100 101 102warnings.warn(103    "pkg_resources is deprecated as an API. "104    "See https://setuptools.pypa.io/en/latest/pkg_resources.html",105    DeprecationWarning,106    stacklevel=2,107)108 109 110_PEP440_FALLBACK = re.compile(r"^v?(?P<safe>(?:[0-9]+!)?[0-9]+(?:\.[0-9]+)*)", re.I)111 112 113class PEP440Warning(RuntimeWarning):114    """115    Used when there is an issue with a version or specifier not complying with116    PEP 440.117    """118 119 120parse_version = packaging.version.Version121 122 123_state_vars = {}124 125 126def _declare_state(vartype, **kw):127    globals().update(kw)128    _state_vars.update(dict.fromkeys(kw, vartype))129 130 131def __getstate__():132    state = {}133    g = globals()134    for k, v in _state_vars.items():135        state[k] = g['_sget_' + v](g[k])136    return state137 138 139def __setstate__(state):140    g = globals()141    for k, v in state.items():142        g['_sset_' + _state_vars[k]](k, g[k], v)143    return state144 145 146def _sget_dict(val):147    return val.copy()148 149 150def _sset_dict(key, ob, state):151    ob.clear()152    ob.update(state)153 154 155def _sget_object(val):156    return val.__getstate__()157 158 159def _sset_object(key, ob, state):160    ob.__setstate__(state)161 162 163_sget_none = _sset_none = lambda *args: None164 165 166def get_supported_platform():167    """Return this platform's maximum compatible version.168 169    distutils.util.get_platform() normally reports the minimum version170    of macOS that would be required to *use* extensions produced by171    distutils.  But what we want when checking compatibility is to know the172    version of macOS that we are *running*.  To allow usage of packages that173    explicitly require a newer version of macOS, we must also know the174    current version of the OS.175 176    If this condition occurs for any other platform with a version in its177    platform strings, this function should be extended accordingly.178    """179    plat = get_build_platform()180    m = macosVersionString.match(plat)181    if m is not None and sys.platform == "darwin":182        try:183            plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3))184        except ValueError:185            # not macOS186            pass187    return plat188 189 190__all__ = [191    # Basic resource access and distribution/entry point discovery192    'require',193    'run_script',194    'get_provider',195    'get_distribution',196    'load_entry_point',197    'get_entry_map',198    'get_entry_info',199    'iter_entry_points',200    'resource_string',201    'resource_stream',202    'resource_filename',203    'resource_listdir',204    'resource_exists',205    'resource_isdir',206    # Environmental control207    'declare_namespace',208    'working_set',209    'add_activation_listener',210    'find_distributions',211    'set_extraction_path',212    'cleanup_resources',213    'get_default_cache',214    # Primary implementation classes215    'Environment',216    'WorkingSet',217    'ResourceManager',218    'Distribution',219    'Requirement',220    'EntryPoint',221    # Exceptions222    'ResolutionError',223    'VersionConflict',224    'DistributionNotFound',225    'UnknownExtra',226    'ExtractionError',227    # Warnings228    'PEP440Warning',229    # Parsing functions and string utilities230    'parse_requirements',231    'parse_version',232    'safe_name',233    'safe_version',234    'get_platform',235    'compatible_platforms',236    'yield_lines',237    'split_sections',238    'safe_extra',239    'to_filename',240    'invalid_marker',241    'evaluate_marker',242    # filesystem utilities243    'ensure_directory',244    'normalize_path',245    # Distribution "precedence" constants246    'EGG_DIST',247    'BINARY_DIST',248    'SOURCE_DIST',249    'CHECKOUT_DIST',250    'DEVELOP_DIST',251    # "Provider" interfaces, implementations, and registration/lookup APIs252    'IMetadataProvider',253    'IResourceProvider',254    'FileMetadata',255    'PathMetadata',256    'EggMetadata',257    'EmptyProvider',258    'empty_provider',259    'NullProvider',260    'EggProvider',261    'DefaultProvider',262    'ZipProvider',263    'register_finder',264    'register_namespace_handler',265    'register_loader_type',266    'fixup_namespace_packages',267    'get_importer',268    # Warnings269    'PkgResourcesDeprecationWarning',270    # Deprecated/backward compatibility only271    'run_main',272    'AvailableDistributions',273]274 275 276class ResolutionError(Exception):277    """Abstract base for dependency resolution errors"""278 279    def __repr__(self):280        return self.__class__.__name__ + repr(self.args)281 282 283class VersionConflict(ResolutionError):284    """285    An already-installed version conflicts with the requested version.286 287    Should be initialized with the installed Distribution and the requested288    Requirement.289    """290 291    _template = "{self.dist} is installed but {self.req} is required"292 293    @property294    def dist(self):295        return self.args[0]296 297    @property298    def req(self):299        return self.args[1]300 301    def report(self):302        return self._template.format(**locals())303 304    def with_context(self, required_by):305        """306        If required_by is non-empty, return a version of self that is a307        ContextualVersionConflict.308        """309        if not required_by:310            return self311        args = self.args + (required_by,)312        return ContextualVersionConflict(*args)313 314 315class ContextualVersionConflict(VersionConflict):316    """317    A VersionConflict that accepts a third parameter, the set of the318    requirements that required the installed Distribution.319    """320 321    _template = VersionConflict._template + ' by {self.required_by}'322 323    @property324    def required_by(self):325        return self.args[2]326 327 328class DistributionNotFound(ResolutionError):329    """A requested distribution was not found"""330 331    _template = (332        "The '{self.req}' distribution was not found "333        "and is required by {self.requirers_str}"334    )335 336    @property337    def req(self):338        return self.args[0]339 340    @property341    def requirers(self):342        return self.args[1]343 344    @property345    def requirers_str(self):346        if not self.requirers:347            return 'the application'348        return ', '.join(self.requirers)349 350    def report(self):351        return self._template.format(**locals())352 353    def __str__(self):354        return self.report()355 356 357class UnknownExtra(ResolutionError):358    """Distribution doesn't have an "extra feature" of the given name"""359 360 361_provider_factories = {}362 363PY_MAJOR = '{}.{}'.format(*sys.version_info)364EGG_DIST = 3365BINARY_DIST = 2366SOURCE_DIST = 1367CHECKOUT_DIST = 0368DEVELOP_DIST = -1369 370 371def register_loader_type(loader_type, provider_factory):372    """Register `provider_factory` to make providers for `loader_type`373 374    `loader_type` is the type or class of a PEP 302 ``module.__loader__``,375    and `provider_factory` is a function that, passed a *module* object,376    returns an ``IResourceProvider`` for that module.377    """378    _provider_factories[loader_type] = provider_factory379 380 381def get_provider(moduleOrReq):382    """Return an IResourceProvider for the named module or requirement"""383    if isinstance(moduleOrReq, Requirement):384        return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0]385    try:386        module = sys.modules[moduleOrReq]387    except KeyError:388        __import__(moduleOrReq)389        module = sys.modules[moduleOrReq]390    loader = getattr(module, '__loader__', None)391    return _find_adapter(_provider_factories, loader)(module)392 393 394@functools.lru_cache(maxsize=None)395def _macos_vers():396    version = platform.mac_ver()[0]397    # fallback for MacPorts398    if version == '':399        plist = '/System/Library/CoreServices/SystemVersion.plist'400        if os.path.exists(plist):401            with open(plist, 'rb') as fh:402                plist_content = plistlib.load(fh)403            if 'ProductVersion' in plist_content:404                version = plist_content['ProductVersion']405    return version.split('.')406 407 408def _macos_arch(machine):409    return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine)410 411 412def get_build_platform():413    """Return this platform's string for platform-specific distributions414 415    XXX Currently this is the same as ``distutils.util.get_platform()``, but it416    needs some hacks for Linux and macOS.417    """418    from sysconfig import get_platform419 420    plat = get_platform()421    if sys.platform == "darwin" and not plat.startswith('macosx-'):422        try:423            version = _macos_vers()424            machine = os.uname()[4].replace(" ", "_")425            return "macosx-%d.%d-%s" % (426                int(version[0]),427                int(version[1]),428                _macos_arch(machine),429            )430        except ValueError:431            # if someone is running a non-Mac darwin system, this will fall432            # through to the default implementation433            pass434    return plat435 436 437macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)")438darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)")439# XXX backward compat440get_platform = get_build_platform441 442 443def compatible_platforms(provided, required):444    """Can code for the `provided` platform run on the `required` platform?445 446    Returns true if either platform is ``None``, or the platforms are equal.447 448    XXX Needs compatibility checks for Linux and other unixy OSes.449    """450    if provided is None or required is None or provided == required:451        # easy case452        return True453 454    # macOS special cases455    reqMac = macosVersionString.match(required)456    if reqMac:457        provMac = macosVersionString.match(provided)458 459        # is this a Mac package?460        if not provMac:461            # this is backwards compatibility for packages built before462            # setuptools 0.6. All packages built after this point will463            # use the new macOS designation.464            provDarwin = darwinVersionString.match(provided)465            if provDarwin:466                dversion = int(provDarwin.group(1))467                macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2))468                if (469                    dversion == 7470                    and macosversion >= "10.3"471                    or dversion == 8472                    and macosversion >= "10.4"473                ):474                    return True475            # egg isn't macOS or legacy darwin476            return False477 478        # are they the same major version and machine type?479        if provMac.group(1) != reqMac.group(1) or provMac.group(3) != reqMac.group(3):480            return False481 482        # is the required OS major update >= the provided one?483        if int(provMac.group(2)) > int(reqMac.group(2)):484            return False485 486        return True487 488    # XXX Linux and other platforms' special cases should go here489    return False490 491 492def get_distribution(dist):493    """Return a current distribution object for a Requirement or string"""494    if isinstance(dist, str):495        dist = Requirement.parse(dist)496    if isinstance(dist, Requirement):497        dist = get_provider(dist)498    if not isinstance(dist, Distribution):499        raise TypeError("Expected string, Requirement, or Distribution", dist)500    return dist501 502 503def load_entry_point(dist, group, name):504    """Return `name` entry point of `group` for `dist` or raise ImportError"""505    return get_distribution(dist).load_entry_point(group, name)506 507 508def get_entry_map(dist, group=None):509    """Return the entry point map for `group`, or the full entry map"""510    return get_distribution(dist).get_entry_map(group)511 512 513def get_entry_info(dist, group, name):514    """Return the EntryPoint object for `group`+`name`, or ``None``"""515    return get_distribution(dist).get_entry_info(group, name)516 517 518class IMetadataProvider(Protocol):519    def has_metadata(self, name) -> bool:520        """Does the package's distribution contain the named metadata?"""521 522    def get_metadata(self, name):523        """The named metadata resource as a string"""524 525    def get_metadata_lines(self, name):526        """Yield named metadata resource as list of non-blank non-comment lines527 528        Leading and trailing whitespace is stripped from each line, and lines529        with ``#`` as the first non-blank character are omitted."""530 531    def metadata_isdir(self, name) -> bool:532        """Is the named metadata a directory?  (like ``os.path.isdir()``)"""533 534    def metadata_listdir(self, name):535        """List of metadata names in the directory (like ``os.listdir()``)"""536 537    def run_script(self, script_name, namespace):538        """Execute the named script in the supplied namespace dictionary"""539 540 541class IResourceProvider(IMetadataProvider, Protocol):542    """An object that provides access to package resources"""543 544    def get_resource_filename(self, manager, resource_name):545        """Return a true filesystem path for `resource_name`546 547        `manager` must be an ``IResourceManager``"""548 549    def get_resource_stream(self, manager, resource_name):550        """Return a readable file-like object for `resource_name`551 552        `manager` must be an ``IResourceManager``"""553 554    def get_resource_string(self, manager, resource_name) -> bytes:555        """Return the contents of `resource_name` as :obj:`bytes`556 557        `manager` must be an ``IResourceManager``"""558 559    def has_resource(self, resource_name):560        """Does the package contain the named resource?"""561 562    def resource_isdir(self, resource_name):563        """Is the named resource a directory?  (like ``os.path.isdir()``)"""564 565    def resource_listdir(self, resource_name):566        """List of resource names in the directory (like ``os.listdir()``)"""567 568 569class WorkingSet:570    """A collection of active distributions on sys.path (or a similar list)"""571 572    def __init__(self, entries=None):573        """Create working set from list of path entries (default=sys.path)"""574        self.entries = []575        self.entry_keys = {}576        self.by_key = {}577        self.normalized_to_canonical_keys = {}578        self.callbacks = []579 580        if entries is None:581            entries = sys.path582 583        for entry in entries:584            self.add_entry(entry)585 586    @classmethod587    def _build_master(cls):588        """589        Prepare the master working set.590        """591        ws = cls()592        try:593            from __main__ import __requires__594        except ImportError:595            # The main program does not list any requirements596            return ws597 598        # ensure the requirements are met599        try:600            ws.require(__requires__)601        except VersionConflict:602            return cls._build_from_requirements(__requires__)603 604        return ws605 606    @classmethod607    def _build_from_requirements(cls, req_spec):608        """609        Build a working set from a requirement spec. Rewrites sys.path.610        """611        # try it without defaults already on sys.path612        # by starting with an empty path613        ws = cls([])614        reqs = parse_requirements(req_spec)615        dists = ws.resolve(reqs, Environment())616        for dist in dists:617            ws.add(dist)618 619        # add any missing entries from sys.path620        for entry in sys.path:621            if entry not in ws.entries:622                ws.add_entry(entry)623 624        # then copy back to sys.path625        sys.path[:] = ws.entries626        return ws627 628    def add_entry(self, entry):629        """Add a path item to ``.entries``, finding any distributions on it630 631        ``find_distributions(entry, True)`` is used to find distributions632        corresponding to the path entry, and they are added.  `entry` is633        always appended to ``.entries``, even if it is already present.634        (This is because ``sys.path`` can contain the same value more than635        once, and the ``.entries`` of the ``sys.path`` WorkingSet should always636        equal ``sys.path``.)637        """638        self.entry_keys.setdefault(entry, [])639        self.entries.append(entry)640        for dist in find_distributions(entry, True):641            self.add(dist, entry, False)642 643    def __contains__(self, dist):644        """True if `dist` is the active distribution for its project"""645        return self.by_key.get(dist.key) == dist646 647    def find(self, req):648        """Find a distribution matching requirement `req`649 650        If there is an active distribution for the requested project, this651        returns it as long as it meets the version requirement specified by652        `req`.  But, if there is an active distribution for the project and it653        does *not* meet the `req` requirement, ``VersionConflict`` is raised.654        If there is no active distribution for the requested project, ``None``655        is returned.656        """657        dist = self.by_key.get(req.key)658 659        if dist is None:660            canonical_key = self.normalized_to_canonical_keys.get(req.key)661 662            if canonical_key is not None:663                req.key = canonical_key664                dist = self.by_key.get(canonical_key)665 666        if dist is not None and dist not in req:667            # XXX add more info668            raise VersionConflict(dist, req)669        return dist670 671    def iter_entry_points(self, group, name=None):672        """Yield entry point objects from `group` matching `name`673 674        If `name` is None, yields all entry points in `group` from all675        distributions in the working set, otherwise only ones matching676        both `group` and `name` are yielded (in distribution order).677        """678        return (679            entry680            for dist in self681            for entry in dist.get_entry_map(group).values()682            if name is None or name == entry.name683        )684 685    def run_script(self, requires, script_name):686        """Locate distribution for `requires` and run `script_name` script"""687        ns = sys._getframe(1).f_globals688        name = ns['__name__']689        ns.clear()690        ns['__name__'] = name691        self.require(requires)[0].run_script(script_name, ns)692 693    def __iter__(self):694        """Yield distributions for non-duplicate projects in the working set695 696        The yield order is the order in which the items' path entries were697        added to the working set.698        """699        seen = {}700        for item in self.entries:701            if item not in self.entry_keys:702                # workaround a cache issue703                continue704 705            for key in self.entry_keys[item]:706                if key not in seen:707                    seen[key] = 1708                    yield self.by_key[key]709 710    def add(self, dist, entry=None, insert=True, replace=False):711        """Add `dist` to working set, associated with `entry`712 713        If `entry` is unspecified, it defaults to the ``.location`` of `dist`.714        On exit from this routine, `entry` is added to the end of the working715        set's ``.entries`` (if it wasn't already present).716 717        `dist` is only added to the working set if it's for a project that718        doesn't already have a distribution in the set, unless `replace=True`.719        If it's added, any callbacks registered with the ``subscribe()`` method720        will be called.721        """722        if insert:723            dist.insert_on(self.entries, entry, replace=replace)724 725        if entry is None:726            entry = dist.location727        keys = self.entry_keys.setdefault(entry, [])728        keys2 = self.entry_keys.setdefault(dist.location, [])729        if not replace and dist.key in self.by_key:730            # ignore hidden distros731            return732 733        self.by_key[dist.key] = dist734        normalized_name = packaging.utils.canonicalize_name(dist.key)735        self.normalized_to_canonical_keys[normalized_name] = dist.key736        if dist.key not in keys:737            keys.append(dist.key)738        if dist.key not in keys2:739            keys2.append(dist.key)740        self._added_new(dist)741 742    def resolve(743        self,744        requirements,745        env=None,746        installer=None,747        replace_conflicting=False,748        extras=None,749    ):750        """List all distributions needed to (recursively) meet `requirements`751 752        `requirements` must be a sequence of ``Requirement`` objects.  `env`,753        if supplied, should be an ``Environment`` instance.  If754        not supplied, it defaults to all distributions available within any755        entry or distribution in the working set.  `installer`, if supplied,756        will be invoked with each requirement that cannot be met by an757        already-installed distribution; it should return a ``Distribution`` or758        ``None``.759 760        Unless `replace_conflicting=True`, raises a VersionConflict exception761        if762        any requirements are found on the path that have the correct name but763        the wrong version.  Otherwise, if an `installer` is supplied it will be764        invoked to obtain the correct version of the requirement and activate765        it.766 767        `extras` is a list of the extras to be used with these requirements.768        This is important because extra requirements may look like `my_req;769        extra = "my_extra"`, which would otherwise be interpreted as a purely770        optional requirement.  Instead, we want to be able to assert that these771        requirements are truly required.772        """773 774        # set up the stack775        requirements = list(requirements)[::-1]776        # set of processed requirements777        processed = {}778        # key -> dist779        best = {}780        to_activate = []781 782        req_extras = _ReqExtras()783 784        # Mapping of requirement to set of distributions that required it;785        # useful for reporting info about conflicts.786        required_by = collections.defaultdict(set)787 788        while requirements:789            # process dependencies breadth-first790            req = requirements.pop(0)791            if req in processed:792                # Ignore cyclic or redundant dependencies793                continue794 795            if not req_extras.markers_pass(req, extras):796                continue797 798            dist = self._resolve_dist(799                req, best, replace_conflicting, env, installer, required_by, to_activate800            )801 802            # push the new requirements onto the stack803            new_requirements = dist.requires(req.extras)[::-1]804            requirements.extend(new_requirements)805 806            # Register the new requirements needed by req807            for new_requirement in new_requirements:808                required_by[new_requirement].add(req.project_name)809                req_extras[new_requirement] = req.extras810 811            processed[req] = True812 813        # return list of distros to activate814        return to_activate815 816    def _resolve_dist(817        self, req, best, replace_conflicting, env, installer, required_by, to_activate818    ):819        dist = best.get(req.key)820        if dist is None:821            # Find the best distribution and add it to the map822            dist = self.by_key.get(req.key)823            if dist is None or (dist not in req and replace_conflicting):824                ws = self825                if env is None:826                    if dist is None:827                        env = Environment(self.entries)828                    else:829                        # Use an empty environment and workingset to avoid830                        # any further conflicts with the conflicting831                        # distribution832                        env = Environment([])833                        ws = WorkingSet([])834                dist = best[req.key] = env.best_match(835                    req, ws, installer, replace_conflicting=replace_conflicting836                )837                if dist is None:838                    requirers = required_by.get(req, None)839                    raise DistributionNotFound(req, requirers)840            to_activate.append(dist)841        if dist not in req:842            # Oops, the "best" so far conflicts with a dependency843            dependent_req = required_by[req]844            raise VersionConflict(dist, req).with_context(dependent_req)845        return dist846 847    def find_plugins(self, plugin_env, full_env=None, installer=None, fallback=True):848        """Find all activatable distributions in `plugin_env`849 850        Example usage::851 852            distributions, errors = working_set.find_plugins(853                Environment(plugin_dirlist)854            )855            # add plugins+libs to sys.path856            map(working_set.add, distributions)857            # display errors858            print('Could not load', errors)859 860        The `plugin_env` should be an ``Environment`` instance that contains861        only distributions that are in the project's "plugin directory" or862        directories. The `full_env`, if supplied, should be an ``Environment``863        contains all currently-available distributions.  If `full_env` is not864        supplied, one is created automatically from the ``WorkingSet`` this865        method is called on, which will typically mean that every directory on866        ``sys.path`` will be scanned for distributions.867 868        `installer` is a standard installer callback as used by the869        ``resolve()`` method. The `fallback` flag indicates whether we should870        attempt to resolve older versions of a plugin if the newest version871        cannot be resolved.872 873        This method returns a 2-tuple: (`distributions`, `error_info`), where874        `distributions` is a list of the distributions found in `plugin_env`875        that were loadable, along with any other distributions that are needed876        to resolve their dependencies.  `error_info` is a dictionary mapping877        unloadable plugin distributions to an exception instance describing the878        error that occurred. Usually this will be a ``DistributionNotFound`` or879        ``VersionConflict`` instance.880        """881 882        plugin_projects = list(plugin_env)883        # scan project names in alphabetic order884        plugin_projects.sort()885 886        error_info = {}887        distributions = {}888 889        if full_env is None:890            env = Environment(self.entries)891            env += plugin_env892        else:893            env = full_env + plugin_env894 895        shadow_set = self.__class__([])896        # put all our entries in shadow_set897        list(map(shadow_set.add, self))898 899        for project_name in plugin_projects:900            for dist in plugin_env[project_name]:901                req = [dist.as_requirement()]902 903                try:904                    resolvees = shadow_set.resolve(req, env, installer)905 906                except ResolutionError as v:907                    # save error info908                    error_info[dist] = v909                    if fallback:910                        # try the next older version of project911                        continue912                    else:913                        # give up on this project, keep going914                        break915 916                else:917                    list(map(shadow_set.add, resolvees))918                    distributions.update(dict.fromkeys(resolvees))919 920                    # success, no need to try any more versions of this project921                    break922 923        distributions = list(distributions)924        distributions.sort()925 926        return distributions, error_info927 928    def require(self, *requirements):929        """Ensure that distributions matching `requirements` are activated930 931        `requirements` must be a string or a (possibly-nested) sequence932        thereof, specifying the distributions and versions required.  The933        return value is a sequence of the distributions that needed to be934        activated to fulfill the requirements; all relevant distributions are935        included, even if they were already activated in this working set.936        """937        needed = self.resolve(parse_requirements(requirements))938 939        for dist in needed:940            self.add(dist)941 942        return needed943 944    def subscribe(self, callback, existing=True):945        """Invoke `callback` for all distributions946 947        If `existing=True` (default),948        call on all existing ones, as well.949        """950        if callback in self.callbacks:951            return952        self.callbacks.append(callback)953        if not existing:954            return955        for dist in self:956            callback(dist)957 958    def _added_new(self, dist):959        for callback in self.callbacks:960            callback(dist)961 962    def __getstate__(self):963        return (964            self.entries[:],965            self.entry_keys.copy(),966            self.by_key.copy(),967            self.normalized_to_canonical_keys.copy(),968            self.callbacks[:],969        )970 971    def __setstate__(self, e_k_b_n_c):972        entries, keys, by_key, normalized_to_canonical_keys, callbacks = e_k_b_n_c973        self.entries = entries[:]974        self.entry_keys = keys.copy()975        self.by_key = by_key.copy()976        self.normalized_to_canonical_keys = normalized_to_canonical_keys.copy()977        self.callbacks = callbacks[:]978 979 980class _ReqExtras(dict):981    """982    Map each requirement to the extras that demanded it.983    """984 985    def markers_pass(self, req, extras=None):986        """987        Evaluate markers for req against each extra that988        demanded it.989 990        Return False if the req has a marker and fails991        evaluation. Otherwise, return True.992        """993        extra_evals = (994            req.marker.evaluate({'extra': extra})995            for extra in self.get(req, ()) + (extras or (None,))996        )997        return not req.marker or any(extra_evals)998 999 1000class Environment:1001    """Searchable snapshot of distributions on a search path"""1002 1003    def __init__(1004        self, search_path=None, platform=get_supported_platform(), python=PY_MAJOR1005    ):1006        """Snapshot distributions available on a search path1007 1008        Any distributions found on `search_path` are added to the environment.1009        `search_path` should be a sequence of ``sys.path`` items.  If not1010        supplied, ``sys.path`` is used.1011 1012        `platform` is an optional string specifying the name of the platform1013        that platform-specific distributions must be compatible with.  If1014        unspecified, it defaults to the current platform.  `python` is an1015        optional string naming the desired version of Python (e.g. ``'3.6'``);1016        it defaults to the current version.1017 1018        You may explicitly set `platform` (and/or `python`) to ``None`` if you1019        wish to map *all* distributions, not just those compatible with the1020        running platform or Python version.1021        """1022        self._distmap = {}1023        self.platform = platform1024        self.python = python1025        self.scan(search_path)1026 1027    def can_add(self, dist):1028        """Is distribution `dist` acceptable for this environment?1029 1030        The distribution must match the platform and python version1031        requirements specified when this environment was created, or False1032        is returned.1033        """1034        py_compat = (1035            self.python is None1036            or dist.py_version is None1037            or dist.py_version == self.python1038        )1039        return py_compat and compatible_platforms(dist.platform, self.platform)1040 1041    def remove(self, dist):1042        """Remove `dist` from the environment"""1043        self._distmap[dist.key].remove(dist)1044 1045    def scan(self, search_path=None):1046        """Scan `search_path` for distributions usable in this environment1047 1048        Any distributions found are added to the environment.1049        `search_path` should be a sequence of ``sys.path`` items.  If not1050        supplied, ``sys.path`` is used.  Only distributions conforming to1051        the platform/python version defined at initialization are added.1052        """1053        if search_path is None:1054            search_path = sys.path1055 1056        for item in search_path:1057            for dist in find_distributions(item):1058                self.add(dist)1059 1060    def __getitem__(self, project_name):1061        """Return a newest-to-oldest list of distributions for `project_name`1062 1063        Uses case-insensitive `project_name` comparison, assuming all the1064        project's distributions use their project's name converted to all1065        lowercase as their key.1066 1067        """1068        distribution_key = project_name.lower()1069        return self._distmap.get(distribution_key, [])1070 1071    def add(self, dist):1072        """Add `dist` if we ``can_add()`` it and it has not already been added"""1073        if self.can_add(dist) and dist.has_version():1074            dists = self._distmap.setdefault(dist.key, [])1075            if dist not in dists:1076                dists.append(dist)1077                dists.sort(key=operator.attrgetter('hashcmp'), reverse=True)1078 1079    def best_match(self, req, working_set, installer=None, replace_conflicting=False):1080        """Find distribution best matching `req` and usable on `working_set`1081 1082        This calls the ``find(req)`` method of the `working_set` to see if a1083        suitable distribution is already active.  (This may raise1084        ``VersionConflict`` if an unsuitable version of the project is already1085        active in the specified `working_set`.)  If a suitable distribution1086        isn't active, this method returns the newest distribution in the1087        environment that meets the ``Requirement`` in `req`.  If no suitable1088        distribution is found, and `installer` is supplied, then the result of1089        calling the environment's ``obtain(req, installer)`` method will be1090        returned.1091        """1092        try:1093            dist = working_set.find(req)1094        except VersionConflict:1095            if not replace_conflicting:1096                raise1097            dist = None1098        if dist is not None:1099            return dist1100        for dist in self[req.key]:1101            if dist in req:1102                return dist1103        # try to download/install1104        return self.obtain(req, installer)1105 1106    def obtain(self, requirement, installer=None):1107        """Obtain a distribution matching `requirement` (e.g. via download)1108 1109        Obtain a distro that matches requirement (e.g. via download).  In the1110        base ``Environment`` class, this routine just returns1111        ``installer(requirement)``, unless `installer` is None, in which case1112        None is returned instead.  This method is a hook that allows subclasses1113        to attempt other ways of obtaining a distribution before falling back1114        to the `installer` argument."""1115        return installer(requirement) if installer else None1116 1117    def __iter__(self):1118        """Yield the unique project names of the available distributions"""1119        for key in self._distmap.keys():1120            if self[key]:1121                yield key1122 1123    def __iadd__(self, other):1124        """In-place addition of a distribution or environment"""1125        if isinstance(other, Distribution):1126            self.add(other)1127        elif isinstance(other, Environment):1128            for project in other:1129                for dist in other[project]:1130                    self.add(dist)1131        else:1132            raise TypeError("Can't add %r to environment" % (other,))1133        return self1134 1135    def __add__(self, other):1136        """Add an environment or distribution to an environment"""1137        new = self.__class__([], platform=None, python=None)1138        for env in self, other:1139            new += env1140        return new1141 1142 1143# XXX backward compatibility1144AvailableDistributions = Environment1145 1146 1147class ExtractionError(RuntimeError):1148    """An error occurred extracting a resource1149 1150    The following attributes are available from instances of this exception:1151 1152    manager1153        The resource manager that raised this exception1154 1155    cache_path1156        The base directory for resource extraction1157 1158    original_error1159        The exception instance that caused extraction to fail1160    """1161 1162 1163class ResourceManager:1164    """Manage resource extraction and packages"""1165 1166    extraction_path = None1167 1168    def __init__(self):1169        self.cached_files = {}1170 1171    def resource_exists(self, package_or_requirement, resource_name):1172        """Does the named resource exist?"""1173        return get_provider(package_or_requirement).has_resource(resource_name)1174 1175    def resource_isdir(self, package_or_requirement, resource_name):1176        """Is the named resource an existing directory?"""1177        return get_provider(package_or_requirement).resource_isdir(resource_name)1178 1179    def resource_filename(self, package_or_requirement, resource_name):1180        """Return a true filesystem path for specified resource"""1181        return get_provider(package_or_requirement).get_resource_filename(1182            self, resource_name1183        )1184 1185    def resource_stream(self, package_or_requirement, resource_name):1186        """Return a readable file-like object for specified resource"""1187        return get_provider(package_or_requirement).get_resource_stream(1188            self, resource_name1189        )1190 1191    def resource_string(self, package_or_requirement, resource_name) -> bytes:1192        """Return specified resource as :obj:`bytes`"""1193        return get_provider(package_or_requirement).get_resource_string(1194            self, resource_name1195        )1196 1197    def resource_listdir(self, package_or_requirement, resource_name):1198        """List the contents of the named resource directory"""1199        return get_provider(package_or_requirement).resource_listdir(resource_name)1200 

Showing the first 1,200 of 3326 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai