comparison env/lib/python3.9/site-packages/setuptools/depends.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 import sys
2 import marshal
3 import contextlib
4 import dis
5 from distutils.version import StrictVersion
6
7 from ._imp import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE
8 from . import _imp
9
10
11 __all__ = [
12 'Require', 'find_module', 'get_module_constant', 'extract_constant'
13 ]
14
15
16 class Require:
17 """A prerequisite to building or installing a distribution"""
18
19 def __init__(
20 self, name, requested_version, module, homepage='',
21 attribute=None, format=None):
22
23 if format is None and requested_version is not None:
24 format = StrictVersion
25
26 if format is not None:
27 requested_version = format(requested_version)
28 if attribute is None:
29 attribute = '__version__'
30
31 self.__dict__.update(locals())
32 del self.self
33
34 def full_name(self):
35 """Return full package/distribution name, w/version"""
36 if self.requested_version is not None:
37 return '%s-%s' % (self.name, self.requested_version)
38 return self.name
39
40 def version_ok(self, version):
41 """Is 'version' sufficiently up-to-date?"""
42 return self.attribute is None or self.format is None or \
43 str(version) != "unknown" and version >= self.requested_version
44
45 def get_version(self, paths=None, default="unknown"):
46 """Get version number of installed module, 'None', or 'default'
47
48 Search 'paths' for module. If not found, return 'None'. If found,
49 return the extracted version attribute, or 'default' if no version
50 attribute was specified, or the value cannot be determined without
51 importing the module. The version is formatted according to the
52 requirement's version format (if any), unless it is 'None' or the
53 supplied 'default'.
54 """
55
56 if self.attribute is None:
57 try:
58 f, p, i = find_module(self.module, paths)
59 if f:
60 f.close()
61 return default
62 except ImportError:
63 return None
64
65 v = get_module_constant(self.module, self.attribute, default, paths)
66
67 if v is not None and v is not default and self.format is not None:
68 return self.format(v)
69
70 return v
71
72 def is_present(self, paths=None):
73 """Return true if dependency is present on 'paths'"""
74 return self.get_version(paths) is not None
75
76 def is_current(self, paths=None):
77 """Return true if dependency is present and up-to-date on 'paths'"""
78 version = self.get_version(paths)
79 if version is None:
80 return False
81 return self.version_ok(version)
82
83
84 def maybe_close(f):
85 @contextlib.contextmanager
86 def empty():
87 yield
88 return
89 if not f:
90 return empty()
91
92 return contextlib.closing(f)
93
94
95 def get_module_constant(module, symbol, default=-1, paths=None):
96 """Find 'module' by searching 'paths', and extract 'symbol'
97
98 Return 'None' if 'module' does not exist on 'paths', or it does not define
99 'symbol'. If the module defines 'symbol' as a constant, return the
100 constant. Otherwise, return 'default'."""
101
102 try:
103 f, path, (suffix, mode, kind) = info = find_module(module, paths)
104 except ImportError:
105 # Module doesn't exist
106 return None
107
108 with maybe_close(f):
109 if kind == PY_COMPILED:
110 f.read(8) # skip magic & date
111 code = marshal.load(f)
112 elif kind == PY_FROZEN:
113 code = _imp.get_frozen_object(module, paths)
114 elif kind == PY_SOURCE:
115 code = compile(f.read(), path, 'exec')
116 else:
117 # Not something we can parse; we'll have to import it. :(
118 imported = _imp.get_module(module, paths, info)
119 return getattr(imported, symbol, None)
120
121 return extract_constant(code, symbol, default)
122
123
124 def extract_constant(code, symbol, default=-1):
125 """Extract the constant value of 'symbol' from 'code'
126
127 If the name 'symbol' is bound to a constant value by the Python code
128 object 'code', return that value. If 'symbol' is bound to an expression,
129 return 'default'. Otherwise, return 'None'.
130
131 Return value is based on the first assignment to 'symbol'. 'symbol' must
132 be a global, or at least a non-"fast" local in the code block. That is,
133 only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol'
134 must be present in 'code.co_names'.
135 """
136 if symbol not in code.co_names:
137 # name's not there, can't possibly be an assignment
138 return None
139
140 name_idx = list(code.co_names).index(symbol)
141
142 STORE_NAME = 90
143 STORE_GLOBAL = 97
144 LOAD_CONST = 100
145
146 const = default
147
148 for byte_code in dis.Bytecode(code):
149 op = byte_code.opcode
150 arg = byte_code.arg
151
152 if op == LOAD_CONST:
153 const = code.co_consts[arg]
154 elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL):
155 return const
156 else:
157 const = default
158
159
160 def _update_globals():
161 """
162 Patch the globals to remove the objects not available on some platforms.
163
164 XXX it'd be better to test assertions about bytecode instead.
165 """
166
167 if not sys.platform.startswith('java') and sys.platform != 'cli':
168 return
169 incompatible = 'extract_constant', 'get_module_constant'
170 for name in incompatible:
171 del globals()[name]
172 __all__.remove(name)
173
174
175 _update_globals()