Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/hypothesis/internal/compat.py: 44%

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

127 statements  

1# This file is part of Hypothesis, which may be found at 

2# https://github.com/HypothesisWorks/hypothesis/ 

3# 

4# Copyright the Hypothesis Authors. 

5# Individual contributors are listed in AUTHORS.rst and the git log. 

6# 

7# This Source Code Form is subject to the terms of the Mozilla Public License, 

8# v. 2.0. If a copy of the MPL was not distributed with this file, You can 

9# obtain one at https://mozilla.org/MPL/2.0/. 

10 

11import codecs 

12import copy 

13import dataclasses 

14import inspect 

15import platform 

16import sys 

17import sysconfig 

18import typing 

19from functools import partial 

20from typing import Any, ForwardRef, List, Optional, TypedDict as TypedDict, get_args 

21 

22try: 

23 BaseExceptionGroup = BaseExceptionGroup 

24 ExceptionGroup = ExceptionGroup # pragma: no cover 

25except NameError: 

26 from exceptiongroup import ( 

27 BaseExceptionGroup as BaseExceptionGroup, 

28 ExceptionGroup as ExceptionGroup, 

29 ) 

30if typing.TYPE_CHECKING: # pragma: no cover 

31 from typing_extensions import ( 

32 Concatenate as Concatenate, 

33 NotRequired as NotRequired, 

34 ParamSpec as ParamSpec, 

35 TypeAlias as TypeAlias, 

36 TypedDict as TypedDict, 

37 override as override, 

38 ) 

39else: 

40 # In order to use NotRequired, we need the version of TypedDict included in Python 3.11+. 

41 if sys.version_info[:2] >= (3, 11): 

42 from typing import NotRequired as NotRequired, TypedDict as TypedDict 

43 else: 

44 try: 

45 from typing_extensions import ( 

46 NotRequired as NotRequired, 

47 TypedDict as TypedDict, 

48 ) 

49 except ImportError: 

50 # We can use the old TypedDict from Python 3.8+ at runtime. 

51 class NotRequired: 

52 """A runtime placeholder for the NotRequired type, which is not available in Python <3.11.""" 

53 

54 def __class_getitem__(cls, item): 

55 return cls 

56 

57 try: 

58 from typing import ( 

59 Concatenate as Concatenate, 

60 ParamSpec as ParamSpec, 

61 TypeAlias as TypeAlias, 

62 override as override, 

63 ) 

64 except ImportError: 

65 try: 

66 from typing_extensions import ( 

67 Concatenate as Concatenate, 

68 ParamSpec as ParamSpec, 

69 TypeAlias as TypeAlias, 

70 override as override, 

71 ) 

72 except ImportError: 

73 Concatenate, ParamSpec = None, None 

74 TypeAlias = None 

75 override = lambda f: f 

76 

77 

78PYPY = platform.python_implementation() == "PyPy" 

79GRAALPY = platform.python_implementation() == "GraalVM" 

80WINDOWS = platform.system() == "Windows" 

81# First defined in CPython 3.13, defaults to False 

82FREE_THREADED_CPYTHON = bool(sysconfig.get_config_var("Py_GIL_DISABLED")) 

83 

84 

85def add_note(exc, note): 

86 try: 

87 exc.add_note(note) 

88 except AttributeError: 

89 if not hasattr(exc, "__notes__"): 

90 try: 

91 exc.__notes__ = [] 

92 except AttributeError: 

93 return # give up, might be e.g. a frozen dataclass 

94 exc.__notes__.append(note) 

95 

96 

97def escape_unicode_characters(s: str) -> str: 

98 return codecs.encode(s, "unicode_escape").decode("ascii") 

99 

100 

101def int_from_bytes(data: typing.Union[bytes, bytearray]) -> int: 

102 return int.from_bytes(data, "big") 

103 

104 

105def int_to_bytes(i: int, size: int) -> bytes: 

106 return i.to_bytes(size, "big") 

107 

108 

109def int_to_byte(i: int) -> bytes: 

110 return bytes([i]) 

111 

112 

113def is_typed_named_tuple(cls): 

114 """Return True if cls is probably a subtype of `typing.NamedTuple`. 

115 

116 Unfortunately types created with `class T(NamedTuple):` actually 

117 subclass `tuple` directly rather than NamedTuple. This is annoying, 

118 and means we just have to hope that nobody defines a different tuple 

119 subclass with similar attributes. 

120 """ 

121 return ( 

122 issubclass(cls, tuple) 

123 and hasattr(cls, "_fields") 

124 and (hasattr(cls, "_field_types") or hasattr(cls, "__annotations__")) 

125 ) 

126 

127 

128def _hint_and_args(x): 

129 return (x, *get_args(x)) 

130 

131 

132def get_type_hints(thing): 

133 """Like the typing version, but tries harder and never errors. 

134 

135 Tries harder: if the thing to inspect is a class but typing.get_type_hints 

136 raises an error or returns no hints, then this function will try calling it 

137 on the __init__ method. This second step often helps with user-defined 

138 classes on older versions of Python. The third step we take is trying 

139 to fetch types from the __signature__ property. 

140 They override any other ones we found earlier. 

141 

142 Never errors: instead of raising TypeError for uninspectable objects, or 

143 NameError for unresolvable forward references, just return an empty dict. 

144 """ 

145 if isinstance(thing, partial): 

146 from hypothesis.internal.reflection import get_signature 

147 

148 bound = set(get_signature(thing.func).parameters).difference( 

149 get_signature(thing).parameters 

150 ) 

151 return {k: v for k, v in get_type_hints(thing.func).items() if k not in bound} 

152 

153 kwargs = {} if sys.version_info[:2] < (3, 9) else {"include_extras": True} 

154 

155 try: 

156 hints = typing.get_type_hints(thing, **kwargs) 

157 except (AttributeError, TypeError, NameError): # pragma: no cover 

158 hints = {} 

159 

160 if inspect.isclass(thing): 

161 try: 

162 hints.update(typing.get_type_hints(thing.__init__, **kwargs)) 

163 except (TypeError, NameError, AttributeError): 

164 pass 

165 

166 try: 

167 if hasattr(thing, "__signature__"): 

168 # It is possible for the signature and annotations attributes to 

169 # differ on an object due to renamed arguments. 

170 from hypothesis.internal.reflection import get_signature 

171 from hypothesis.strategies._internal.types import is_a_type 

172 

173 vkinds = (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD) 

174 for p in get_signature(thing).parameters.values(): 

175 if ( 

176 p.kind not in vkinds 

177 and is_a_type(p.annotation) 

178 and p.annotation is not p.empty 

179 ): 

180 p_hint = p.annotation 

181 

182 # Defer to `get_type_hints` if signature annotation is, or 

183 # contains, a forward reference that is otherwise resolved. 

184 if any( 

185 isinstance(sig_hint, ForwardRef) 

186 and not isinstance(hint, ForwardRef) 

187 for sig_hint, hint in zip( 

188 _hint_and_args(p.annotation), 

189 _hint_and_args(hints.get(p.name, Any)), 

190 ) 

191 ): 

192 p_hint = hints[p.name] 

193 if p.default is None: 

194 hints[p.name] = typing.Optional[p_hint] 

195 else: 

196 hints[p.name] = p_hint 

197 except (AttributeError, TypeError, NameError): # pragma: no cover 

198 pass 

199 

200 return hints 

201 

202 

203# Under Python 2, math.floor and math.ceil returned floats, which cannot 

204# represent large integers - eg `float(2**53) == float(2**53 + 1)`. 

205# We therefore implement them entirely in (long) integer operations. 

206# We still use the same trick on Python 3, because Numpy values and other 

207# custom __floor__ or __ceil__ methods may convert via floats. 

208# See issue #1667, Numpy issue 9068. 

209def floor(x): 

210 y = int(x) 

211 if y != x and x < 0: 

212 return y - 1 

213 return y 

214 

215 

216def ceil(x): 

217 y = int(x) 

218 if y != x and x > 0: 

219 return y + 1 

220 return y 

221 

222 

223def extract_bits(x: int, /, width: Optional[int] = None) -> List[int]: 

224 assert x >= 0 

225 result = [] 

226 while x: 

227 result.append(x & 1) 

228 x >>= 1 

229 if width is not None: 

230 result = (result + [0] * width)[:width] 

231 result.reverse() 

232 return result 

233 

234 

235# int.bit_count was added sometime around python 3.9 

236try: 

237 bit_count = int.bit_count 

238except AttributeError: # pragma: no cover 

239 bit_count = lambda self: sum(extract_bits(abs(self))) 

240 

241 

242def bad_django_TestCase(runner): 

243 if runner is None or "django.test" not in sys.modules: 

244 return False 

245 else: # pragma: no cover 

246 if not isinstance(runner, sys.modules["django.test"].TransactionTestCase): 

247 return False 

248 

249 from hypothesis.extra.django._impl import HypothesisTestCase 

250 

251 return not isinstance(runner, HypothesisTestCase) 

252 

253 

254# see issue #3812 

255if sys.version_info[:2] < (3, 12): 

256 

257 def dataclass_asdict(obj, *, dict_factory=dict): 

258 """ 

259 A vendored variant of dataclasses.asdict. Includes the bugfix for 

260 defaultdicts (cpython/32056) for all versions. See also issues/3812. 

261 

262 This should be removed whenever we drop support for 3.11. We can use the 

263 standard dataclasses.asdict after that point. 

264 """ 

265 if not dataclasses._is_dataclass_instance(obj): # pragma: no cover 

266 raise TypeError("asdict() should be called on dataclass instances") 

267 return _asdict_inner(obj, dict_factory) 

268 

269else: # pragma: no cover 

270 dataclass_asdict = dataclasses.asdict 

271 

272 

273def _asdict_inner(obj, dict_factory): 

274 if dataclasses._is_dataclass_instance(obj): 

275 return dict_factory( 

276 (f.name, _asdict_inner(getattr(obj, f.name), dict_factory)) 

277 for f in dataclasses.fields(obj) 

278 ) 

279 elif isinstance(obj, tuple) and hasattr(obj, "_fields"): 

280 return type(obj)(*[_asdict_inner(v, dict_factory) for v in obj]) 

281 elif isinstance(obj, (list, tuple)): 

282 return type(obj)(_asdict_inner(v, dict_factory) for v in obj) 

283 elif isinstance(obj, dict): 

284 if hasattr(type(obj), "default_factory"): 

285 result = type(obj)(obj.default_factory) 

286 for k, v in obj.items(): 

287 result[_asdict_inner(k, dict_factory)] = _asdict_inner(v, dict_factory) 

288 return result 

289 return type(obj)( 

290 (_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory)) 

291 for k, v in obj.items() 

292 ) 

293 else: 

294 return copy.deepcopy(obj)