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