From b81d9ed875090d39606ff22fff3b1eb3cdf46197 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 22 Sep 2015 22:07:30 +0100 Subject: [PATCH 1/2] Fix missing comma in __init__ --- gpiozero/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gpiozero/__init__.py b/gpiozero/__init__.py index 9ff5f69..61e54dc 100644 --- a/gpiozero/__init__.py +++ b/gpiozero/__init__.py @@ -26,9 +26,9 @@ from .output_devices import ( ) from .boards import ( TrafficLights, - PiTraffic + PiTraffic, FishDish, - TrafficHat + TrafficHat, PiLiter, ) From 5c12d8c2e0b048579601d3518de6eb96ce109edd Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 22 Sep 2015 23:03:01 +0100 Subject: [PATCH 2/2] Flexible events Permit event callbacks to accept no parameters, or a single parameter providing the source input object --- gpiozero/input_devices.py | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/gpiozero/input_devices.py b/gpiozero/input_devices.py index 79bd6b4..5dd3a28 100644 --- a/gpiozero/input_devices.py +++ b/gpiozero/input_devices.py @@ -1,5 +1,7 @@ from __future__ import division +import inspect +from functools import wraps from time import sleep, time from threading import Event @@ -54,21 +56,42 @@ class WaitableInputDevice(InputDevice): return self._when_activated def _set_when_activated(self, value): - if not callable(value) and value is not None: - raise InputDeviceError('value must be None or a function') - self._when_activated = value + self._when_activated = self._wrap_callback(value) + when_activated = property(_get_when_activated, _set_when_activated) def _get_when_deactivated(self): return self._when_deactivated def _set_when_deactivated(self, value): - if not callable(value) and value is not None: - raise InputDeviceError('value must be None or a function') - self._when_deactivated = value + self._when_deactivated = self._wrap_callback(value) when_deactivated = property(_get_when_deactivated, _set_when_deactivated) + def _wrap_callback(self, fn): + if fn is None: + return None + elif not callable(fn): + raise InputDeviceError('value must be None or a callable') + else: + # Try binding ourselves to the argspec of the provided callable. + # If this works, assume the function is capable of accepting us + # as the only (mandatory) parameter. + try: + inspect.getcallargs(fn, self) + @wraps(fn) + def wrapper(): + return fn(self) + return wrapper + except TypeError: + try: + inspect.getcallargs(fn) + return fn + except TypeError: + raise InputDeviceError( + 'value must be a callable which accepts up to one ' + 'mandatory parameter') + def _fire_events(self): old_state = self._last_state new_state = self._last_state = self.is_active