Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/utils/functional.py: 66%

207 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1import copy 

2import itertools 

3import operator 

4from functools import total_ordering, wraps 

5 

6 

7class cached_property: 

8 """ 

9 Decorator that converts a method with a single self argument into a 

10 property cached on the instance. 

11 

12 A cached property can be made out of an existing method: 

13 (e.g. ``url = cached_property(get_absolute_url)``). 

14 The optional ``name`` argument is obsolete as of Python 3.6 and will be 

15 deprecated in Django 4.0 (#30127). 

16 """ 

17 

18 name = None 

19 

20 @staticmethod 

21 def func(instance): 

22 raise TypeError( 

23 "Cannot use cached_property instance without calling " 

24 "__set_name__() on it." 

25 ) 

26 

27 def __init__(self, func, name=None): 

28 self.real_func = func 

29 self.__doc__ = getattr(func, "__doc__") 

30 

31 def __set_name__(self, owner, name): 

32 if self.name is None: 32 ↛ 35line 32 didn't jump to line 35, because the condition on line 32 was never false

33 self.name = name 

34 self.func = self.real_func 

35 elif name != self.name: 

36 raise TypeError( 

37 "Cannot assign the same cached_property to two different names " 

38 "(%r and %r)." % (self.name, name) 

39 ) 

40 

41 def __get__(self, instance, cls=None): 

42 """ 

43 Call the function and put the return value in instance.__dict__ so that 

44 subsequent attribute access on the instance returns the cached value 

45 instead of calling cached_property.__get__(). 

46 """ 

47 if instance is None: 

48 return self 

49 res = instance.__dict__[self.name] = self.func(instance) 

50 return res 

51 

52 

53class classproperty: 

54 """ 

55 Decorator that converts a method with a single cls argument into a property 

56 that can be accessed directly from the class. 

57 """ 

58 

59 def __init__(self, method=None): 

60 self.fget = method 

61 

62 def __get__(self, instance, cls=None): 

63 return self.fget(cls) 

64 

65 def getter(self, method): 

66 self.fget = method 

67 return self 

68 

69 

70class Promise: 

71 """ 

72 Base class for the proxy class created in the closure of the lazy function. 

73 It's used to recognize promises in code. 

74 """ 

75 

76 pass 

77 

78 

79def lazy(func, *resultclasses): 

80 """ 

81 Turn any callable into a lazy evaluated callable. result classes or types 

82 is required -- at least one is needed so that the automatic forcing of 

83 the lazy evaluation code is triggered. Results are not memoized; the 

84 function is evaluated on every access. 

85 """ 

86 

87 @total_ordering 

88 class __proxy__(Promise): 

89 """ 

90 Encapsulate a function call and act as a proxy for methods that are 

91 called on the result of that function. The function is not evaluated 

92 until one of the methods on the result is called. 

93 """ 

94 

95 __prepared = False 

96 

97 def __init__(self, args, kw): 

98 self.__args = args 

99 self.__kw = kw 

100 if not self.__prepared: 

101 self.__prepare_class__() 

102 self.__class__.__prepared = True 

103 

104 def __reduce__(self): 

105 return ( 

106 _lazy_proxy_unpickle, 

107 (func, self.__args, self.__kw) + resultclasses, 

108 ) 

109 

110 def __repr__(self): 

111 return repr(self.__cast()) 

112 

113 @classmethod 

114 def __prepare_class__(cls): 

115 for resultclass in resultclasses: 

116 for type_ in resultclass.mro(): 

117 for method_name in type_.__dict__: 

118 # All __promise__ return the same wrapper method, they 

119 # look up the correct implementation when called. 

120 if hasattr(cls, method_name): 

121 continue 

122 meth = cls.__promise__(method_name) 

123 setattr(cls, method_name, meth) 

124 cls._delegate_bytes = bytes in resultclasses 

125 cls._delegate_text = str in resultclasses 

126 if cls._delegate_bytes and cls._delegate_text: 126 ↛ 127line 126 didn't jump to line 127, because the condition on line 126 was never true

127 raise ValueError( 

128 "Cannot call lazy() with both bytes and text return types." 

129 ) 

130 if cls._delegate_text: 

131 cls.__str__ = cls.__text_cast 

132 elif cls._delegate_bytes: 132 ↛ 133line 132 didn't jump to line 133, because the condition on line 132 was never true

133 cls.__bytes__ = cls.__bytes_cast 

134 

135 @classmethod 

136 def __promise__(cls, method_name): 

137 # Builds a wrapper around some magic method 

138 def __wrapper__(self, *args, **kw): 

139 # Automatically triggers the evaluation of a lazy value and 

140 # applies the given magic method of the result type. 

141 res = func(*self.__args, **self.__kw) 

142 return getattr(res, method_name)(*args, **kw) 

143 

144 return __wrapper__ 

145 

146 def __text_cast(self): 

147 return func(*self.__args, **self.__kw) 

148 

149 def __bytes_cast(self): 

150 return bytes(func(*self.__args, **self.__kw)) 

151 

152 def __bytes_cast_encoded(self): 

153 return func(*self.__args, **self.__kw).encode() 

154 

155 def __cast(self): 

156 if self._delegate_bytes: 

157 return self.__bytes_cast() 

158 elif self._delegate_text: 

159 return self.__text_cast() 

160 else: 

161 return func(*self.__args, **self.__kw) 

162 

163 def __str__(self): 

164 # object defines __str__(), so __prepare_class__() won't overload 

165 # a __str__() method from the proxied class. 

166 return str(self.__cast()) 

167 

168 def __eq__(self, other): 

169 if isinstance(other, Promise): 

170 other = other.__cast() 

171 return self.__cast() == other 

172 

173 def __lt__(self, other): 

174 if isinstance(other, Promise): 

175 other = other.__cast() 

176 return self.__cast() < other 

177 

178 def __hash__(self): 

179 return hash(self.__cast()) 

180 

181 def __mod__(self, rhs): 

182 if self._delegate_text: 182 ↛ 184line 182 didn't jump to line 184, because the condition on line 182 was never false

183 return str(self) % rhs 

184 return self.__cast() % rhs 

185 

186 def __add__(self, other): 

187 return self.__cast() + other 

188 

189 def __radd__(self, other): 

190 return other + self.__cast() 

191 

192 def __deepcopy__(self, memo): 

193 # Instances of this class are effectively immutable. It's just a 

194 # collection of functions. So we don't need to do anything 

195 # complicated for copying. 

196 memo[id(self)] = self 

197 return self 

198 

199 @wraps(func) 

200 def __wrapper__(*args, **kw): 

201 # Creates the proxy object, instead of the actual value. 

202 return __proxy__(args, kw) 

203 

204 return __wrapper__ 

205 

206 

207def _lazy_proxy_unpickle(func, args, kwargs, *resultclasses): 

208 return lazy(func, *resultclasses)(*args, **kwargs) 

209 

210 

211def lazystr(text): 

212 """ 

213 Shortcut for the common case of a lazy callable that returns str. 

214 """ 

215 return lazy(str, str)(text) 

216 

217 

218def keep_lazy(*resultclasses): 

219 """ 

220 A decorator that allows a function to be called with one or more lazy 

221 arguments. If none of the args are lazy, the function is evaluated 

222 immediately, otherwise a __proxy__ is returned that will evaluate the 

223 function when needed. 

224 """ 

225 if not resultclasses: 225 ↛ 226line 225 didn't jump to line 226, because the condition on line 225 was never true

226 raise TypeError("You must pass at least one argument to keep_lazy().") 

227 

228 def decorator(func): 

229 lazy_func = lazy(func, *resultclasses) 

230 

231 @wraps(func) 

232 def wrapper(*args, **kwargs): 

233 if any( 

234 isinstance(arg, Promise) 

235 for arg in itertools.chain(args, kwargs.values()) 

236 ): 

237 return lazy_func(*args, **kwargs) 

238 return func(*args, **kwargs) 

239 

240 return wrapper 

241 

242 return decorator 

243 

244 

245def keep_lazy_text(func): 

246 """ 

247 A decorator for functions that accept lazy arguments and return text. 

248 """ 

249 return keep_lazy(str)(func) 

250 

251 

252empty = object() 

253 

254 

255def new_method_proxy(func): 

256 def inner(self, *args): 

257 if self._wrapped is empty: 

258 self._setup() 

259 return func(self._wrapped, *args) 

260 

261 return inner 

262 

263 

264class LazyObject: 

265 """ 

266 A wrapper for another class that can be used to delay instantiation of the 

267 wrapped class. 

268 

269 By subclassing, you have the opportunity to intercept and alter the 

270 instantiation. If you don't need to do that, use SimpleLazyObject. 

271 """ 

272 

273 # Avoid infinite recursion when tracing __init__ (#19456). 

274 _wrapped = None 

275 

276 def __init__(self): 

277 # Note: if a subclass overrides __init__(), it will likely need to 

278 # override __copy__() and __deepcopy__() as well. 

279 self._wrapped = empty 

280 

281 __getattr__ = new_method_proxy(getattr) 

282 

283 def __setattr__(self, name, value): 

284 if name == "_wrapped": 

285 # Assign to __dict__ to avoid infinite __setattr__ loops. 

286 self.__dict__["_wrapped"] = value 

287 else: 

288 if self._wrapped is empty: 288 ↛ 289line 288 didn't jump to line 289, because the condition on line 288 was never true

289 self._setup() 

290 setattr(self._wrapped, name, value) 

291 

292 def __delattr__(self, name): 

293 if name == "_wrapped": 

294 raise TypeError("can't delete _wrapped.") 

295 if self._wrapped is empty: 

296 self._setup() 

297 delattr(self._wrapped, name) 

298 

299 def _setup(self): 

300 """ 

301 Must be implemented by subclasses to initialize the wrapped object. 

302 """ 

303 raise NotImplementedError( 

304 "subclasses of LazyObject must provide a _setup() method" 

305 ) 

306 

307 # Because we have messed with __class__ below, we confuse pickle as to what 

308 # class we are pickling. We're going to have to initialize the wrapped 

309 # object to successfully pickle it, so we might as well just pickle the 

310 # wrapped object since they're supposed to act the same way. 

311 # 

312 # Unfortunately, if we try to simply act like the wrapped object, the ruse 

313 # will break down when pickle gets our id(). Thus we end up with pickle 

314 # thinking, in effect, that we are a distinct object from the wrapped 

315 # object, but with the same __dict__. This can cause problems (see #25389). 

316 # 

317 # So instead, we define our own __reduce__ method and custom unpickler. We 

318 # pickle the wrapped object as the unpickler's argument, so that pickle 

319 # will pickle it normally, and then the unpickler simply returns its 

320 # argument. 

321 def __reduce__(self): 

322 if self._wrapped is empty: 

323 self._setup() 

324 return (unpickle_lazyobject, (self._wrapped,)) 

325 

326 def __copy__(self): 

327 if self._wrapped is empty: 

328 # If uninitialized, copy the wrapper. Use type(self), not 

329 # self.__class__, because the latter is proxied. 

330 return type(self)() 

331 else: 

332 # If initialized, return a copy of the wrapped object. 

333 return copy.copy(self._wrapped) 

334 

335 def __deepcopy__(self, memo): 

336 if self._wrapped is empty: 

337 # We have to use type(self), not self.__class__, because the 

338 # latter is proxied. 

339 result = type(self)() 

340 memo[id(self)] = result 

341 return result 

342 return copy.deepcopy(self._wrapped, memo) 

343 

344 __bytes__ = new_method_proxy(bytes) 

345 __str__ = new_method_proxy(str) 

346 __bool__ = new_method_proxy(bool) 

347 

348 # Introspection support 

349 __dir__ = new_method_proxy(dir) 

350 

351 # Need to pretend to be the wrapped class, for the sake of objects that 

352 # care about this (especially in equality tests) 

353 __class__ = property(new_method_proxy(operator.attrgetter("__class__"))) 

354 __eq__ = new_method_proxy(operator.eq) 

355 __lt__ = new_method_proxy(operator.lt) 

356 __gt__ = new_method_proxy(operator.gt) 

357 __ne__ = new_method_proxy(operator.ne) 

358 __hash__ = new_method_proxy(hash) 

359 

360 # List/Tuple/Dictionary methods support 

361 __getitem__ = new_method_proxy(operator.getitem) 

362 __setitem__ = new_method_proxy(operator.setitem) 

363 __delitem__ = new_method_proxy(operator.delitem) 

364 __iter__ = new_method_proxy(iter) 

365 __len__ = new_method_proxy(len) 

366 __contains__ = new_method_proxy(operator.contains) 

367 

368 

369def unpickle_lazyobject(wrapped): 

370 """ 

371 Used to unpickle lazy objects. Just return its argument, which will be the 

372 wrapped object. 

373 """ 

374 return wrapped 

375 

376 

377class SimpleLazyObject(LazyObject): 

378 """ 

379 A lazy object initialized from any function. 

380 

381 Designed for compound objects of unknown type. For builtins or objects of 

382 known type, use django.utils.functional.lazy. 

383 """ 

384 

385 def __init__(self, func): 

386 """ 

387 Pass in a callable that returns the object to be wrapped. 

388 

389 If copies are made of the resulting SimpleLazyObject, which can happen 

390 in various circumstances within Django, then you must ensure that the 

391 callable can be safely run more than once and will return the same 

392 value. 

393 """ 

394 self.__dict__["_setupfunc"] = func 

395 super().__init__() 

396 

397 def _setup(self): 

398 self._wrapped = self._setupfunc() 

399 

400 # Return a meaningful representation of the lazy object for debugging 

401 # without evaluating the wrapped object. 

402 def __repr__(self): 

403 if self._wrapped is empty: 

404 repr_attr = self._setupfunc 

405 else: 

406 repr_attr = self._wrapped 

407 return "<%s: %r>" % (type(self).__name__, repr_attr) 

408 

409 def __copy__(self): 

410 if self._wrapped is empty: 

411 # If uninitialized, copy the wrapper. Use SimpleLazyObject, not 

412 # self.__class__, because the latter is proxied. 

413 return SimpleLazyObject(self._setupfunc) 

414 else: 

415 # If initialized, return a copy of the wrapped object. 

416 return copy.copy(self._wrapped) 

417 

418 def __deepcopy__(self, memo): 

419 if self._wrapped is empty: 

420 # We have to use SimpleLazyObject, not self.__class__, because the 

421 # latter is proxied. 

422 result = SimpleLazyObject(self._setupfunc) 

423 memo[id(self)] = result 

424 return result 

425 return copy.deepcopy(self._wrapped, memo) 

426 

427 

428def partition(predicate, values): 

429 """ 

430 Split the values into two sets, based on the return value of the function 

431 (True/False). e.g.: 

432 

433 >>> partition(lambda x: x > 3, range(5)) 

434 [0, 1, 2, 3], [4] 

435 """ 

436 results = ([], []) 

437 for item in values: 

438 results[predicate(item)].append(item) 

439 return results