diff options
Diffstat (limited to 'pkg_resources.py')
-rw-r--r-- | pkg_resources.py | 358 |
1 files changed, 72 insertions, 286 deletions
diff --git a/pkg_resources.py b/pkg_resources.py index 36a0e6ed..02976016 100644 --- a/pkg_resources.py +++ b/pkg_resources.py @@ -13,7 +13,13 @@ The package resource API is designed to work with normal filesystem packages, method. """ -import sys, os, time, re, imp, types, zipfile, zipimport +import sys +import os +import time +import re +import imp +import zipfile +import zipimport import warnings import stat try: @@ -122,8 +128,6 @@ def _sset_object(key, ob, state): _sget_none = _sset_none = lambda *args: None - - def get_supported_platform(): """Return this platform's maximum compatible version. @@ -137,7 +141,8 @@ def get_supported_platform(): If this condition occurs for any other platform with a version in its platform strings, this function should be extended accordingly. """ - plat = get_build_platform(); m = macosVersionString.match(plat) + plat = get_build_platform() + m = macosVersionString.match(plat) if m is not None and sys.platform == "darwin": try: plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3)) @@ -145,26 +150,6 @@ def get_supported_platform(): pass # not Mac OS X return plat - - - - - - - - - - - - - - - - - - - - __all__ = [ # Basic resource access and distribution/entry point discovery 'require', 'run_script', 'get_provider', 'get_distribution', @@ -206,6 +191,7 @@ __all__ = [ # Deprecated/backward compatibility only 'run_main', 'AvailableDistributions', ] + class ResolutionError(Exception): """Abstract base for dependency resolution errors""" def __repr__(self): @@ -222,7 +208,7 @@ class UnknownExtra(ResolutionError): _provider_factories = {} PY_MAJOR = sys.version[:3] -EGG_DIST = 3 +EGG_DIST = 3 BINARY_DIST = 2 SOURCE_DIST = 1 CHECKOUT_DIST = 0 @@ -299,11 +285,6 @@ darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)") get_platform = get_build_platform # XXX backward compat - - - - - def compatible_platforms(provided,required): """Can code for the `provided` platform run on the `required` platform? @@ -329,7 +310,7 @@ def compatible_platforms(provided,required): dversion = int(provDarwin.group(1)) macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2)) if dversion == 7 and macosversion >= "10.3" or \ - dversion == 8 and macosversion >= "10.4": + dversion == 8 and macosversion >= "10.4": #import warnings #warnings.warn("Mac eggs should be rebuilt to " @@ -340,11 +321,9 @@ def compatible_platforms(provided,required): # are they the same major version and machine type? if provMac.group(1) != reqMac.group(1) or \ - provMac.group(3) != reqMac.group(3): + provMac.group(3) != reqMac.group(3): return False - - # is the required OS major update >= the provided one? if int(provMac.group(2)) > int(reqMac.group(2)): return False @@ -410,14 +389,6 @@ class IMetadataProvider: """Execute the named script in the supplied namespace dictionary""" - - - - - - - - class IResourceProvider(IMetadataProvider): """An object that provides access to package resources""" @@ -446,19 +417,6 @@ class IResourceProvider(IMetadataProvider): """List of resource names in the directory (like ``os.listdir()``)""" - - - - - - - - - - - - - class WorkingSet(object): """A collection of active distributions on sys.path (or a similar list)""" @@ -475,7 +433,6 @@ class WorkingSet(object): for entry in entries: self.add_entry(entry) - def add_entry(self, entry): """Add a path item to ``.entries``, finding any distributions on it @@ -491,15 +448,10 @@ class WorkingSet(object): for dist in find_distributions(entry, True): self.add(dist, entry, False) - def __contains__(self,dist): """True if `dist` is the active distribution for its project""" return self.by_key.get(dist.key) == dist - - - - def find(self, req): """Find a distribution matching requirement `req` @@ -539,8 +491,6 @@ class WorkingSet(object): ns['__name__'] = name self.require(requires)[0].run_script(script_name, ns) - - def __iter__(self): """Yield distributions for non-duplicate projects in the working set @@ -633,9 +583,8 @@ class WorkingSet(object): return to_activate # return list of distros to activate - def find_plugins(self, - plugin_env, full_env=None, installer=None, fallback=True - ): + def find_plugins(self, plugin_env, full_env=None, installer=None, + fallback=True): """Find all activatable distributions in `plugin_env` Example usage:: @@ -712,10 +661,6 @@ class WorkingSet(object): return distributions, error_info - - - - def require(self, *requirements): """Ensure that distributions matching `requirements` are activated @@ -793,7 +738,7 @@ class Environment(object): """ return (self.python is None or dist.py_version is None or dist.py_version==self.python) \ - and compatible_platforms(dist.platform,self.platform) + and compatible_platforms(dist.platform,self.platform) def remove(self, dist): """Remove `dist` from the environment""" @@ -839,7 +784,6 @@ class Environment(object): if dist.key in self._cache: _sort_dists(self._cache[dist.key]) - def best_match(self, req, working_set, installer=None): """Find distribution best matching `req` and usable on `working_set` @@ -878,9 +822,6 @@ class Environment(object): for key in self._distmap.keys(): if self[key]: yield key - - - def __iadd__(self, other): """In-place addition of a distribution or environment""" if isinstance(other,Distribution): @@ -920,8 +861,6 @@ class ExtractionError(RuntimeError): """ - - class ResourceManager: """Manage resource extraction and packages""" extraction_path = None @@ -983,27 +922,13 @@ The Python egg cache directory is currently set to: Perhaps your account does not have write access to this directory? You can change the cache directory by setting the PYTHON_EGG_CACHE environment variable to point to an accessible directory. -""" % (old_exc, cache_path) +""" % (old_exc, cache_path) ) - err.manager = self - err.cache_path = cache_path + err.manager = self + err.cache_path = cache_path err.original_error = old_exc raise err - - - - - - - - - - - - - - def get_cache_path(self, archive_name, names=()): """Return absolute location in cache for `archive_name` and `names` @@ -1053,23 +978,6 @@ variable to point to an accessible directory. "PYTHON_EGG_CACHE environment variable)." % path) warnings.warn(msg, UserWarning) - - - - - - - - - - - - - - - - - def postprocess(self, tempname, filename): """Perform any platform-specific postprocessing of `tempname` @@ -1090,27 +998,6 @@ variable to point to an accessible directory. mode = ((os.stat(tempname).st_mode) | 0x16D) & 0xFFF # 0555, 07777 os.chmod(tempname, mode) - - - - - - - - - - - - - - - - - - - - - def set_extraction_path(self, path): """Set the base path where resources will be extracted to, if needed. @@ -1150,8 +1037,6 @@ variable to point to an accessible directory. """ # XXX - - def get_default_cache(): """Determine the default cache location @@ -1227,13 +1112,6 @@ def to_filename(name): """ return name.replace('-','_') - - - - - - - _marker_names = { 'os': ['name'], 'sys': ['platform'], 'platform': ['version','machine','python_implementation'], @@ -1267,12 +1145,28 @@ def _pyimp(): else: return 'CPython' +def normalize_exception(exc): + """ + Given a SyntaxError from a marker evaluation, normalize the error message: + - Remove indications of filename and line number. + - Replace platform-specific error messages with standard error messages. + """ + subs = { + 'unexpected EOF while parsing': 'invalid syntax', + 'parenthesis is never closed': 'invalid syntax', + } + exc.filename = None + exc.lineno = None + exc.msg = subs.get(exc.msg, exc.msg) + return exc + + def invalid_marker(text): """Validate text as a PEP 426 environment marker; return exception or False""" try: evaluate_marker(text) except SyntaxError: - return sys.exc_info()[1] + return normalize_exception(sys.exc_info()[1]) return False def evaluate_marker(text, extra=None, _ops={}): @@ -1289,7 +1183,9 @@ def evaluate_marker(text, extra=None, _ops={}): if not _ops: from token import NAME, STRING - import token, symbol, operator + import token + import symbol + import operator def and_test(nodelist): # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! @@ -1355,7 +1251,7 @@ def evaluate_marker(text, extra=None, _ops={}): if kind==STRING: s = nodelist[1] if s[:1] not in "'\"" or s.startswith('"""') or s.startswith("'''") \ - or '\\' in s: + or '\\' in s: raise SyntaxError( "Only plain strings allowed in environment markers") return s[1:-1] @@ -1434,7 +1330,6 @@ class NullProvider: def metadata_isdir(self,name): return self.egg_info and self._isdir(self._fn(self.egg_info,name)) - def resource_listdir(self,resource_name): return self._listdir(self._fn(self.module_path,resource_name)) @@ -1512,11 +1407,6 @@ class EggProvider(NullProvider): old = path path, base = os.path.split(path) - - - - - class DefaultProvider(EggProvider): """Provides access to package resources in the filesystem""" @@ -1549,9 +1439,9 @@ class EmptyProvider(NullProvider): """Provider that returns nothing for all requests""" _isdir = _has = lambda self,path: False - _get = lambda self,path: '' - _listdir = lambda self,path: [] - module_path = None + _get = lambda self,path: '' + _listdir = lambda self,path: [] + module_path = None def __init__(self): pass @@ -1752,28 +1642,6 @@ class ZipProvider(EggProvider): register_loader_type(zipimport.zipimporter, ZipProvider) - - - - - - - - - - - - - - - - - - - - - - class FileMetadata(EmptyProvider): """Metadata handler for standalone PKG-INFO files @@ -1804,20 +1672,6 @@ class FileMetadata(EmptyProvider): return yield_lines(self.get_metadata(name)) - - - - - - - - - - - - - - class PathMetadata(DefaultProvider): """Metadata provider for egg directories @@ -1898,8 +1752,6 @@ class ImpLoader: return mod - - def get_importer(path_item): """Retrieve a PEP 302 "importer" for the given path item @@ -1937,10 +1789,6 @@ else: del ImpLoader, ImpImporter - - - - _declare_state('dict', _distribution_finders = {}) def register_finder(importer_type, distribution_finder): @@ -2164,12 +2012,12 @@ def yield_lines(strs): LINE_END = re.compile(r"\s*(#.*)?$").match # whitespace and comment CONTINUE = re.compile(r"\s*\\\s*(#.*)?$").match # line continuation -DISTRO = re.compile(r"\s*((\w|[-.])+)").match # Distribution or extra -VERSION = re.compile(r"\s*(<=?|>=?|==|!=)\s*((\w|[-.])+)").match # ver. info -COMMA = re.compile(r"\s*,").match # comma between items +DISTRO = re.compile(r"\s*((\w|[-.])+)").match # Distribution or extra +VERSION = re.compile(r"\s*(<=?|>=?|==|!=)\s*((\w|[-.])+)").match # ver. info +COMMA = re.compile(r"\s*,").match # comma between items OBRACKET = re.compile(r"\s*\[").match CBRACKET = re.compile(r"\s*\]").match -MODULE = re.compile(r"\w+(\.\w+)*$").match +MODULE = re.compile(r"\w+(\.\w+)*$").match EGG_NAME = re.compile( r"(?P<name>[^-]+)" r"( -(?P<ver>[^-]+) (-py(?P<pyver>[^-]+) (-(?P<plat>.+))? )? )?", @@ -2271,8 +2119,6 @@ class EntryPoint(object): list(map(working_set.add, working_set.resolve(self.dist.requires(self.extras),env,installer))) - - #@classmethod def parse(cls, src, dist=None): """Parse a single entry point from string `src` @@ -2307,13 +2153,6 @@ class EntryPoint(object): parse = classmethod(parse) - - - - - - - #@classmethod def parse_group(cls, group, lines, dist=None): """Parse an entry point group""" @@ -2364,10 +2203,9 @@ class Distribution(object): """Wrap an actual or potential sys.path entry w/metadata""" PKG_INFO = 'PKG-INFO' - def __init__(self, - location=None, metadata=None, project_name=None, version=None, - py_version=PY_MAJOR, platform=None, precedence = EGG_DIST - ): + def __init__(self, location=None, metadata=None, project_name=None, + version=None, py_version=PY_MAJOR, platform=None, + precedence=EGG_DIST): self.project_name = safe_name(project_name or 'Unknown') if version is not None: self._version = safe_version(version) @@ -2395,7 +2233,6 @@ class Distribution(object): ) from_location = classmethod(from_location) - hashcmp = property( lambda self: ( getattr(self,'parsed_version',()), @@ -2461,9 +2298,6 @@ class Distribution(object): ) version = property(version) - - - #@property def _dep_map(self): try: @@ -2503,8 +2337,6 @@ class Distribution(object): for line in self.get_metadata_lines(name): yield line - - def activate(self,path=None): """Ensure distribution is importable on `path` (default=sys.path)""" if path is None: path = sys.path @@ -2513,7 +2345,6 @@ class Distribution(object): fixup_namespace_packages(self.location) list(map(declare_namespace, self._get_metadata('namespace_packages.txt'))) - def egg_name(self): """Return what this distribution's standard .egg filename should be""" filename = "%s-%s-py%s" % ( @@ -2543,9 +2374,6 @@ class Distribution(object): raise AttributeError(attr) return getattr(self._provider, attr) - - - #@classmethod def from_filename(cls,filename,metadata=None, **kw): return cls.from_location( @@ -2581,12 +2409,6 @@ class Distribution(object): """Return the EntryPoint object for `group`+`name`, or ``None``""" return self.get_entry_map(group).get(name) - - - - - - def insert_on(self, path, loc = None): """Insert self.location in path before its nearest parent directory""" @@ -2627,7 +2449,6 @@ class Distribution(object): return - def check_version_conflict(self): if self.key=='setuptools': return # ignore the inevitable setuptools self-conflicts :( @@ -2636,8 +2457,7 @@ class Distribution(object): loc = normalize_path(self.location) for modname in self._get_metadata('top_level.txt'): if (modname not in sys.modules or modname in nsp - or modname in _namespace_packages - ): + or modname in _namespace_packages): continue if modname in ('pkg_resources', 'setuptools', 'site'): continue @@ -2668,9 +2488,6 @@ class Distribution(object): kw.setdefault('metadata', self._provider) return self.__class__(**kw) - - - #@property def extras(self): return [dep for dep in self._dep_map if dep] @@ -2740,9 +2557,11 @@ class DistInfoDistribution(Distribution): return dm -_distributionImpl = {'.egg': Distribution, - '.egg-info': Distribution, - '.dist-info': DistInfoDistribution } +_distributionImpl = { + '.egg': Distribution, + '.egg-info': Distribution, + '.dist-info': DistInfoDistribution, + } def issue_warning(*args,**kw): @@ -2759,27 +2578,6 @@ def issue_warning(*args,**kw): warn(stacklevel = level+1, *args, **kw) - - - - - - - - - - - - - - - - - - - - - def parse_requirements(strs): """Yield ``Requirement`` objects for each specification in `strs` @@ -2796,7 +2594,8 @@ def parse_requirements(strs): while not TERMINATOR(line,p): if CONTINUE(line,p): try: - line = next(lines); p = 0 + line = next(lines) + p = 0 except StopIteration: raise ValueError( "\\ must not appear on the last nonblank line" @@ -2847,21 +2646,6 @@ def _sort_dists(dists): dists[::-1] = [d for hc,d in tmp] - - - - - - - - - - - - - - - class Requirement: def __init__(self, project_name, specs, extras): """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!""" @@ -2896,14 +2680,16 @@ class Requirement: compare = lambda a, b: (a > b) - (a < b) # -1, 0, 1 for parsed,trans,op,ver in self.index: action = trans[compare(item,parsed)] # Indexing: 0, 1, -1 - if action=='F': return False - elif action=='T': return True - elif action=='+': last = True + if action=='F': + return False + elif action=='T': + return True + elif action=='+': + last = True elif action=='-' or last is None: last = False if last is None: last = True # no rules encountered return last - def __hash__(self): return self.__hash @@ -2922,12 +2708,12 @@ class Requirement: state_machine = { # =>< - '<' : '--T', - '<=': 'T-T', - '>' : 'F+F', - '>=': 'T+F', - '==': 'T..', - '!=': 'F++', + '<': '--T', + '<=': 'T-T', + '>': 'F+F', + '>=': 'T+F', + '==': 'T..', + '!=': 'F++', } @@ -3025,5 +2811,5 @@ run_main = run_script # backward compatibility # all distributions added to the working set in the future (e.g. by # calling ``require()``) will get activated as well. add_activation_listener(lambda dist: dist.activate()) -working_set.entries=[]; list(map(working_set.add_entry,sys.path)) # match order - +working_set.entries=[] +list(map(working_set.add_entry,sys.path)) # match order |