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
« 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
7class cached_property:
8 """
9 Decorator that converts a method with a single self argument into a
10 property cached on the instance.
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 """
18 name = None
20 @staticmethod
21 def func(instance):
22 raise TypeError(
23 "Cannot use cached_property instance without calling "
24 "__set_name__() on it."
25 )
27 def __init__(self, func, name=None):
28 self.real_func = func
29 self.__doc__ = getattr(func, "__doc__")
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 )
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
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 """
59 def __init__(self, method=None):
60 self.fget = method
62 def __get__(self, instance, cls=None):
63 return self.fget(cls)
65 def getter(self, method):
66 self.fget = method
67 return self
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 """
76 pass
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 """
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 """
95 __prepared = False
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
104 def __reduce__(self):
105 return (
106 _lazy_proxy_unpickle,
107 (func, self.__args, self.__kw) + resultclasses,
108 )
110 def __repr__(self):
111 return repr(self.__cast())
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
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)
144 return __wrapper__
146 def __text_cast(self):
147 return func(*self.__args, **self.__kw)
149 def __bytes_cast(self):
150 return bytes(func(*self.__args, **self.__kw))
152 def __bytes_cast_encoded(self):
153 return func(*self.__args, **self.__kw).encode()
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)
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())
168 def __eq__(self, other):
169 if isinstance(other, Promise):
170 other = other.__cast()
171 return self.__cast() == other
173 def __lt__(self, other):
174 if isinstance(other, Promise):
175 other = other.__cast()
176 return self.__cast() < other
178 def __hash__(self):
179 return hash(self.__cast())
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
186 def __add__(self, other):
187 return self.__cast() + other
189 def __radd__(self, other):
190 return other + self.__cast()
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
199 @wraps(func)
200 def __wrapper__(*args, **kw):
201 # Creates the proxy object, instead of the actual value.
202 return __proxy__(args, kw)
204 return __wrapper__
207def _lazy_proxy_unpickle(func, args, kwargs, *resultclasses):
208 return lazy(func, *resultclasses)(*args, **kwargs)
211def lazystr(text):
212 """
213 Shortcut for the common case of a lazy callable that returns str.
214 """
215 return lazy(str, str)(text)
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().")
228 def decorator(func):
229 lazy_func = lazy(func, *resultclasses)
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)
240 return wrapper
242 return decorator
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)
252empty = object()
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)
261 return inner
264class LazyObject:
265 """
266 A wrapper for another class that can be used to delay instantiation of the
267 wrapped class.
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 """
273 # Avoid infinite recursion when tracing __init__ (#19456).
274 _wrapped = None
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
281 __getattr__ = new_method_proxy(getattr)
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)
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)
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 )
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,))
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)
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)
344 __bytes__ = new_method_proxy(bytes)
345 __str__ = new_method_proxy(str)
346 __bool__ = new_method_proxy(bool)
348 # Introspection support
349 __dir__ = new_method_proxy(dir)
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)
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)
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
377class SimpleLazyObject(LazyObject):
378 """
379 A lazy object initialized from any function.
381 Designed for compound objects of unknown type. For builtins or objects of
382 known type, use django.utils.functional.lazy.
383 """
385 def __init__(self, func):
386 """
387 Pass in a callable that returns the object to be wrapped.
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__()
397 def _setup(self):
398 self._wrapped = self._setupfunc()
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)
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)
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)
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.:
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