comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/setuptools/depends.py @ 68:5028fdace37b

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