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 |