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
):
41 future
= asyncio
.ensure_future(self
.func(obj
))
42 obj
.__dict
__[self
.func
.__name
__] = future
48 class threaded_cached_property(object):
50 A cached_property version for use in environments where multiple threads
51 might concurrently try to access the property.
54 def __init__(self
, func
):
55 self
.__doc
__ = getattr(func
, "__doc__")
57 self
.lock
= threading
.RLock()
59 def __get__(self
, obj
, cls
):
63 obj_dict
= obj
.__dict
__
64 name
= self
.func
.__name
__
67 # check if the value was computed before the lock was acquired
71 # if not, do the calculation and release the lock
72 return obj_dict
.setdefault(name
, self
.func(obj
))
75 class cached_property_with_ttl(object):
77 A property that is only computed once per instance and then replaces itself
78 with an ordinary attribute. Setting the ttl to a number expresses how long
79 the property will last before being timed out.
82 def __init__(self
, ttl
=None):
89 self
._prepare
_func
(func
)
91 def __call__(self
, func
):
92 self
._prepare
_func
(func
)
95 def __get__(self
, obj
, cls
):
100 obj_dict
= obj
.__dict
__
103 value
, last_updated
= obj_dict
[name
]
107 ttl_expired
= self
.ttl
and self
.ttl
< now
- last_updated
111 value
= self
.func(obj
)
112 obj_dict
[name
] = (value
, now
)
115 def __delete__(self
, obj
):
116 obj
.__dict
__.pop(self
.__name
__, None)
118 def __set__(self
, obj
, value
):
119 obj
.__dict
__[self
.__name
__] = (value
, time())
121 def _prepare_func(self
, func
):
124 self
.__doc
__ = func
.__doc
__
125 self
.__name
__ = func
.__name
__
126 self
.__module
__ = func
.__module
__
129 # Aliases to make cached_property_with_ttl easier to use
130 cached_property_ttl
= cached_property_with_ttl
131 timed_cached_property
= cached_property_with_ttl
134 class threaded_cached_property_with_ttl(cached_property_with_ttl
):
136 A cached_property version for use in environments where multiple threads
137 might concurrently try to access the property.
140 def __init__(self
, ttl
=None):
141 super(threaded_cached_property_with_ttl
, self
).__init
__(ttl
)
142 self
.lock
= threading
.RLock()
144 def __get__(self
, obj
, cls
):
146 return super(threaded_cached_property_with_ttl
, self
).__get
__(obj
, cls
)
149 # Alias to make threaded_cached_property_with_ttl easier to use
150 threaded_cached_property_ttl
= threaded_cached_property_with_ttl
151 timed_threaded_cached_property
= threaded_cached_property_with_ttl