Project

General

Profile

Statistics
| Branch: | Revision:

root / env / lib / python2.7 / site-packages / distribute-0.6.19-py2.7.egg / setuptools / depends.py @ 1a305335

History | View | Annotate | Download (6.06 KB)

1 1a305335 officers
from __future__ import generators
2
import sys, imp, marshal
3
from imp import PKG_DIRECTORY, PY_COMPILED, PY_SOURCE, PY_FROZEN
4
from distutils.version import StrictVersion, LooseVersion
5
6
__all__ = [
7
    'Require', 'find_module', 'get_module_constant', 'extract_constant'
8
]
9
10
class Require:
11
    """A prerequisite to building or installing a distribution"""
12
13
    def __init__(self,name,requested_version,module,homepage='',
14
        attribute=None,format=None
15
    ):
16
17
        if format is None and requested_version is not None:
18
            format = StrictVersion
19
20
        if format is not None:
21
            requested_version = format(requested_version)
22
            if attribute is None:
23
                attribute = '__version__'
24
25
        self.__dict__.update(locals())
26
        del self.self
27
28
29
    def full_name(self):
30
        """Return full package/distribution name, w/version"""
31
        if self.requested_version is not None:
32
            return '%s-%s' % (self.name,self.requested_version)
33
        return self.name
34
35
36
    def version_ok(self,version):
37
        """Is 'version' sufficiently up-to-date?"""
38
        return self.attribute is None or self.format is None or \
39
            str(version)<>"unknown" and version >= self.requested_version
40
41
42
    def get_version(self, paths=None, default="unknown"):
43
44
        """Get version number of installed module, 'None', or 'default'
45

46
        Search 'paths' for module.  If not found, return 'None'.  If found,
47
        return the extracted version attribute, or 'default' if no version
48
        attribute was specified, or the value cannot be determined without
49
        importing the module.  The version is formatted according to the
50
        requirement's version format (if any), unless it is 'None' or the
51
        supplied 'default'.
52
        """
53
54
        if self.attribute is None:
55
            try:
56
                f,p,i = find_module(self.module,paths)
57
                if f: f.close()
58
                return default
59
            except ImportError:
60
                return None
61
62
        v = get_module_constant(self.module,self.attribute,default,paths)
63
64
        if v is not None and v is not default and self.format is not None:
65
            return self.format(v)
66
67
        return v
68
69
70
    def is_present(self,paths=None):
71
        """Return true if dependency is present on 'paths'"""
72
        return self.get_version(paths) is not None
73
74
75
    def is_current(self,paths=None):
76
        """Return true if dependency is present and up-to-date on 'paths'"""
77
        version = self.get_version(paths)
78
        if version is None:
79
            return False
80
        return self.version_ok(version)
81
82
83
def _iter_code(code):
84
85
    """Yield '(op,arg)' pair for each operation in code object 'code'"""
86
87
    from array import array
88
    from dis import HAVE_ARGUMENT, EXTENDED_ARG
89
90
    bytes = array('b',code.co_code)
91
    eof = len(code.co_code)
92
93
    ptr = 0
94
    extended_arg = 0
95
96
    while ptr<eof:
97
98
        op = bytes[ptr]
99
100
        if op>=HAVE_ARGUMENT:
101
102
            arg = bytes[ptr+1] + bytes[ptr+2]*256 + extended_arg
103
            ptr += 3
104
105
            if op==EXTENDED_ARG:
106
                extended_arg = arg * 65536L
107
                continue
108
109
        else:
110
            arg = None
111
            ptr += 1
112
113
        yield op,arg
114
115
116
117
118
119
120
121
122
123
124
def find_module(module, paths=None):
125
    """Just like 'imp.find_module()', but with package support"""
126
127
    parts = module.split('.')
128
129
    while parts:
130
        part = parts.pop(0)
131
        f, path, (suffix,mode,kind) = info = imp.find_module(part, paths)
132
133
        if kind==PKG_DIRECTORY:
134
            parts = parts or ['__init__']
135
            paths = [path]
136
137
        elif parts:
138
            raise ImportError("Can't find %r in %s" % (parts,module))
139
140
    return info
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def get_module_constant(module, symbol, default=-1, paths=None):
166
167
    """Find 'module' by searching 'paths', and extract 'symbol'
168

169
    Return 'None' if 'module' does not exist on 'paths', or it does not define
170
    'symbol'.  If the module defines 'symbol' as a constant, return the
171
    constant.  Otherwise, return 'default'."""
172
173
    try:
174
        f, path, (suffix,mode,kind) = find_module(module,paths)
175
    except ImportError:
176
        # Module doesn't exist
177
        return None
178
179
    try:
180
        if kind==PY_COMPILED:
181
            f.read(8)   # skip magic & date
182
            code = marshal.load(f)
183
        elif kind==PY_FROZEN:
184
            code = imp.get_frozen_object(module)
185
        elif kind==PY_SOURCE:
186
            code = compile(f.read(), path, 'exec')
187
        else:
188
            # Not something we can parse; we'll have to import it.  :(
189
            if module not in sys.modules:
190
                imp.load_module(module,f,path,(suffix,mode,kind))
191
            return getattr(sys.modules[module],symbol,None)
192
193
    finally:
194
        if f:
195
            f.close()
196
197
    return extract_constant(code,symbol,default)
198
199
200
201
202
203
204
205
206
def extract_constant(code,symbol,default=-1):
207
    """Extract the constant value of 'symbol' from 'code'
208

209
    If the name 'symbol' is bound to a constant value by the Python code
210
    object 'code', return that value.  If 'symbol' is bound to an expression,
211
    return 'default'.  Otherwise, return 'None'.
212

213
    Return value is based on the first assignment to 'symbol'.  'symbol' must
214
    be a global, or at least a non-"fast" local in the code block.  That is,
215
    only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol'
216
    must be present in 'code.co_names'.
217
    """
218
219
    if symbol not in code.co_names:
220
        # name's not there, can't possibly be an assigment
221
        return None
222
223
    name_idx = list(code.co_names).index(symbol)
224
225
    STORE_NAME = 90
226
    STORE_GLOBAL = 97
227
    LOAD_CONST = 100
228
229
    const = default
230
231
    for op, arg in _iter_code(code):
232
233
        if op==LOAD_CONST:
234
            const = code.co_consts[arg]
235
        elif arg==name_idx and (op==STORE_NAME or op==STORE_GLOBAL):
236
            return const
237
        else:
238
            const = default
239
            
240
if sys.platform.startswith('java') or sys.platform == 'cli':
241
    # XXX it'd be better to test assertions about bytecode instead...
242
    del extract_constant, get_module_constant
243
    __all__.remove('extract_constant')
244
    __all__.remove('get_module_constant')
245