1 # -*- coding: utf-8 -*-
3 __author__
= "Daniel Greenfeld"
4 __email__
= "pydanny@gmail.com"
8 from functools
import wraps
14 except (ImportError, SyntaxError):
18 class cached_property(object):
20 A property that is only computed once per instance and then replaces itself
21 with an ordinary attribute. Deleting the attribute resets the property.
22 Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
25 def __init__(self
, func
):
26 self
.__doc
__ = getattr(func
, "__doc__")
29 def __get__(self
, obj
, cls
):
33 if asyncio
and asyncio
.iscoroutinefunction(self
.func
):
34 return self
._wrap
_in
_coroutine
(obj
)
36 value
= obj
.__dict
__[self
.func
.__name
__] = self
.func(obj
)
39 def _wrap_in_coroutine(self
, obj
):
43 future
= asyncio
.ensure_future(self
.func(obj
))
44 obj
.__dict
__[self
.func
.__name
__] = future
50 class threaded_cached_property(object):
52 A cached_property version for use in environments where multiple threads
53 might concurrently try to access the property.
56 def __init__(self
, func
):
57 self
.__doc
__ = getattr(func
, "__doc__")
59 self
.lock
= threading
.RLock()
61 def __get__(self
, obj
, cls
):
65 obj_dict
= obj
.__dict
__
66 name
= self
.func
.__name
__
69 # check if the value was computed before the lock was acquired
73 # if not, do the calculation and release the lock
74 return obj_dict
.setdefault(name
, self
.func(obj
))
77 class cached_property_with_ttl(object):
79 A property that is only computed once per instance and then replaces itself
80 with an ordinary attribute. Setting the ttl to a number expresses how long
81 the property will last before being timed out.
84 def __init__(self
, ttl
=None):
91 self
._prepare
_func
(func
)
93 def __call__(self
, func
):
94 self
._prepare
_func
(func
)
97 def __get__(self
, obj
, cls
):
102 obj_dict
= obj
.__dict
__
105 value
, last_updated
= obj_dict
[name
]
109 ttl_expired
= self
.ttl
and self
.ttl
< now
- last_updated
113 value
= self
.func(obj
)
114 obj_dict
[name
] = (value
, now
)
117 def __delete__(self
, obj
):
118 obj
.__dict
__.pop(self
.__name
__, None)
120 def __set__(self
, obj
, value
):
121 obj
.__dict
__[self
.__name
__] = (value
, time())
123 def _prepare_func(self
, func
):
126 self
.__doc
__ = func
.__doc
__
127 self
.__name
__ = func
.__name
__
128 self
.__module
__ = func
.__module
__
131 # Aliases to make cached_property_with_ttl easier to use
132 cached_property_ttl
= cached_property_with_ttl
133 timed_cached_property
= cached_property_with_ttl
136 class threaded_cached_property_with_ttl(cached_property_with_ttl
):
138 A cached_property version for use in environments where multiple threads
139 might concurrently try to access the property.
142 def __init__(self
, ttl
=None):
143 super(threaded_cached_property_with_ttl
, self
).__init
__(ttl
)
144 self
.lock
= threading
.RLock()
146 def __get__(self
, obj
, cls
):
148 return super(threaded_cached_property_with_ttl
, self
).__get
__(obj
, cls
)
151 # Alias to make threaded_cached_property_with_ttl easier to use
152 threaded_cached_property_ttl
= threaded_cached_property_with_ttl
153 timed_threaded_cached_property
= threaded_cached_property_with_ttl