mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-19 04:49:36 -07:00
Add backports.cached-property==1.0.2
This commit is contained in:
parent
2a0e07aca5
commit
7386ca1c42
4 changed files with 124 additions and 0 deletions
94
lib/backports/cached_property/__init__.py
Normal file
94
lib/backports/cached_property/__init__.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
"""Backport of python 3.8 functools.cached_property.
|
||||
|
||||
cached_property() - computed once per instance, cached as attribute
|
||||
"""
|
||||
|
||||
__all__ = ("cached_property",)
|
||||
|
||||
# Standard Library
|
||||
from sys import version_info
|
||||
try:
|
||||
# Local Implementation
|
||||
from ._version import version as __version__
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
if version_info >= (3, 8):
|
||||
# Standard Library
|
||||
from functools import cached_property # pylint: disable=no-name-in-module
|
||||
else:
|
||||
# Standard Library
|
||||
from threading import RLock
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import Optional
|
||||
from typing import Type
|
||||
from typing import TypeVar
|
||||
|
||||
_NOT_FOUND = object()
|
||||
_T = TypeVar("_T")
|
||||
_S = TypeVar("_S")
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
class cached_property: # NOSONAR # pylint: disable=invalid-name # noqa: N801
|
||||
"""Cached property implementation.
|
||||
|
||||
Transform a method of a class into a property whose value is computed once
|
||||
and then cached as a normal attribute for the life of the instance.
|
||||
Similar to property(), with the addition of caching.
|
||||
Useful for expensive computed properties of instances
|
||||
that are otherwise effectively immutable.
|
||||
"""
|
||||
|
||||
def __init__(self, func: Callable[[Any], _T]) -> None:
|
||||
"""Cached property implementation."""
|
||||
self.func = func
|
||||
self.attrname: Optional[str] = None
|
||||
self.__doc__ = func.__doc__
|
||||
self.lock = RLock()
|
||||
|
||||
def __set_name__(self, owner: Type[Any], name: str) -> None:
|
||||
"""Assign attribute name and owner."""
|
||||
if self.attrname is None:
|
||||
self.attrname = name
|
||||
elif name != self.attrname:
|
||||
raise TypeError(
|
||||
"Cannot assign the same cached_property to two different names "
|
||||
f"({self.attrname!r} and {name!r})."
|
||||
)
|
||||
|
||||
def __get__(self, instance: Optional[_S], owner: Optional[Type[Any]] = None) -> Any:
|
||||
"""Property-like getter implementation.
|
||||
|
||||
:return: property instance if requested on class or value/cached value if requested on instance.
|
||||
:rtype: Union[cached_property[_T], _T]
|
||||
:raises TypeError: call without calling __set_name__ or no '__dict__' attribute
|
||||
"""
|
||||
if instance is None:
|
||||
return self
|
||||
if self.attrname is None:
|
||||
raise TypeError("Cannot use cached_property instance without calling __set_name__ on it.")
|
||||
try:
|
||||
cache = instance.__dict__
|
||||
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
|
||||
msg = (
|
||||
f"No '__dict__' attribute on {type(instance).__name__!r} "
|
||||
f"instance to cache {self.attrname!r} property."
|
||||
)
|
||||
raise TypeError(msg) from None
|
||||
val = cache.get(self.attrname, _NOT_FOUND)
|
||||
if val is _NOT_FOUND:
|
||||
with self.lock:
|
||||
# check if another thread filled cache while we awaited lock
|
||||
val = cache.get(self.attrname, _NOT_FOUND)
|
||||
if val is _NOT_FOUND:
|
||||
val = self.func(instance)
|
||||
try:
|
||||
cache[self.attrname] = val
|
||||
except TypeError:
|
||||
msg = (
|
||||
f"The '__dict__' attribute on {type(instance).__name__!r} instance "
|
||||
f"does not support item assignment for caching {self.attrname!r} property."
|
||||
)
|
||||
raise TypeError(msg) from None
|
||||
return val
|
24
lib/backports/cached_property/__init__.pyi
Normal file
24
lib/backports/cached_property/__init__.pyi
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Standard Library
|
||||
from threading import RLock
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import Generic
|
||||
from typing import Optional
|
||||
from typing import Type
|
||||
from typing import TypeVar
|
||||
from typing import overload
|
||||
|
||||
_T = TypeVar("_T")
|
||||
_S = TypeVar("_S")
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
class cached_property(Generic[_T]):
|
||||
func: Callable[[Any], _T]
|
||||
attrname: Optional[str]
|
||||
lock: RLock
|
||||
def __init__(self, func: Callable[[Any], _T]) -> None: ...
|
||||
@overload
|
||||
def __get__(self, instance: None, owner: Optional[Type[Any]] = ...) -> cached_property[_T]: ...
|
||||
@overload
|
||||
def __get__(self, instance: _S, owner: Optional[Type[Any]] = ...) -> _T: ...
|
||||
def __set_name__(self, owner: Type[Any], name: str) -> None: ...
|
5
lib/backports/cached_property/_version.py
Normal file
5
lib/backports/cached_property/_version.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
# coding: utf-8
|
||||
# file generated by setuptools_scm
|
||||
# don't change, don't track in version control
|
||||
version = '1.0.2'
|
||||
version_tuple = (1, 0, 2)
|
1
lib/backports/cached_property/py.typed
Normal file
1
lib/backports/cached_property/py.typed
Normal file
|
@ -0,0 +1 @@
|
|||
|
Loading…
Add table
Add a link
Reference in a new issue