18.0 vanilla

This commit is contained in:
Ernad Husremovic 2025-10-03 18:06:50 +02:00
parent d72e748793
commit 0a7ae8db93
337 changed files with 399651 additions and 232598 deletions

View file

@ -1,28 +1,42 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
__all__ = ['synchronized', 'lazy_classproperty', 'lazy_property',
'classproperty', 'conditional', 'lazy']
import warnings
from inspect import getsourcefile, Parameter, signature
from functools import wraps
from json import JSONEncoder
from __future__ import annotations
import typing
from inspect import Parameter, getsourcefile, signature
from decorator import decorator
class lazy_property(object):
__all__ = [
'classproperty',
'conditional',
'lazy',
'lazy_classproperty',
'lazy_property',
'synchronized',
]
T = typing.TypeVar("T")
if typing.TYPE_CHECKING:
from collections.abc import Callable
class lazy_property(typing.Generic[T]):
""" Decorator for a lazy property of an object, i.e., an object attribute
that is determined by the result of a method call evaluated once. To
reevaluate the property, simply delete the attribute on the object, and
get it again.
"""
def __init__(self, fget):
def __init__(self, fget: Callable[[typing.Any], T]):
assert not fget.__name__.startswith('__'),\
"lazy_property does not support mangled names"
self.fget = fget
def __get__(self, obj, cls):
@typing.overload
def __get__(self, obj: None, cls: typing.Any, /) -> typing.Any: ...
@typing.overload
def __get__(self, obj: object, cls: typing.Any, /) -> T: ...
def __get__(self, obj, cls, /):
if obj is None:
return self
value = self.fget(obj)
@ -34,7 +48,7 @@ class lazy_property(object):
return self.fget.__doc__
@staticmethod
def reset_all(obj):
def reset_all(obj) -> None:
""" Reset all lazy properties on the instance `obj`. """
cls = type(obj)
obj_dict = vars(obj)
@ -42,12 +56,6 @@ class lazy_property(object):
if isinstance(getattr(cls, name, None), lazy_property):
obj_dict.pop(name)
class lazy_classproperty(lazy_property):
""" Similar to :class:`lazy_property`, but for classes. """
def __get__(self, obj, cls):
val = self.fget(cls)
setattr(cls, self.fget.__name__, val)
return val
def conditional(condition, decorator):
""" Decorator for a conditionally applied decorator.
@ -63,7 +71,8 @@ def conditional(condition, decorator):
else:
return lambda fn: fn
def filter_kwargs(func, kwargs):
def filter_kwargs(func: Callable, kwargs: dict[str, typing.Any]) -> dict[str, typing.Any]:
""" Filter the given keyword arguments to only return the kwargs
that binds to the function's signature.
"""
@ -80,19 +89,22 @@ def filter_kwargs(func, kwargs):
return {key: kwargs[key] for key in kwargs if key not in leftovers}
def synchronized(lock_attr='_lock'):
def synchronized(lock_attr: str = '_lock'):
@decorator
def locked(func, inst, *args, **kwargs):
with getattr(inst, lock_attr):
return func(inst, *args, **kwargs)
return locked
locked = synchronized()
def frame_codeinfo(fframe, back=0):
""" Return a (filename, line) pair for a previous frame .
@return (filename, lineno) where lineno is either int or string==''
"""
try:
if not fframe:
return "<unknown>", ''
@ -107,33 +119,25 @@ def frame_codeinfo(fframe, back=0):
except Exception:
return "<unknown>", ''
def compose(a, b):
""" Composes the callables ``a`` and ``b``. ``compose(a, b)(*args)`` is
equivalent to ``a(b(*args))``.
Can be used as a decorator by partially applying ``a``::
class classproperty(typing.Generic[T]):
def __init__(self, fget: Callable[[typing.Any], T]) -> None:
self.fget = classmethod(fget)
@partial(compose, a)
def b():
...
"""
warnings.warn(
"Since 16.0, just byo or use a dedicated library like funcy.",
DeprecationWarning,
stacklevel=2,
)
@wraps(b)
def wrapper(*args, **kwargs):
return a(b(*args, **kwargs))
return wrapper
class _ClassProperty(property):
def __get__(self, cls, owner):
def __get__(self, cls, owner: type | None = None, /) -> T:
return self.fget.__get__(None, owner)()
def classproperty(func):
return _ClassProperty(classmethod(func))
@property
def __doc__(self):
return self.fget.__doc__
class lazy_classproperty(classproperty[T], typing.Generic[T]):
""" Similar to :class:`lazy_property`, but for classes. """
def __get__(self, cls, owner: type | None = None, /) -> T:
val = super().__get__(cls, owner)
setattr(owner, self.fget.__name__, val)
return val
class lazy(object):