From bcc94354ea45d0a449d73ad5b9473837ad5a8cde Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 19 Jun 2017 22:22:39 +0100 Subject: [PATCH] Fix #553 Ensure SourceMixin descendents shut down the source prior to closing. Furthermore, make sure devices are closed before pin factory shuts down, and that pins have a strong reference to their owning factory (to prevent losing the factory before the pins). --- gpiozero/devices.py | 15 +++++++++++++++ gpiozero/exc.py | 3 +++ gpiozero/mixins.py | 5 ++++- gpiozero/pins/pi.py | 6 +++--- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/gpiozero/devices.py b/gpiozero/devices.py index ed8d37c..4b282d0 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -34,6 +34,7 @@ from .exc import ( GPIOPinInUse, GPIODeviceClosed, PinFactoryFallback, + PinReservationsExist, ) from .compat import frozendict @@ -202,6 +203,20 @@ class Device(ValuesMixin, GPIOBase): @classmethod def _set_pin_factory(cls, new_factory): + reserved_devices = { + dev + for ref_list in cls._reservations.values() + for ref in ref_list + for dev in (ref(),) + if dev is not None + } + if new_factory is None: + for dev in reserved_devices: + dev.close() + elif reserved_devices: + raise PinReservationsExist( + "can't change factory while devices still hold pin " + "reservations (%r)" % dev) if cls._pin_factory is not None: cls._pin_factory.close() cls._pin_factory = new_factory diff --git a/gpiozero/exc.py b/gpiozero/exc.py index 416f1a6..1a3182d 100644 --- a/gpiozero/exc.py +++ b/gpiozero/exc.py @@ -145,6 +145,9 @@ class PinNoPins(PinError, RuntimeError): class PinInvalidPin(PinError, ValueError): "Error raised when an invalid pin specification is provided" +class PinReservationsExist(PinError, RuntimeError): + "Error raised when pin factory is changed while reservations still exist" + class GPIOZeroWarning(Warning): "Base class for all warnings in GPIO Zero" diff --git a/gpiozero/mixins.py b/gpiozero/mixins.py index 794a850..56ed1d5 100644 --- a/gpiozero/mixins.py +++ b/gpiozero/mixins.py @@ -70,10 +70,13 @@ class SourceMixin(object): def close(self): try: - super(SourceMixin, self).close() self.source = None except AttributeError: pass + try: + super(SourceMixin, self).close() + except AttributeError: + pass def _copy_values(self, source): for v in source: diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index 8fa408c..2f88ce3 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -9,10 +9,10 @@ str = type('') import io from threading import RLock from types import MethodType -from weakref import ref, proxy try: - from weakref import WeakMethod + from weakref import ref, WeakMethod except ImportError: + from ..compat import WeakMethod import warnings @@ -216,7 +216,7 @@ class PiPin(Pin): """ def __init__(self, factory, number): super(PiPin, self).__init__() - self._factory = proxy(factory) + self._factory = factory self._when_changed_lock = RLock() self._when_changed = None self._number = number