1 # -*- coding: utf-8 -*-
3 __author__
= "Daniel Greenfeld"
4 __email__
= "pydanny@gmail.com"
13 except (ImportError, SyntaxError):
17 class cached_property(object):
19 A property that is only computed once per instance and then replaces itself
20 with an ordinary attribute. Deleting the attribute resets the property.
21 Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
24 def __init__(self
, func
):
25 self
.__doc
__ = getattr(func
, "__doc__")
28 def __get__(self
, obj
, cls
):
32 if asyncio
and asyncio
.iscoroutinefunction(self
.func
):
33 return self
._wrap
_in
_coroutine
(obj
)
35 value
= obj
.__dict
__[self
.func
.__name
__] = self
.func(obj
)
38 def _wrap_in_coroutine(self
, obj
):
42 future
= asyncio
.ensure_future(self
.func(obj
))
43 obj
.__dict
__[self
.func
.__name
__] = future
49 class threaded_cached_property(object):
51 A cached_property version for use in environments where multiple threads
52 might concurrently try to access the property.
55 def __init__(self
, func
):
56 self
.__doc
__ = getattr(func
, "__doc__")
58 self
.lock
= threading
.RLock()
60 def __get__(self
, obj
, cls
):
64 obj_dict
= obj
.__dict
__
65 name
= self
.func
.__name
__
68 # check if the value was computed before the lock was acquired
72 # if not, do the calculation and release the lock
73 return obj_dict
.setdefault(name
, self
.func(obj
))
76 class cached_property_with_ttl(object):
78 A property that is only computed once per instance and then replaces itself
79 with an ordinary attribute. Setting the ttl to a number expresses how long
80 the property will last before being timed out.
83 def __init__(self
, ttl
=None):
90 self
._prepare
_func
(func
)
92 def __call__(self
, func
):
93 self
._prepare
_func
(func
)
96 def __get__(self
, obj
, cls
):
101 obj_dict
= obj
.__dict
__
104 value
, last_updated
= obj_dict
[name
]
108 ttl_expired
= self
.ttl
and self
.ttl
< now
- last_updated
112 value
= self
.func(obj
)
113 obj_dict
[name
] = (value
, now
)
116 def __delete__(self
, obj
):
117 obj
.__dict
__.pop(self
.__name
__, None)
119 def __set__(self
, obj
, value
):
120 obj
.__dict
__[self
.__name
__] = (value
, time())
122 def _prepare_func(self
, func
):
125 self
.__doc
__ = func
.__doc
__
126 self
.__name
__ = func
.__name
__
127 self
.__module
__ = func
.__module
__
130 # Aliases to make cached_property_with_ttl easier to use
131 cached_property_ttl
= cached_property_with_ttl
132 timed_cached_property
= cached_property_with_ttl
135 class threaded_cached_property_with_ttl(cached_property_with_ttl
):
137 A cached_property version for use in environments where multiple threads
138 might concurrently try to access the property.
141 def __init__(self
, ttl
=None):
142 super(threaded_cached_property_with_ttl
, self
).__init
__(ttl
)
143 self
.lock
= threading
.RLock()
145 def __get__(self
, obj
, cls
):
147 return super(threaded_cached_property_with_ttl
, self
).__get
__(obj
, cls
)
150 # Alias to make threaded_cached_property_with_ttl easier to use
151 threaded_cached_property_ttl
= threaded_cached_property_with_ttl
152 timed_threaded_cached_property
= threaded_cached_property_with_ttl