~logan/ubuntu/raring/distribute/0.6.34

« back to all changes in this revision

Viewing changes to pkg_resources.py

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2012-08-29 11:43:26 UTC
  • mfrom: (1.1.7 upstream)
  • mto: (9.1.4 experimental)
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: package-import@ubuntu.com-20120829114326-yekl2s3dydkmdu26
Tags: upstream-0.6.28
ImportĀ upstreamĀ versionĀ 0.6.28

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
        mkdir(dirname, mode)
53
53
 
54
54
 
55
 
 
56
 
 
57
 
 
 
55
_state_vars = {}
 
56
 
 
57
def _declare_state(vartype, **kw):
 
58
    g = globals()
 
59
    for name, val in kw.iteritems():
 
60
        g[name] = val
 
61
        _state_vars[name] = vartype
 
62
 
 
63
def __getstate__():
 
64
    state = {}
 
65
    g = globals()
 
66
    for k, v in _state_vars.iteritems():
 
67
        state[k] = g['_sget_'+v](g[k])
 
68
    return state
 
69
 
 
70
def __setstate__(state):
 
71
    g = globals()
 
72
    for k, v in state.iteritems():
 
73
        g['_sset_'+_state_vars[k]](k, g[k], v)
 
74
    return state
 
75
 
 
76
def _sget_dict(val):
 
77
    return val.copy()
 
78
 
 
79
def _sset_dict(key, ob, state):
 
80
    ob.clear()
 
81
    ob.update(state)
 
82
 
 
83
def _sget_object(val):
 
84
    return val.__getstate__()
 
85
 
 
86
def _sset_object(key, ob, state):
 
87
    ob.__setstate__(state)
 
88
 
 
89
_sget_none = _sset_none = lambda *args: None
58
90
 
59
91
 
60
92
 
476
508
        """
477
509
        seen = {}
478
510
        for item in self.entries:
 
511
            if item not in self.entry_keys:
 
512
                # workaround a cache issue
 
513
                continue
 
514
 
479
515
            for key in self.entry_keys[item]:
480
516
                if key not in seen:
481
517
                    seen[key]=1
672
708
        for callback in self.callbacks:
673
709
            callback(dist)
674
710
 
675
 
 
676
 
 
677
 
 
678
 
 
679
 
 
680
 
 
 
711
    def __getstate__(self):
 
712
        return (self.entries[:], self.entry_keys.copy(), self.by_key.copy(),
 
713
                self.callbacks[:])
 
714
 
 
715
    def __setstate__(self, (entries, keys, by_key, callbacks)):
 
716
        self.entries = entries[:]
 
717
        self.entry_keys = keys.copy()
 
718
        self.by_key = by_key.copy()
 
719
        self.callbacks = callbacks[:]
681
720
 
682
721
 
683
722
 
1286
1325
 
1287
1326
register_loader_type(type(None), DefaultProvider)
1288
1327
 
 
1328
try:
 
1329
    # CPython >=3.3
 
1330
    import _frozen_importlib
 
1331
except ImportError:
 
1332
    pass
 
1333
else:
 
1334
    register_loader_type(_frozen_importlib.SourceFileLoader, DefaultProvider)
 
1335
 
1289
1336
 
1290
1337
class EmptyProvider(NullProvider):
1291
1338
    """Provider that returns nothing for all requests"""
1638
1685
 
1639
1686
 
1640
1687
 
1641
 
_distribution_finders = {}
 
1688
_declare_state('dict', _distribution_finders = {})
1642
1689
 
1643
1690
def register_finder(importer_type, distribution_finder):
1644
1691
    """Register `distribution_finder` to find distributions in sys.path items
1699
1746
            # scan for .egg and .egg-info in directory
1700
1747
            for entry in os.listdir(path_item):
1701
1748
                lower = entry.lower()
1702
 
                if lower.endswith('.egg-info'):
 
1749
                if lower.endswith('.egg-info') or lower.endswith('.dist-info'):
1703
1750
                    fullpath = os.path.join(path_item, entry)
1704
1751
                    if os.path.isdir(fullpath):
1705
1752
                        # egg-info directory, allow getting metadata
1720
1767
                        break
1721
1768
register_finder(ImpWrapper,find_on_path)
1722
1769
 
1723
 
_namespace_handlers = {}
1724
 
_namespace_packages = {}
 
1770
try:
 
1771
    # CPython >=3.3
 
1772
    import _frozen_importlib
 
1773
except ImportError:
 
1774
    pass
 
1775
else:
 
1776
    register_finder(_frozen_importlib.FileFinder, find_on_path)
 
1777
 
 
1778
_declare_state('dict', _namespace_handlers={})
 
1779
_declare_state('dict', _namespace_packages={})
 
1780
 
1725
1781
 
1726
1782
def register_namespace_handler(importer_type, namespace_handler):
1727
1783
    """Register `namespace_handler` to declare namespace packages
1773
1829
        if '.' in packageName:
1774
1830
            parent = '.'.join(packageName.split('.')[:-1])
1775
1831
            declare_namespace(parent)
1776
 
            __import__(parent)
 
1832
            if parent not in _namespace_packages:
 
1833
                __import__(parent)
1777
1834
            try:
1778
1835
                path = sys.modules[parent].__path__
1779
1836
            except AttributeError:
1817
1874
register_namespace_handler(ImpWrapper,file_ns_handler)
1818
1875
register_namespace_handler(zipimport.zipimporter,file_ns_handler)
1819
1876
 
 
1877
try:
 
1878
    # CPython >=3.3
 
1879
    import _frozen_importlib
 
1880
except ImportError:
 
1881
    pass
 
1882
else:
 
1883
    register_namespace_handler(_frozen_importlib.FileFinder, file_ns_handler)
 
1884
 
1820
1885
 
1821
1886
def null_ns_handler(importer, path_item, packageName, module):
1822
1887
    return None
1875
1940
def _parse_version_parts(s):
1876
1941
    for part in component_re.split(s):
1877
1942
        part = replace(part,part)
1878
 
        if not part or part=='.':
 
1943
        if part in ['', '.']:
1879
1944
            continue
1880
1945
        if part[:1] in '0123456789':
1881
1946
            yield part.zfill(8)    # pad for numeric comparison
1918
1983
    parts = []
1919
1984
    for part in _parse_version_parts(s.lower()):
1920
1985
        if part.startswith('*'):
1921
 
            if part<'*final':   # remove '-' before a prerelease tag
1922
 
                while parts and parts[-1]=='*final-': parts.pop()
1923
1986
            # remove trailing zeros from each series of numeric parts
1924
1987
            while parts and parts[-1]=='00000000':
1925
1988
                parts.pop()
2056
2119
 
2057
2120
class Distribution(object):
2058
2121
    """Wrap an actual or potential sys.path entry w/metadata"""
 
2122
    PKG_INFO = 'PKG-INFO'
 
2123
    
2059
2124
    def __init__(self,
2060
2125
        location=None, metadata=None, project_name=None, version=None,
2061
2126
        py_version=PY_MAJOR, platform=None, precedence = EGG_DIST
2073
2138
    def from_location(cls,location,basename,metadata=None,**kw):
2074
2139
        project_name, version, py_version, platform = [None]*4
2075
2140
        basename, ext = os.path.splitext(basename)
2076
 
        if ext.lower() in (".egg",".egg-info"):
 
2141
        if ext.lower() in _distributionImpl:
 
2142
            # .dist-info gets much metadata differently
2077
2143
            match = EGG_NAME(basename)
2078
2144
            if match:
2079
2145
                project_name, version, py_version, platform = match.group(
2080
2146
                    'name','ver','pyver','plat'
2081
2147
                )
 
2148
            cls = _distributionImpl[ext.lower()]
2082
2149
        return cls(
2083
2150
            location, metadata, project_name=project_name, version=version,
2084
2151
            py_version=py_version, platform=platform, **kw
2141
2208
        try:
2142
2209
            return self._version
2143
2210
        except AttributeError:
2144
 
            for line in self._get_metadata('PKG-INFO'):
 
2211
            for line in self._get_metadata(self.PKG_INFO):
2145
2212
                if line.lower().startswith('version:'):
2146
2213
                    self._version = safe_version(line.split(':',1)[1].strip())
2147
2214
                    return self._version
2148
2215
            else:
2149
2216
                raise ValueError(
2150
 
                    "Missing 'Version:' header and/or PKG-INFO file", self
 
2217
                    "Missing 'Version:' header and/or %s file" % self.PKG_INFO, self
2151
2218
                )
2152
2219
    version = property(version)
2153
2220
 
2378
2445
    extras = property(extras)
2379
2446
 
2380
2447
 
 
2448
class DistInfoDistribution(Distribution):
 
2449
    """Wrap an actual or potential sys.path entry w/metadata, .dist-info style"""
 
2450
    PKG_INFO = 'METADATA'
 
2451
    EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])")
 
2452
 
 
2453
    @property
 
2454
    def _parsed_pkg_info(self):
 
2455
        """Parse and cache metadata"""
 
2456
        try:
 
2457
            return self._pkg_info
 
2458
        except AttributeError:
 
2459
            from email.parser import Parser
 
2460
            self._pkg_info = Parser().parsestr(self.get_metadata(self.PKG_INFO))
 
2461
            return self._pkg_info
 
2462
    
 
2463
    @property
 
2464
    def _dep_map(self):
 
2465
        try:
 
2466
            return self.__dep_map
 
2467
        except AttributeError:
 
2468
            self.__dep_map = self._compute_dependencies()
 
2469
            return self.__dep_map
 
2470
 
 
2471
    def _preparse_requirement(self, requires_dist):
 
2472
        """Convert 'Foobar (1); baz' to ('Foobar ==1', 'baz')
 
2473
        Split environment marker, add == prefix to version specifiers as 
 
2474
        necessary, and remove parenthesis.
 
2475
        """
 
2476
        parts = requires_dist.split(';', 1) + ['']
 
2477
        distvers = parts[0].strip()
 
2478
        mark = parts[1].strip()
 
2479
        distvers = re.sub(self.EQEQ, r"\1==\2\3", distvers)
 
2480
        distvers = distvers.replace('(', '').replace(')', '')
 
2481
        return (distvers, mark)
 
2482
            
 
2483
    def _compute_dependencies(self):
 
2484
        """Recompute this distribution's dependencies."""
 
2485
        def dummy_marker(marker):
 
2486
            def marker_fn(environment=None, override=None):
 
2487
                return True
 
2488
            marker_fn.__doc__ = marker
 
2489
            return marker_fn
 
2490
        try:
 
2491
            from markerlib import as_function
 
2492
        except ImportError:
 
2493
            as_function = dummy_marker
 
2494
        dm = self.__dep_map = {None: []}
 
2495
 
 
2496
        reqs = []
 
2497
        # Including any condition expressions
 
2498
        for req in self._parsed_pkg_info.get_all('Requires-Dist') or []:
 
2499
            distvers, mark = self._preparse_requirement(req)
 
2500
            parsed = parse_requirements(distvers).next()
 
2501
            parsed.marker_fn = as_function(mark)
 
2502
            reqs.append(parsed)
 
2503
            
 
2504
        def reqs_for_extra(extra):
 
2505
            for req in reqs:
 
2506
                if req.marker_fn(override={'extra':extra}):
 
2507
                    yield req
 
2508
 
 
2509
        common = set(reqs_for_extra(None))
 
2510
        dm[None].extend(common)
 
2511
            
 
2512
        for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []:
 
2513
            extra = safe_extra(extra.strip())
 
2514
            dm[extra] = list(set(reqs_for_extra(extra)) - common)
 
2515
 
 
2516
        return dm
 
2517
    
 
2518
 
 
2519
_distributionImpl = {'.egg': Distribution,
 
2520
                     '.egg-info': Distribution,
 
2521
                     '.dist-info': DistInfoDistribution }
 
2522
 
 
2523
 
2381
2524
def issue_warning(*args,**kw):
2382
2525
    level = 1
2383
2526
    g = globals()
2650
2793
        os.open = old_open  # and then put it back
2651
2794
 
2652
2795
 
2653
 
# Set up global resource manager
 
2796
# Set up global resource manager (deliberately not state-saved)
2654
2797
_manager = ResourceManager()
2655
2798
def _initialize(g):
2656
2799
    for name in dir(_manager):
2659
2802
_initialize(globals())
2660
2803
 
2661
2804
# Prepare the master working set and make the ``require()`` API available
2662
 
working_set = WorkingSet()
 
2805
_declare_state('object', working_set = WorkingSet())
 
2806
 
2663
2807
try:
2664
2808
    # Does the main program list any requirements?
2665
2809
    from __main__ import __requires__