Added keyword args to MockFactory.pin

And a few other last minute fixes
This commit is contained in:
Dave Jones
2016-10-23 15:29:55 +01:00
parent 2ecc25f995
commit 945bea4e54
8 changed files with 75 additions and 21 deletions

View File

@@ -154,6 +154,22 @@ Base classes
.. autoclass:: SPI .. autoclass:: SPI
:members: :members:
.. currentmodule:: gpiozero.pins.pi
.. autoclass:: PiFactory
:members:
.. autoclass:: PiPin
:members:
.. currentmodule:: gpiozero.pins.local
.. autoclass:: LocalPiFactory
:members:
.. autoclass:: LocalPiPin
:members:
Utilities Utilities
========= =========
@@ -164,6 +180,8 @@ non-physical pins are used, or to raise exceptions when pull-downs are
requested on pins with physical pull-up resistors attached. The following requested on pins with physical pull-up resistors attached. The following
functions and classes can be used to query this database: functions and classes can be used to query this database:
.. currentmodule:: gpiozero
.. autofunction:: pi_info .. autofunction:: pi_info
.. autoclass:: PiBoardInfo .. autoclass:: PiBoardInfo

View File

@@ -25,8 +25,10 @@ from ..exc import DeviceClosed, PinUnknownPi, SPIInvalidClockMode
class LocalPiFactory(PiFactory): class LocalPiFactory(PiFactory):
""" """
Abstract base class representing pins attached locally to a Pi. This forms Abstract base class representing pins attached locally to a Pi. This forms
the base class for local-only pin interfaces (:class:`RPiGPIOPin`, the base class for local-only pin interfaces
:class:`RPIOPin`, and :class:`NativePin`). (:class:`~gpiozero.pins.rpigpio.RPiGPIOPin`,
:class:`~gpiozero.pins.rpio.RPIOPin`, and
:class:`~gpiozero.pins.native.NativePin`).
""" """
pins = {} pins = {}

View File

@@ -161,9 +161,9 @@ class MockConnectedPin(MockPin):
mock pin. This is used in the "real pins" portion of the test suite to mock pin. This is used in the "real pins" portion of the test suite to
check that one pin can influence another. check that one pin can influence another.
""" """
def __init__(self, factory, number): def __init__(self, factory, number, input_pin=None):
super(MockConnectedPin, self).__init__(factory, number) super(MockConnectedPin, self).__init__(factory, number)
self.input_pin = None self.input_pin = input_pin
def _change_state(self, value): def _change_state(self, value):
if self.input_pin: if self.input_pin:
@@ -181,9 +181,9 @@ class MockChargingPin(MockPin):
(as if attached to, e.g. a typical circuit using an LDR and a capacitor (as if attached to, e.g. a typical circuit using an LDR and a capacitor
to time the charging rate). to time the charging rate).
""" """
def __init__(self, factory, number): def __init__(self, factory, number, charge_time=0.01):
super(MockChargingPin, self).__init__(factory, number) super(MockChargingPin, self).__init__(factory, number)
self.charge_time = 0.01 # dark charging time self.charge_time = charge_time # dark charging time
self._charge_stop = Event() self._charge_stop = Event()
self._charge_thread = None self._charge_thread = None
@@ -220,10 +220,10 @@ class MockTriggerPin(MockPin):
corresponding pin instance. When this pin is driven high it will trigger corresponding pin instance. When this pin is driven high it will trigger
the echo pin to drive high for the echo time. the echo pin to drive high for the echo time.
""" """
def __init__(self, factory, number): def __init__(self, factory, number, echo_pin=None, echo_time=0.04):
super(MockTriggerPin, self).__init__(factory, number) super(MockTriggerPin, self).__init__(factory, number)
self.echo_pin = None self.echo_pin = echo_pin
self.echo_time = 0.04 # longest echo time self.echo_time = echo_time # longest echo time
self._echo_thread = None self._echo_thread = None
def _set_state(self, value): def _set_state(self, value):
@@ -432,14 +432,14 @@ class MockFactory(LocalPiFactory):
def reset(self): def reset(self):
self.pins.clear() self.pins.clear()
def pin(self, spec, pin_class=None): def pin(self, spec, pin_class=None, **kwargs):
if pin_class is None: if pin_class is None:
pin_class = self.pin_class pin_class = self.pin_class
n = self._to_gpio(spec) n = self._to_gpio(spec)
try: try:
pin = self.pins[n] pin = self.pins[n]
except KeyError: except KeyError:
pin = pin_class(self, n) pin = pin_class(self, n, **kwargs)
self.pins[n] = pin self.pins[n] = pin
else: else:
# Ensure the pin class expected supports PWM (or not) # Ensure the pin class expected supports PWM (or not)

View File

@@ -34,7 +34,7 @@ from ..exc import (
class PiFactory(Factory): class PiFactory(Factory):
""" """
Abstract base class representing hardware attached to a Raspberry Pi. This Abstract base class representing hardware attached to a Raspberry Pi. This
forms the base of :class:`LocalPiFactory`. forms the base of :class:`~gpiozero.pins.local.LocalPiFactory`.
""" """
def __init__(self): def __init__(self):
self._info = None self._info = None
@@ -187,7 +187,31 @@ class PiFactory(Factory):
class PiPin(Pin): class PiPin(Pin):
""" """
Abstract base class representing a multi-function GPIO pin attached to a Abstract base class representing a multi-function GPIO pin attached to a
Raspberry Pi. Raspberry Pi. This overrides several methods in the abstract base
:class:`~gpiozero.Pin`. Descendents must override the following methods:
* :meth:`_get_function`
* :meth:`_set_function`
* :meth:`_get_state`
* :meth:`_call_when_changed`
* :meth:`_enable_event_detect`
* :meth:`_disable_event_detect`
Descendents *may* additionally override the following methods, if
applicable:
* :meth:`close`
* :meth:`output_with_state`
* :meth:`input_with_pull`
* :meth:`_set_state`
* :meth:`_get_frequency`
* :meth:`_set_frequency`
* :meth:`_get_pull`
* :meth:`_set_pull`
* :meth:`_get_bounce`
* :meth:`_set_bounce`
* :meth:`_get_edges`
* :meth:`_set_edges`
""" """
def __init__(self, factory, number): def __init__(self, factory, number):
super(PiPin, self).__init__() super(PiPin, self).__init__()
@@ -214,6 +238,11 @@ class PiPin(Pin):
return self.factory.address + ('GPIO%d' % self.number,) return self.factory.address + ('GPIO%d' % self.number,)
def _call_when_changed(self): def _call_when_changed(self):
"""
Called to fire the :attr:`when_changed` event handler; override this
in descendents if additional (currently redundant) parameters need
to be passed.
"""
method = self.when_changed() method = self.when_changed()
if method is None: if method is None:
self.when_changed = None self.when_changed = None
@@ -242,8 +271,17 @@ class PiPin(Pin):
self._enable_event_detect() self._enable_event_detect()
def _enable_event_detect(self): def _enable_event_detect(self):
"""
Enables event detection. This is called to activate event detection on
pin :attr:`number`, watching for the specified :attr:`edges`. In
response, :meth:`_call_when_changed` should be executed.
"""
raise NotImplementedError raise NotImplementedError
def _disable_event_detect(self): def _disable_event_detect(self):
"""
Disables event detection. This is called to deactivate event detection
on pin :attr:`number`.
"""
raise NotImplementedError raise NotImplementedError

View File

@@ -171,9 +171,7 @@ def test_input_light_sensor():
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_input_distance_sensor(): def test_input_distance_sensor():
echo_pin = Device._pin_factory.pin(4) echo_pin = Device._pin_factory.pin(4)
trig_pin = Device._pin_factory.pin(5, pin_class=MockTriggerPin) trig_pin = Device._pin_factory.pin(5, pin_class=MockTriggerPin, echo_pin=echo_pin, echo_time=0.02)
trig_pin.echo_pin = echo_pin
trig_pin.echo_time = 0.02
with pytest.raises(ValueError): with pytest.raises(ValueError):
DistanceSensor(echo_pin, trig_pin, max_distance=-1) DistanceSensor(echo_pin, trig_pin, max_distance=-1)
# normal queue len is large (because the sensor is *really* jittery) but # normal queue len is large (because the sensor is *really* jittery) but

View File

@@ -85,15 +85,13 @@ def pins(request, pin_factory):
# Why return both pins in a single fixture? If we defined one fixture for # Why return both pins in a single fixture? If we defined one fixture for
# each pin then pytest will (correctly) test RPiGPIOPin(22) against # each pin then pytest will (correctly) test RPiGPIOPin(22) against
# NativePin(27) and so on. This isn't supported, so we don't test it # NativePin(27) and so on. This isn't supported, so we don't test it
if pin_factory.__class__.__name__ == 'MockFactory':
test_pin = pin_factory.pin(TEST_PIN, pin_class=MockConnectedPin)
else:
test_pin = pin_factory.pin(TEST_PIN)
input_pin = pin_factory.pin(INPUT_PIN) input_pin = pin_factory.pin(INPUT_PIN)
input_pin.function = 'input' input_pin.function = 'input'
input_pin.pull = 'down' input_pin.pull = 'down'
if pin_factory.__class__.__name__ == 'MockFactory': if pin_factory.__class__.__name__ == 'MockFactory':
test_pin.input_pin = input_pin test_pin = pin_factory.pin(TEST_PIN, pin_class=MockConnectedPin, input_pin=input_pin)
else:
test_pin = pin_factory.pin(TEST_PIN)
def fin(): def fin():
test_pin.close() test_pin.close()
input_pin.close() input_pin.close()