-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathlazy_string.py
More file actions
82 lines (59 loc) · 2.23 KB
/
lazy_string.py
File metadata and controls
82 lines (59 loc) · 2.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import sys
if sys.version_info >= (3, 9):
from collections.abc import Callable
from collections.abc import Mapping
List = list
Tuple = tuple
else:
from typing import Callable
from typing import Mapping
from typing import List
from typing import Tuple
from collections import UserString
from typing import Any
from typing import TypeVar
from typing import Union
LazyString = TypeVar("LazyString")
class LazyString(UserString):
"""
A string with delayed evaluation.
:param func: Callable (e.g., function) returning a string.
:param args: Optional positional arguments which will be passed to the ``func``.
:param kwargs: Optional keyword arguments which will be passed to the ``func``.
"""
__slots__ = ("_func", "_args", )
def __new__(cls, func: Union[Callable, str], *args: Tuple, **kwargs: Mapping) -> object:
if isinstance(func, str):
# Many UserString's functions like `lower`, `__add__` and so on wrap
# returned values with a call to `self.__class__(...)` to ensure the
# result is of the same type as the original class.
# However, as the result of all of such methods is always a string,
# there's no need to create a new instance of a `LazyString`
return func
return object.__new__(cls)
def __init__(self, func: Callable[..., str], *args: Tuple, **kwargs: Mapping) -> None:
self._func = func
self._args = args
self._kwargs = kwargs
@property
def data(self) -> str:
return self._func(*self._args, **self._kwargs)
def __getnewargs_ex__(self) -> Tuple[Tuple, Mapping]:
args = (self._func, ) + self._args
return (args, self._kwargs)
def __getstate__(self) -> Tuple[Callable, Tuple, Mapping]:
return (self._func, self._args, self._kwargs)
def __setstate__(self, state: Tuple[Callable, Tuple, Mapping]) -> None:
self._func, self._args, self._kwargs = state
def __getattr__(self, name: str) -> Any:
return getattr(self.data, name)
def __dir__(self) -> List[str]:
return dir(str)
def __copy__(self) -> LazyString:
return self
def __repr__(self) -> str:
try:
r = repr(str(self.data))
return f"{self.__class__.__name__}({r})"
except Exception:
return "<%s broken>" % self.__class__.__name__