Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/utils/functional.py: 32%

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

213 statements  

1import copy 

2import itertools 

3import operator 

4from functools import 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 """ 

15 

16 name = None 

17 

18 @staticmethod 

19 def func(instance): 

20 raise TypeError( 

21 "Cannot use cached_property instance without calling " 

22 "__set_name__() on it." 

23 ) 

24 

25 def __init__(self, func): 

26 self.real_func = func 

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

28 

29 def __set_name__(self, owner, name): 

30 if self.name is None: 

31 self.name = name 

32 self.func = self.real_func 

33 elif name != self.name: 

34 raise TypeError( 

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

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

37 ) 

38 

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

40 """ 

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

42 subsequent attribute access on the instance returns the cached value 

43 instead of calling cached_property.__get__(). 

44 """ 

45 if instance is None: 

46 return self 

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

48 return res 

49 

50 

51class classproperty: 

52 """ 

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

54 that can be accessed directly from the class. 

55 """ 

56 

57 def __init__(self, method=None): 

58 self.fget = method 

59 

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

61 return self.fget(cls) 

62 

63 def getter(self, method): 

64 self.fget = method 

65 return self 

66 

67 

68class Promise: 

69 """ 

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

71 It's used to recognize promises in code. 

72 """ 

73 

74 pass 

75 

76 

77def lazy(func, *resultclasses): 

78 """ 

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

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

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

82 function is evaluated on every access. 

83 """ 

84 

85 class __proxy__(Promise): 

86 """ 

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

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

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

90 """ 

91 

92 def __init__(self, args, kw): 

93 self._args = args 

94 self._kw = kw 

95 

96 def __reduce__(self): 

97 return ( 

98 _lazy_proxy_unpickle, 

99 (func, self._args, self._kw) + resultclasses, 

100 ) 

101 

102 def __deepcopy__(self, memo): 

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

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

105 # complicated for copying. 

106 memo[id(self)] = self 

107 return self 

108 

109 def __cast(self): 

110 return func(*self._args, **self._kw) 

111 

112 # Explicitly wrap methods which are defined on object and hence would 

113 # not have been overloaded by the loop over resultclasses below. 

114 

115 def __repr__(self): 

116 return repr(self.__cast()) 

117 

118 def __str__(self): 

119 return str(self.__cast()) 

120 

121 def __eq__(self, other): 

122 if isinstance(other, Promise): 

123 other = other.__cast() 

124 return self.__cast() == other 

125 

126 def __ne__(self, other): 

127 if isinstance(other, Promise): 

128 other = other.__cast() 

129 return self.__cast() != other 

130 

131 def __lt__(self, other): 

132 if isinstance(other, Promise): 

133 other = other.__cast() 

134 return self.__cast() < other 

135 

136 def __le__(self, other): 

137 if isinstance(other, Promise): 

138 other = other.__cast() 

139 return self.__cast() <= other 

140 

141 def __gt__(self, other): 

142 if isinstance(other, Promise): 

143 other = other.__cast() 

144 return self.__cast() > other 

145 

146 def __ge__(self, other): 

147 if isinstance(other, Promise): 

148 other = other.__cast() 

149 return self.__cast() >= other 

150 

151 def __hash__(self): 

152 return hash(self.__cast()) 

153 

154 def __format__(self, format_spec): 

155 return format(self.__cast(), format_spec) 

156 

157 # Explicitly wrap methods which are required for certain operations on 

158 # int/str objects to function correctly. 

159 

160 def __add__(self, other): 

161 return self.__cast() + other 

162 

163 def __radd__(self, other): 

164 return other + self.__cast() 

165 

166 def __mod__(self, other): 

167 return self.__cast() % other 

168 

169 def __mul__(self, other): 

170 return self.__cast() * other 

171 

172 # Add wrappers for all methods from resultclasses which haven't been 

173 # wrapped explicitly above. 

174 for resultclass in resultclasses: 

175 for type_ in resultclass.mro(): 

176 for method_name in type_.__dict__: 

177 # All __promise__ return the same wrapper method, they look up 

178 # the correct implementation when called. 

179 if hasattr(__proxy__, method_name): 

180 continue 

181 

182 # Builds a wrapper around some method. Pass method_name to 

183 # avoid issues due to late binding. 

184 def __wrapper__(self, *args, __method_name=method_name, **kw): 

185 # Automatically triggers the evaluation of a lazy value and 

186 # applies the given method of the result type. 

187 result = func(*self._args, **self._kw) 

188 return getattr(result, __method_name)(*args, **kw) 

189 

190 setattr(__proxy__, method_name, __wrapper__) 

191 

192 @wraps(func) 

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

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

195 return __proxy__(args, kw) 

196 

197 return __wrapper__ 

198 

199 

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

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

202 

203 

204def lazystr(text): 

205 """ 

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

207 """ 

208 return lazy(str, str)(text) 

209 

210 

211def keep_lazy(*resultclasses): 

212 """ 

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

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

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

216 function when needed. 

217 """ 

218 if not resultclasses: 

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

220 

221 def decorator(func): 

222 lazy_func = lazy(func, *resultclasses) 

223 

224 @wraps(func) 

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

226 if any( 

227 isinstance(arg, Promise) 

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

229 ): 

230 return lazy_func(*args, **kwargs) 

231 return func(*args, **kwargs) 

232 

233 return wrapper 

234 

235 return decorator 

236 

237 

238def keep_lazy_text(func): 

239 """ 

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

241 """ 

242 return keep_lazy(str)(func) 

243 

244 

245empty = object() 

246 

247 

248def new_method_proxy(func): 

249 def inner(self, *args): 

250 if (_wrapped := self._wrapped) is empty: 

251 self._setup() 

252 _wrapped = self._wrapped 

253 return func(_wrapped, *args) 

254 

255 inner._mask_wrapped = False 

256 return inner 

257 

258 

259class LazyObject: 

260 """ 

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

262 wrapped class. 

263 

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

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

266 """ 

267 

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

269 _wrapped = None 

270 

271 def __init__(self): 

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

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

274 self._wrapped = empty 

275 

276 def __getattribute__(self, name): 

277 if name == "_wrapped": 

278 # Avoid recursion when getting wrapped object. 

279 return super().__getattribute__(name) 

280 value = super().__getattribute__(name) 

281 # If attribute is a proxy method, raise an AttributeError to call 

282 # __getattr__() and use the wrapped object method. 

283 if not getattr(value, "_mask_wrapped", True): 

284 raise AttributeError 

285 return value 

286 

287 __getattr__ = new_method_proxy(getattr) 

288 

289 def __setattr__(self, name, value): 

290 if name == "_wrapped": 

291 # Assign to __dict__ to avoid infinite __setattr__ loops. 

292 self.__dict__["_wrapped"] = value 

293 else: 

294 if self._wrapped is empty: 

295 self._setup() 

296 setattr(self._wrapped, name, value) 

297 

298 def __delattr__(self, name): 

299 if name == "_wrapped": 

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

301 if self._wrapped is empty: 

302 self._setup() 

303 delattr(self._wrapped, name) 

304 

305 def _setup(self): 

306 """ 

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

308 """ 

309 raise NotImplementedError( 

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

311 ) 

312 

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

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

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

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

317 # 

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

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

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

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

322 # 

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

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

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

326 # argument. 

327 def __reduce__(self): 

328 if self._wrapped is empty: 

329 self._setup() 

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

331 

332 def __copy__(self): 

333 if self._wrapped is empty: 

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

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

336 return type(self)() 

337 else: 

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

339 return copy.copy(self._wrapped) 

340 

341 def __deepcopy__(self, memo): 

342 if self._wrapped is empty: 

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

344 # latter is proxied. 

345 result = type(self)() 

346 memo[id(self)] = result 

347 return result 

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

349 

350 __bytes__ = new_method_proxy(bytes) 

351 __str__ = new_method_proxy(str) 

352 __bool__ = new_method_proxy(bool) 

353 

354 # Introspection support 

355 __dir__ = new_method_proxy(dir) 

356 

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

358 # care about this (especially in equality tests) 

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

360 __eq__ = new_method_proxy(operator.eq) 

361 __lt__ = new_method_proxy(operator.lt) 

362 __gt__ = new_method_proxy(operator.gt) 

363 __ne__ = new_method_proxy(operator.ne) 

364 __hash__ = new_method_proxy(hash) 

365 

366 # List/Tuple/Dictionary methods support 

367 __getitem__ = new_method_proxy(operator.getitem) 

368 __setitem__ = new_method_proxy(operator.setitem) 

369 __delitem__ = new_method_proxy(operator.delitem) 

370 __iter__ = new_method_proxy(iter) 

371 __len__ = new_method_proxy(len) 

372 __contains__ = new_method_proxy(operator.contains) 

373 

374 

375def unpickle_lazyobject(wrapped): 

376 """ 

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

378 wrapped object. 

379 """ 

380 return wrapped 

381 

382 

383class SimpleLazyObject(LazyObject): 

384 """ 

385 A lazy object initialized from any function. 

386 

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

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

389 """ 

390 

391 def __init__(self, func): 

392 """ 

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

394 

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

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

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

398 value. 

399 """ 

400 self.__dict__["_setupfunc"] = func 

401 super().__init__() 

402 

403 def _setup(self): 

404 self._wrapped = self._setupfunc() 

405 

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

407 # without evaluating the wrapped object. 

408 def __repr__(self): 

409 if self._wrapped is empty: 

410 repr_attr = self._setupfunc 

411 else: 

412 repr_attr = self._wrapped 

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

414 

415 def __copy__(self): 

416 if self._wrapped is empty: 

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

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

419 return SimpleLazyObject(self._setupfunc) 

420 else: 

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

422 return copy.copy(self._wrapped) 

423 

424 def __deepcopy__(self, memo): 

425 if self._wrapped is empty: 

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

427 # latter is proxied. 

428 result = SimpleLazyObject(self._setupfunc) 

429 memo[id(self)] = result 

430 return result 

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

432 

433 __add__ = new_method_proxy(operator.add) 

434 

435 @new_method_proxy 

436 def __radd__(self, other): 

437 return other + self 

438 

439 

440def partition(predicate, values): 

441 """ 

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

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

444 

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

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

447 """ 

448 results = ([], []) 

449 for item in values: 

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

451 return results