1 parent
8eea0020b7
commit
be1aac4fac
5 files changed
+91
-9
No files matched your search
@@ -53,7 +53,7 @@ def remove_comment(stream):
|
||||
class Invoice(Model):
|
||||
"EDocument UN/CEFACT Invoice"
|
||||
__name__ = 'edocument.uncefact.invoice'
|
||||
__no_slots__ = True # to work with cached_property
|
||||
__slots__ = ('invoice',)
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
* Support cached_property on object with __slots__
|
||||
* Allow creating indexes concurrently
|
||||
* Allow skipping index creation
|
||||
* Add assert methods to test tools
|
||||
|
||||
@@ -32,7 +32,9 @@ class Model(URLMixin, PoolBase, metaclass=ModelMeta):
|
||||
"""
|
||||
Define a model in Tryton.
|
||||
"""
|
||||
__slots__ = ('_id', '_values', '_init_values', '_removed', '_deleted')
|
||||
__slots__ = (
|
||||
'_id', '_values', '_init_values', '_removed', '_deleted',
|
||||
'__weakref__')
|
||||
_rec_name = 'name'
|
||||
|
||||
id = fields.Integer(lazy_gettext('ir.msg_ID'), readonly=True)
|
||||
|
||||
@@ -12,8 +12,8 @@ import sql
|
||||
import sql.operators
|
||||
|
||||
from trytond.tools import (
|
||||
decimal_, escape_wildcard, file_open, firstline, grouped_slice,
|
||||
is_full_text, is_instance_method, likify, lstrip_wildcard,
|
||||
cached_property, decimal_, escape_wildcard, file_open, firstline,
|
||||
grouped_slice, is_full_text, is_instance_method, likify, lstrip_wildcard,
|
||||
pairwise_longest, reduce_domain, reduce_ids, remove_forbidden_chars,
|
||||
rstrip_wildcard, slugify, sortable_values, strip_wildcard, timezone,
|
||||
unescape_wildcard)
|
||||
@@ -1214,6 +1214,58 @@ class QRCodeTestCase(unittest.TestCase):
|
||||
self.assertIsNotNone(image.getvalue())
|
||||
|
||||
|
||||
class CachedProperty:
|
||||
_count = 0
|
||||
|
||||
def get_count(self):
|
||||
self._count += 1
|
||||
return self._count
|
||||
|
||||
cached_count = cached_property(get_count)
|
||||
|
||||
|
||||
class CachedPropertySlots:
|
||||
__slots__ = ('_count', '__weakref__')
|
||||
|
||||
def __init__(self):
|
||||
self._count = 0
|
||||
|
||||
def get_count(self):
|
||||
self._count += 1
|
||||
return self._count
|
||||
|
||||
cached_count = cached_property(get_count)
|
||||
|
||||
|
||||
class CachedPropertyTestCase(unittest.TestCase):
|
||||
"Test cached_property"
|
||||
|
||||
def test_cached_property_clear(self):
|
||||
"Test clear cached property"
|
||||
item = CachedProperty()
|
||||
|
||||
self.assertEqual(item.cached_count, 1)
|
||||
del item.cached_count
|
||||
self.assertEqual(item.cached_count, 2)
|
||||
|
||||
def test_cached_property_with_slots(self):
|
||||
"Test cached property with slots"
|
||||
item = CachedPropertySlots()
|
||||
|
||||
self.assertEqual(item.cached_count, 1)
|
||||
self.assertEqual(item.cached_count, 1)
|
||||
self.assertEqual(item.get_count(), 2)
|
||||
self.assertEqual(item.cached_count, 1)
|
||||
|
||||
def test_cached_property_with_slots_clear(self):
|
||||
"Test clear cached property with slots"
|
||||
item = CachedPropertySlots()
|
||||
|
||||
self.assertEqual(item.cached_count, 1)
|
||||
del item.cached_count
|
||||
self.assertEqual(item.cached_count, 2)
|
||||
|
||||
|
||||
def load_tests(loader, tests, pattern):
|
||||
tests.addTest(doctest.DocTestSuite(decimal_))
|
||||
return tests
|
||||
@@ -1,11 +1,8 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import posixpath
|
||||
|
||||
try:
|
||||
from functools import cached_property
|
||||
except ImportError:
|
||||
from werkzeug.utils import cached_property
|
||||
from functools import cached_property
|
||||
from weakref import WeakKeyDictionary
|
||||
|
||||
try:
|
||||
from werkzeug.security import safe_join
|
||||
@@ -21,6 +18,36 @@ from .misc import (
|
||||
rstrip_wildcard, slugify, sortable_values, sql_pairing, strip_wildcard,
|
||||
unescape_wildcard)
|
||||
|
||||
_NOT_FOUND = object()
|
||||
|
||||
|
||||
class cached_property(cached_property):
|
||||
_cache = None
|
||||
|
||||
def __get__(self, instance, owner=None):
|
||||
if instance is None:
|
||||
return self
|
||||
cache = getattr(instance, '__dict__', None)
|
||||
if cache is None: # __slots__
|
||||
if self._cache is None:
|
||||
self._cache = WeakKeyDictionary()
|
||||
val = self._cache.get(instance, _NOT_FOUND)
|
||||
if val is _NOT_FOUND:
|
||||
self._cache[instance] = val = self.func(instance)
|
||||
return val
|
||||
else:
|
||||
return super().__get__(instance, owner)
|
||||
|
||||
def __delete__(self, instance):
|
||||
cache = getattr(instance, '__dict__', None)
|
||||
try:
|
||||
if cache:
|
||||
del cache[self.attrname]
|
||||
elif self._cache:
|
||||
del self._cache[instance]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
class ClassProperty(property):
|
||||
def __get__(self, cls, owner):
|
||||
|
||||
Reference in new issue
Block a user