Skip to content

Commit

Permalink
Merge pull request #5856 from pythonic64/fix_alias_property_to_use_ca…
Browse files Browse the repository at this point in the history
…ched_value

Update AliasProperty to cache value only if "cache" argument is set to True
  • Loading branch information
KeyWeeUsr committed Nov 17, 2018
2 parents 083473b + 5559faa commit 372b819
Show file tree
Hide file tree
Showing 2 changed files with 364 additions and 111 deletions.
60 changes: 46 additions & 14 deletions kivy/properties.pyx
Expand Up @@ -1384,27 +1384,47 @@ cdef class AliasProperty(Property):
If you don't find a Property class that fits to your needs, you can make
your own by creating custom Python getter and setter methods.
Example from kivy/uix/widget.py::
Example from kivy/uix/widget.py where `x` and `width` are instances of
:class:`NumericProperty`::
def get_right(self):
return self.x + self.width
def set_right(self, value):
self.x = value - self.width
right = AliasProperty(get_right, set_right, bind=['x', 'width'])
If `x` were to be an instance level attribute and not Kivy property then
you have to return `True` from setter to dispatch value of `right`::
def set_right(self, value):
self.x = value - self.width
return True
If your want to cache the value returned by getter then pass `cache=True`.
This way getter will only be called if new value is set or one of the
binded properties changes. In both cases new value of alias property will
be cached again.
To make property readonly pass `None` as setter. This way `AttributeError`
will be raised on every set attempt::
right = AliasProperty(get_right, None, bind=['x', 'width'], cache=True)
:Parameters:
`getter`: function
Function to use as a property getter
Function to use as a property getter.
`setter`: function
Function to use as a property setter. Properties listening to the
alias property won't be updated when the property is set (e.g.
`right = 10`), unless the `setter` returns `True`.
Function to use as a property setter. Callbacks bound to the
alias property won't be called when the property is set (e.g.
`right = 10`), unless the setter returns `True`.
`bind`: list/tuple
Properties to observe for changes, as property name strings
Properties to observe for changes, as property name strings.
Changing values of this properties will dispatch value of the
alias property.
`cache`: boolean
If True, the value will be cached, until one of the binded elements
will changes
`rebind`: bool, defaults to False
If `True`, the value will be cached, until one of the binded
elements changes or if setter returns `True`.
`rebind`: bool, defaults to `False`
See :class:`ObjectProperty` for details.
.. versionchanged:: 1.9.0
Expand All @@ -1430,7 +1450,12 @@ cdef class AliasProperty(Property):
self.use_cache = 1

def __read_only(self, _obj, _value):
raise AttributeError('property is read-only')
raise AttributeError(
'"{}.{}" property is readonly'.format(
type(_obj).__name__,
self._name
)
)

cdef init_storage(self, EventDispatcher obj, PropertyStorage storage):
Property.init_storage(self, obj, storage)
Expand All @@ -1446,10 +1471,11 @@ cdef class AliasProperty(Property):

cpdef trigger_change(self, EventDispatcher obj, value):
cdef PropertyStorage ps = obj.__storage[self._name]
ps.alias_initial = 0
dvalue = ps.getter(obj)
if ps.value != dvalue:
ps.value = dvalue
if self.use_cache:
ps.alias_initial = 0
ps.value = dvalue
self.dispatch(obj)

cdef check(self, EventDispatcher obj, value):
Expand All @@ -1459,14 +1485,20 @@ cdef class AliasProperty(Property):
cdef PropertyStorage ps = obj.__storage[self._name]
if self.use_cache:
if ps.alias_initial:
return ps.getter(obj)
ps.alias_initial = 0
ps.value = ps.getter(obj)
return ps.value
return ps.getter(obj)

cpdef set(self, EventDispatcher obj, value):
cdef PropertyStorage ps = obj.__storage[self._name]
if ps.setter(obj, value):
ps.value = self.get(obj)
if self.use_cache:
if ps.alias_initial:
ps.alias_initial = 0
ps.value = ps.getter(obj)
self.dispatch(obj)
elif self.force_dispatch:
self.dispatch(obj)

cpdef dispatch(self, EventDispatcher obj):
Expand Down

0 comments on commit 372b819

Please sign in to comment.