wrapt 2.2.2rc1__tar.gz → 2.2.2rc3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wrapt-2.2.2rc1/src/wrapt.egg-info → wrapt-2.2.2rc3}/PKG-INFO +1 -1
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/__init__.py +1 -1
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/caching.py +14 -2
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3/src/wrapt.egg-info}/PKG-INFO +1 -1
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_lru_cache.py +155 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/LICENSE +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/MANIFEST.in +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/README.md +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/RELEASE.rst +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/pyproject.toml +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/setup.cfg +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/setup.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/__wrapt__.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/_wrappers.c +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/arguments.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/decorators.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/importer.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/patches.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/proxies.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/signature.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/synchronization.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/weakrefs.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt/wrappers.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt-stubs/__init__.pyi +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt.egg-info/SOURCES.txt +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt.egg-info/dependency_links.txt +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt.egg-info/not-zip-safe +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt.egg-info/requires.txt +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/src/wrapt.egg-info/top_level.txt +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/conftest.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/compat.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/module1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/module2.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_adapter.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_adapter_py3.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_adapter_py33.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_annotations.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_attribute_wrapper.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_auto_object_proxy.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_callable_binding_no_args.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_callable_object_proxy.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_class.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_class_py37.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_copy.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_decorator_state.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_decorators.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_deferred_patching.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_descriptor_get_class_access.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_descriptors_py36.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_enabled_bool_error.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_entry_points.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_formatargspec_py35.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_formatargspec_py38.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_function.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_function_wrapper.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_inheritance_py37.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_inner_classmethod.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_inner_staticmethod.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_inplace_operators.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_instancemethod.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_lazy_object_proxy.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_memoize.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_monkey_patching.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_nested_function.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_object_proxy.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_object_proxy_hook.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_object_proxy_self_dict.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_object_proxy_type_checks.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_outer_classmethod.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_outer_staticmethod.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_pickle.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_post_import_hooks.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_pyerr_clear_propagation.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_resolve_path.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_runtime_type_hints.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_synchronized_async.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_synchronized_lock.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_synchronized_markers.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_type_module_attribute.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_update_attributes.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_weak_function_proxy.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/core/test_with_signature.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_auto_object_proxy_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_auto_object_proxy_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_decorator_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_decorator_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t2.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t2.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t3.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t3.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t4.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t4.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t5.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t5.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t6.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t6.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t7.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t7.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t8.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_cls_t8.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t2.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t2.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t3.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t3.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t4.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t4.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t5.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t5.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t6.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t6.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t7.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_function_wrapper_fn_t7.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_object_proxy_arithmetic_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_object_proxy_arithmetic_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_object_proxy_container_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_object_proxy_container_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_object_proxy_context_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_object_proxy_context_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_partial_callable_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_partial_callable_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_patch_function_wrapper_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_patch_function_wrapper_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_patching_primitives_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_patching_primitives_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_post_import_hooks_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_post_import_hooks_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_synchronized_lock_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_synchronized_lock_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_transient_function_wrapper_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_transient_function_wrapper_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_weak_function_proxy_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_weak_function_proxy_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t1.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t1.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t2.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t2.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t3.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t3.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t4.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t4.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t5.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t5.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t6.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t6.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t7.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t7.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t8.out +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tests/mypy/mypy_wrap_function_wrapper_t8.py +0 -0
- {wrapt-2.2.2rc1 → wrapt-2.2.2rc3}/tox.ini +0 -0
|
@@ -9,7 +9,7 @@ methods a single shared cache is used, matching ``functools.lru_cache``.
|
|
|
9
9
|
from functools import lru_cache as _functools_lru_cache
|
|
10
10
|
from functools import partial
|
|
11
11
|
|
|
12
|
-
from .__wrapt__ import BoundFunctionWrapper, FunctionWrapper
|
|
12
|
+
from .__wrapt__ import BaseObjectProxy, BoundFunctionWrapper, FunctionWrapper
|
|
13
13
|
from .decorators import decorator
|
|
14
14
|
from .synchronization import synchronized
|
|
15
15
|
|
|
@@ -71,7 +71,19 @@ class _BoundLRUCacheFunctionWrapper(BoundFunctionWrapper):
|
|
|
71
71
|
self.__wrapped__
|
|
72
72
|
)
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
# If the instance the method is bound to is a wrapt
|
|
75
|
+
# object proxy, a plain setattr() would fall through and
|
|
76
|
+
# store the cache on the wrapped object rather than the
|
|
77
|
+
# proxy. Use type() rather than isinstance() so the check
|
|
78
|
+
# sees the real proxy type and is not fooled by the proxy
|
|
79
|
+
# overriding __class__ to report the wrapped object's
|
|
80
|
+
# type. Proxies expose __self_setattr__() which stores the
|
|
81
|
+
# attribute on the proxy itself.
|
|
82
|
+
|
|
83
|
+
if issubclass(type(instance), BaseObjectProxy):
|
|
84
|
+
instance.__self_setattr__(cache_attr, cache)
|
|
85
|
+
else:
|
|
86
|
+
setattr(instance, cache_attr, cache)
|
|
75
87
|
|
|
76
88
|
return cache(*args, **kwargs)
|
|
77
89
|
|
|
@@ -267,6 +267,161 @@ class TestStaticMethod(unittest.TestCase):
|
|
|
267
267
|
self.assertEqual(info.misses, 1)
|
|
268
268
|
|
|
269
269
|
|
|
270
|
+
class OverrideBase:
|
|
271
|
+
def __init__(self):
|
|
272
|
+
self.base_calls = 0
|
|
273
|
+
self.derived_calls = 0
|
|
274
|
+
|
|
275
|
+
@wrapt.lru_cache
|
|
276
|
+
def compute(self, x):
|
|
277
|
+
self.base_calls += 1
|
|
278
|
+
return x * 2
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class OverrideDerived(OverrideBase):
|
|
282
|
+
@wrapt.lru_cache
|
|
283
|
+
def compute(self, x):
|
|
284
|
+
self.derived_calls += 1
|
|
285
|
+
return super().compute(x) + 1
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class TestOverriddenMethodWithSuper(unittest.TestCase):
|
|
289
|
+
def test_super_call_returns_correct_result(self):
|
|
290
|
+
obj = OverrideDerived()
|
|
291
|
+
self.assertEqual(obj.compute(10), 21)
|
|
292
|
+
|
|
293
|
+
def test_super_call_does_not_recurse(self):
|
|
294
|
+
# Regression test: a subclass method decorated with lru_cache that
|
|
295
|
+
# called the base method via super() used to recurse forever because
|
|
296
|
+
# the base and derived methods shared a single per-instance cache
|
|
297
|
+
# slot derived from the method name alone.
|
|
298
|
+
obj = OverrideDerived()
|
|
299
|
+
try:
|
|
300
|
+
result = obj.compute(10)
|
|
301
|
+
except RecursionError:
|
|
302
|
+
self.fail("super() call recursed instead of reaching base method")
|
|
303
|
+
self.assertEqual(result, 21)
|
|
304
|
+
|
|
305
|
+
def test_both_bodies_execute_once(self):
|
|
306
|
+
obj = OverrideDerived()
|
|
307
|
+
obj.compute(10)
|
|
308
|
+
self.assertEqual(obj.derived_calls, 1)
|
|
309
|
+
self.assertEqual(obj.base_calls, 1)
|
|
310
|
+
|
|
311
|
+
def test_base_and_derived_cached_independently(self):
|
|
312
|
+
obj = OverrideDerived()
|
|
313
|
+
obj.compute(10)
|
|
314
|
+
obj.compute(10)
|
|
315
|
+
# Second call is served from both caches, so neither body re-runs.
|
|
316
|
+
self.assertEqual(obj.derived_calls, 1)
|
|
317
|
+
self.assertEqual(obj.base_calls, 1)
|
|
318
|
+
info = obj.compute.cache_info()
|
|
319
|
+
self.assertEqual(info.hits, 1)
|
|
320
|
+
self.assertEqual(info.misses, 1)
|
|
321
|
+
|
|
322
|
+
def test_base_class_instance_unaffected(self):
|
|
323
|
+
obj = OverrideBase()
|
|
324
|
+
self.assertEqual(obj.compute(10), 20)
|
|
325
|
+
self.assertEqual(obj.base_calls, 1)
|
|
326
|
+
self.assertEqual(obj.derived_calls, 0)
|
|
327
|
+
|
|
328
|
+
def test_separate_instances_have_separate_caches(self):
|
|
329
|
+
obj1 = OverrideDerived()
|
|
330
|
+
obj2 = OverrideDerived()
|
|
331
|
+
obj1.compute(10)
|
|
332
|
+
obj2.compute(10)
|
|
333
|
+
self.assertEqual(obj1.derived_calls, 1)
|
|
334
|
+
self.assertEqual(obj2.derived_calls, 1)
|
|
335
|
+
self.assertEqual(obj1.base_calls, 1)
|
|
336
|
+
self.assertEqual(obj2.base_calls, 1)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class ProxyWrapped:
|
|
340
|
+
def __init__(self, a):
|
|
341
|
+
self.a = a
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
class ProxyCached(wrapt.ObjectProxy):
|
|
345
|
+
@wrapt.lru_cache
|
|
346
|
+
def compute(self, x):
|
|
347
|
+
return self.a + x
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class ProxyCachedWithState(wrapt.ObjectProxy):
|
|
351
|
+
def __init__(self, wrapped, factor):
|
|
352
|
+
super().__init__(wrapped)
|
|
353
|
+
self._self_factor = factor
|
|
354
|
+
|
|
355
|
+
@wrapt.lru_cache
|
|
356
|
+
def compute(self, x):
|
|
357
|
+
return self._self_factor * x
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class SlottedWrapped:
|
|
361
|
+
__slots__ = ("a",)
|
|
362
|
+
|
|
363
|
+
def __init__(self, a):
|
|
364
|
+
self.a = a
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
class TestObjectProxySubclass(unittest.TestCase):
|
|
368
|
+
def test_returns_correct_result(self):
|
|
369
|
+
obj = ProxyCached(ProxyWrapped(1))
|
|
370
|
+
self.assertEqual(obj.compute(10), 11)
|
|
371
|
+
|
|
372
|
+
def test_caching(self):
|
|
373
|
+
obj = ProxyCached(ProxyWrapped(1))
|
|
374
|
+
obj.compute(10)
|
|
375
|
+
obj.compute(10)
|
|
376
|
+
info = obj.compute.cache_info()
|
|
377
|
+
self.assertEqual(info.hits, 1)
|
|
378
|
+
self.assertEqual(info.misses, 1)
|
|
379
|
+
|
|
380
|
+
def test_cache_not_stored_on_wrapped_object(self):
|
|
381
|
+
wrapped = ProxyWrapped(1)
|
|
382
|
+
obj = ProxyCached(wrapped)
|
|
383
|
+
obj.compute(10)
|
|
384
|
+
cache_attrs = [k for k in vars(wrapped) if k.startswith("_lru_cache_")]
|
|
385
|
+
self.assertEqual(cache_attrs, [])
|
|
386
|
+
|
|
387
|
+
def test_per_proxy_state_not_shared_for_same_wrapped_object(self):
|
|
388
|
+
# Two proxies over the same wrapped object must keep independent
|
|
389
|
+
# per-instance caches keyed to their own proxy state, not a single
|
|
390
|
+
# cache stored on the shared wrapped object.
|
|
391
|
+
wrapped = ProxyWrapped(1)
|
|
392
|
+
obj1 = ProxyCachedWithState(wrapped, 2)
|
|
393
|
+
obj2 = ProxyCachedWithState(wrapped, 10)
|
|
394
|
+
self.assertEqual(obj1.compute(5), 10)
|
|
395
|
+
self.assertEqual(obj2.compute(5), 50)
|
|
396
|
+
|
|
397
|
+
def test_proxy_garbage_collected_with_long_lived_wrapped(self):
|
|
398
|
+
# The cache must be stored on the proxy, not the wrapped object, so
|
|
399
|
+
# a proxy is not kept alive by a wrapped object that outlives it.
|
|
400
|
+
registry = []
|
|
401
|
+
|
|
402
|
+
def make_and_use():
|
|
403
|
+
backing = ProxyWrapped(7)
|
|
404
|
+
registry.append(backing)
|
|
405
|
+
proxy = ProxyCached(backing)
|
|
406
|
+
proxy.compute(4)
|
|
407
|
+
return weakref.ref(proxy)
|
|
408
|
+
|
|
409
|
+
ref = make_and_use()
|
|
410
|
+
gc.collect()
|
|
411
|
+
self.assertIsNone(ref())
|
|
412
|
+
|
|
413
|
+
def test_wrapped_object_without_dict(self):
|
|
414
|
+
# A wrapped object that does not accept arbitrary attributes (for
|
|
415
|
+
# example one using __slots__) must not cause the cache storage to
|
|
416
|
+
# fail, since the cache is stored on the proxy.
|
|
417
|
+
obj = ProxyCached(SlottedWrapped(1))
|
|
418
|
+
self.assertEqual(obj.compute(10), 11)
|
|
419
|
+
self.assertEqual(obj.compute(10), 11)
|
|
420
|
+
info = obj.compute.cache_info()
|
|
421
|
+
self.assertEqual(info.hits, 1)
|
|
422
|
+
self.assertEqual(info.misses, 1)
|
|
423
|
+
|
|
424
|
+
|
|
270
425
|
class TestIntrospection(unittest.TestCase):
|
|
271
426
|
def test_function_name(self):
|
|
272
427
|
self.assertEqual(cached_function.__name__, "cached_function")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|