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
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

    
246