mirror of
https://github.com/KevinMidboe/python-gpiozero.git
synced 2026-01-30 13:17:01 +00:00
Rework when_changed attribute to use weakrefs
Some fairly major changes to ensure that the Pin.when_changed property doesn't keep references to the objects owning the callbacks that are assigned. This is vaguely tricky given that ordinary weakref's can't be used with bound methods (which are ephemeral), so I've back-ported weakref.WeakMethod from Py3.4. This solves a whole pile of things like Button instances not disappearing when they're deleted, and makes composite devices containing Buttons much easier to construct as we don't need to worry about partially constructed things not getting deleted.
This commit is contained in:
@@ -7,7 +7,12 @@ from __future__ import (
|
||||
str = type('')
|
||||
|
||||
import io
|
||||
import weakref
|
||||
from threading import RLock
|
||||
from weakref import ref, proxy
|
||||
try:
|
||||
from weakref import WeakMethod
|
||||
except ImportError:
|
||||
from .compat import WeakMethod
|
||||
import warnings
|
||||
|
||||
try:
|
||||
@@ -186,7 +191,9 @@ class PiPin(Pin):
|
||||
"""
|
||||
def __init__(self, factory, number):
|
||||
super(PiPin, self).__init__()
|
||||
self._factory = weakref.proxy(factory)
|
||||
self._factory = proxy(factory)
|
||||
self._when_changed_lock = RLock()
|
||||
self._when_changed = None
|
||||
self._number = number
|
||||
try:
|
||||
factory.pi_info.physical_pin(self.address[-1])
|
||||
@@ -206,3 +213,39 @@ class PiPin(Pin):
|
||||
def _get_address(self):
|
||||
return self.factory.address + ('GPIO%d' % self.number,)
|
||||
|
||||
def _call_when_changed(self):
|
||||
method = self.when_changed()
|
||||
if method is None:
|
||||
self.when_changed = None
|
||||
else:
|
||||
method()
|
||||
|
||||
def _get_when_changed(self):
|
||||
return self._when_changed
|
||||
|
||||
def _set_when_changed(self, value):
|
||||
# Have to take care, if value is either a closure or a bound method,
|
||||
# not to keep a strong reference to the containing object
|
||||
with self._when_changed_lock:
|
||||
if self._when_changed is None and value is not None:
|
||||
if isinstance(value, MethodType):
|
||||
self._when_changed = WeakMethod(value)
|
||||
else:
|
||||
self._when_changed = ref(value)
|
||||
self._enable_event_detect()
|
||||
elif self._when_changed is not None and value is None:
|
||||
self._disable_event_detect()
|
||||
self._when_changed = None
|
||||
elif value is None:
|
||||
self._when_changed = None
|
||||
elif isinstance(value, MethodType):
|
||||
self._when_changed = WeakMethod(value)
|
||||
else:
|
||||
self._when_changed = ref(value)
|
||||
|
||||
def _enable_event_detect(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def _disable_event_detect(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
Reference in New Issue
Block a user