Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/setuptools/depends.py: 24%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

92 statements  

1import sys 

2import marshal 

3import contextlib 

4from distutils.version import StrictVersion 

5 

6from .py33compat import Bytecode 

7 

8from .py27compat import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE 

9from . import py27compat 

10 

11 

12__all__ = [ 

13 'Require', 'find_module', 'get_module_constant', 'extract_constant' 

14] 

15 

16 

17class Require: 

18 """A prerequisite to building or installing a distribution""" 

19 

20 def __init__( 

21 self, name, requested_version, module, homepage='', 

22 attribute=None, format=None): 

23 

24 if format is None and requested_version is not None: 

25 format = StrictVersion 

26 

27 if format is not None: 

28 requested_version = format(requested_version) 

29 if attribute is None: 

30 attribute = '__version__' 

31 

32 self.__dict__.update(locals()) 

33 del self.self 

34 

35 def full_name(self): 

36 """Return full package/distribution name, w/version""" 

37 if self.requested_version is not None: 

38 return '%s-%s' % (self.name, self.requested_version) 

39 return self.name 

40 

41 def version_ok(self, version): 

42 """Is 'version' sufficiently up-to-date?""" 

43 return self.attribute is None or self.format is None or \ 

44 str(version) != "unknown" and version >= self.requested_version 

45 

46 def get_version(self, paths=None, default="unknown"): 

47 """Get version number of installed module, 'None', or 'default' 

48 

49 Search 'paths' for module. If not found, return 'None'. If found, 

50 return the extracted version attribute, or 'default' if no version 

51 attribute was specified, or the value cannot be determined without 

52 importing the module. The version is formatted according to the 

53 requirement's version format (if any), unless it is 'None' or the 

54 supplied 'default'. 

55 """ 

56 

57 if self.attribute is None: 

58 try: 

59 f, p, i = find_module(self.module, paths) 

60 if f: 

61 f.close() 

62 return default 

63 except ImportError: 

64 return None 

65 

66 v = get_module_constant(self.module, self.attribute, default, paths) 

67 

68 if v is not None and v is not default and self.format is not None: 

69 return self.format(v) 

70 

71 return v 

72 

73 def is_present(self, paths=None): 

74 """Return true if dependency is present on 'paths'""" 

75 return self.get_version(paths) is not None 

76 

77 def is_current(self, paths=None): 

78 """Return true if dependency is present and up-to-date on 'paths'""" 

79 version = self.get_version(paths) 

80 if version is None: 

81 return False 

82 return self.version_ok(version) 

83 

84 

85def maybe_close(f): 

86 @contextlib.contextmanager 

87 def empty(): 

88 yield 

89 return 

90 if not f: 

91 return empty() 

92 

93 return contextlib.closing(f) 

94 

95 

96def get_module_constant(module, symbol, default=-1, paths=None): 

97 """Find 'module' by searching 'paths', and extract 'symbol' 

98 

99 Return 'None' if 'module' does not exist on 'paths', or it does not define 

100 'symbol'. If the module defines 'symbol' as a constant, return the 

101 constant. Otherwise, return 'default'.""" 

102 

103 try: 

104 f, path, (suffix, mode, kind) = info = find_module(module, paths) 

105 except ImportError: 

106 # Module doesn't exist 

107 return None 

108 

109 with maybe_close(f): 

110 if kind == PY_COMPILED: 

111 f.read(8) # skip magic & date 

112 code = marshal.load(f) 

113 elif kind == PY_FROZEN: 

114 code = py27compat.get_frozen_object(module, paths) 

115 elif kind == PY_SOURCE: 

116 code = compile(f.read(), path, 'exec') 

117 else: 

118 # Not something we can parse; we'll have to import it. :( 

119 imported = py27compat.get_module(module, paths, info) 

120 return getattr(imported, symbol, None) 

121 

122 return extract_constant(code, symbol, default) 

123 

124 

125def extract_constant(code, symbol, default=-1): 

126 """Extract the constant value of 'symbol' from 'code' 

127 

128 If the name 'symbol' is bound to a constant value by the Python code 

129 object 'code', return that value. If 'symbol' is bound to an expression, 

130 return 'default'. Otherwise, return 'None'. 

131 

132 Return value is based on the first assignment to 'symbol'. 'symbol' must 

133 be a global, or at least a non-"fast" local in the code block. That is, 

134 only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol' 

135 must be present in 'code.co_names'. 

136 """ 

137 if symbol not in code.co_names: 

138 # name's not there, can't possibly be an assignment 

139 return None 

140 

141 name_idx = list(code.co_names).index(symbol) 

142 

143 STORE_NAME = 90 

144 STORE_GLOBAL = 97 

145 LOAD_CONST = 100 

146 

147 const = default 

148 

149 for byte_code in Bytecode(code): 

150 op = byte_code.opcode 

151 arg = byte_code.arg 

152 

153 if op == LOAD_CONST: 

154 const = code.co_consts[arg] 

155 elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL): 

156 return const 

157 else: 

158 const = default 

159 

160 

161def _update_globals(): 

162 """ 

163 Patch the globals to remove the objects not available on some platforms. 

164 

165 XXX it'd be better to test assertions about bytecode instead. 

166 """ 

167 

168 if not sys.platform.startswith('java') and sys.platform != 'cli': 

169 return 

170 incompatible = 'extract_constant', 'get_module_constant' 

171 for name in incompatible: 

172 del globals()[name] 

173 __all__.remove(name) 

174 

175 

176_update_globals()