From c820636fcba5e6e95cf938760c357ba86cf8f4fc Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 4 Jul 2017 00:26:41 +0100 Subject: [PATCH] Fix #279 once and for all (ha! ;) This implements the proposal discussed in the re-opened #279 to add a pin_factory argument at the device level and remove the ability to specify a pin instance to device constructors (they now only accept a pin specification). Note: there's still a couple of bits to tidy up (tests on "real" Pis, and pin_factory.release_all needs refinement) but the test suite is now at least capable of passing on a PC. --- gpiozero/devices.py | 99 +++---------- gpiozero/pins/__init__.py | 99 +++++++------ gpiozero/pins/local.py | 40 ++--- gpiozero/pins/mock.py | 8 +- gpiozero/pins/native.py | 6 +- gpiozero/pins/pi.py | 18 +-- gpiozero/pins/pigpio.py | 45 +++--- gpiozero/pins/rpigpio.py | 2 +- gpiozero/pins/rpio.py | 2 +- tests/test_boards.py | 85 ++++++----- tests/test_devices.py | 6 +- tests/test_inputs.py | 37 +++-- tests/test_outputs.py | 304 ++++++++++++++++++++++---------------- tests/test_spi.py | 48 +++--- 14 files changed, 396 insertions(+), 403 deletions(-) diff --git a/gpiozero/devices.py b/gpiozero/devices.py index 346c677..1a1c687 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -11,7 +11,7 @@ import os import atexit import weakref import warnings -from collections import namedtuple, defaultdict +from collections import namedtuple from itertools import chain from types import FunctionType from threading import Lock @@ -194,77 +194,21 @@ class Device(ValuesMixin, GPIOBase): property, the :attr:`value` property, and the :meth:`close` method). """ pin_factory = None # instance of a Factory sub-class - _reservations = defaultdict(list) # maps pin addresses to lists of devices - _res_lock = Lock() + + def __init__(self, **kwargs): + # Force pin_factory to be keyword-only, even in Python 2 + self.pin_factory = kwargs.pop('pin_factory', Device.pin_factory) + if kwargs: + raise TypeError("Device.__init__() got unexpected keyword " + "argument '%s'" % kwargs.popitem()[0]) + super(Device, self).__init__() def __repr__(self): return "" % (self.__class__.__name__) - def _reserve_pins(self, *pins_or_addresses): - """ - Called to indicate that the device reserves the right to use the - specified *pins_or_addresses*. This should be done during device - construction. If pins are reserved, you must ensure that the - reservation is released by eventually called :meth:`_release_pins`. - - The *pins_or_addresses* can be actual :class:`Pin` instances or the - addresses of pin instances (each address is a tuple of strings). The - latter form is permitted to ensure that devices do not have to - construct :class:`Pin` objects to reserve pins. This is important as - constructing a pin often configures it (e.g. as an input) which - conflicts with alternate pin functions like SPI. - """ - addresses = ( - p.address if isinstance(p, Pin) else p - for p in pins_or_addresses - ) - with Device._res_lock: - for address in addresses: - for device_ref in Device._reservations[address]: - device = device_ref() - if device is not None and self._conflicts_with(device): - raise GPIOPinInUse( - 'pin %s is already in use by %r' % ( - '/'.join(address), device) - ) - Device._reservations[address].append(weakref.ref(self)) - - def _release_pins(self, *pins_or_addresses): - """ - Releases the reservation of this device against *pins_or_addresses*. - This is typically called during :meth:`close` to clean up reservations - taken during construction. Releasing a reservation that is not - currently held will be silently ignored (to permit clean-up after - failed / partial construction). - """ - addresses = ( - p.address if isinstance(p, Pin) else p - for p in pins_or_addresses - ) - with Device._res_lock: - for address in addresses: - Device._reservations[address] = [ - ref for ref in Device._reservations[address] - if ref() not in (self, None) # may as well clean up dead refs - ] - - def _release_all(self): - """ - Releases all pin reservations taken out by this device. See - :meth:`_release_pins` for further information). - """ - with Device._res_lock: - Device._reservations = defaultdict(list, { - address: [ - ref for ref in conflictors - if ref() not in (self, None) - ] - for address, conflictors in Device._reservations.items() - }) - def _conflicts_with(self, other): """ - Called by :meth:`_reserve_pin` to test whether the *other* + Called by :meth:`Factory.reserve_pins` to test whether the *other* :class:`Device` using a common pin conflicts with this device's intent to use it. The default is ``True`` indicating that all devices conflict with common pins. Sub-classes may override this to permit more nuanced @@ -315,6 +259,7 @@ class CompositeDevice(Device): self._named = frozendict({}) self._namedtuple = None self._order = kwargs.pop('_order', None) + pin_factory = kwargs.pop('pin_factory', None) try: if self._order is None: self._order = sorted(kwargs.keys()) @@ -336,7 +281,8 @@ class CompositeDevice(Device): dev.close() raise self._all = args + tuple(kwargs[v] for v in self._order) - super(CompositeDevice, self).__init__() + kwargs = {'pin_factory': pin_factory} if pin_factory is not None else {} + super(CompositeDevice, self).__init__(**kwargs) def __getattr__(self, name): # if _named doesn't exist yet, pretend it's an empty dict @@ -412,20 +358,17 @@ class GPIODevice(Device): this is ``None``, :exc:`GPIOPinMissing` will be raised. If the pin is already in use by another device, :exc:`GPIOPinInUse` will be raised. """ - def __init__(self, pin=None): - super(GPIODevice, self).__init__() + def __init__(self, pin=None, **kwargs): + super(GPIODevice, self).__init__(**kwargs) # self._pin must be set before any possible exceptions can be raised # because it's accessed in __del__. However, it mustn't be given the # value of pin until we've verified that it isn't already allocated self._pin = None if pin is None: raise GPIOPinMissing('No pin given') - if isinstance(pin, Pin): - self._reserve_pins(pin) - else: - # Check you can reserve *before* constructing the pin - self._reserve_pins(Device.pin_factory.pin_address(pin)) - pin = Device.pin_factory.pin(pin) + # Check you can reserve *before* constructing the pin + self.pin_factory.reserve_pins(self, pin) + pin = self.pin_factory.pin(pin) self._pin = pin self._active_state = True self._inactive_state = False @@ -443,7 +386,7 @@ class GPIODevice(Device): def close(self): super(GPIODevice, self).close() if self._pin is not None: - self._release_pins(self._pin) + self.pin_factory.release_pins(self, self._pin.number) self._pin.close() self._pin = None @@ -512,10 +455,10 @@ def _default_pin_factory(name=os.getenv('GPIOZERO_PIN_FACTORY', None)): def _devices_shutdown(): if Device.pin_factory: - with Device._res_lock: + with Device.pin_factory._res_lock: reserved_devices = { dev - for ref_list in Device._reservations.values() + for ref_list in Device.pin_factory._reservations.values() for ref in ref_list for dev in (ref(),) if dev is not None diff --git a/gpiozero/pins/__init__.py b/gpiozero/pins/__init__.py index 60d325c..83ebc0c 100644 --- a/gpiozero/pins/__init__.py +++ b/gpiozero/pins/__init__.py @@ -8,6 +8,10 @@ from __future__ import ( ) str = type('') +from weakref import ref +from collections import defaultdict +from threading import Lock + from ..exc import ( PinInvalidFunction, PinSetInput, @@ -20,6 +24,7 @@ from ..exc import ( SPIFixedBitOrder, SPIFixedSelect, SPIFixedWordSize, + GPIOPinInUse, ) @@ -36,10 +41,61 @@ class Factory(object): applicable: * :meth:`close` + * :meth:`reserve_pins` + * :meth:`release_pins` + * :meth:`release_all` * :meth:`pin` * :meth:`spi` * :meth:`_get_pi_info` """ + def __init__(self): + self._reservations = defaultdict(list) + self._res_lock = Lock() + + def reserve_pins(self, requester, *pins): + """ + Called to indicate that the device reserves the right to use the + specified *pins*. This should be done during device construction. If + pins are reserved, you must ensure that the reservation is released by + eventually called :meth:`release_pins`. + """ + with self._res_lock: + for pin in pins: + for reserver_ref in self._reservations[pin]: + reserver = reserver_ref() + if reserver is not None and requester._conflicts_with(reserver): + raise GPIOPinInUse('pin %s is already in use by %r' % + (pin, reserver)) + self._reservations[pin].append(ref(requester)) + + def release_pins(self, reserver, *pins): + """ + Releases the reservation of *reserver* against *pins*. This is + typically called during :meth:`Device.close` to clean up reservations + taken during construction. Releasing a reservation that is not currently + held will be silently ignored (to permit clean-up after failed / partial + construction). + """ + with self._res_lock: + for pin in pins: + self._reservations[pin] = [ + ref for ref in self._reservations[pin] + if ref() not in (reserver, None) # may as well clean up dead refs + ] + + def release_all(self, reserver): + """ + Releases all pin reservations taken out by *reserver*. See + :meth:`release_pins` for further information). + """ + with self._res_lock: + self._reservations = defaultdict(list, { + pin: [ + ref for ref in conflictors + if ref() not in (reserver, None) + ] + for pin, conflictors in self._reservations.items() + }) def close(self): """ @@ -63,19 +119,6 @@ class Factory(object): """ raise PinUnsupported("Individual pins are not supported by this pin factory") - def pin_address(self, spec): - """ - Returns the address that a pin *would* have if constructed from the - given *spec*. - - This unusual method is used by the pin reservation system to check - for conflicts *prior* to pin construction; with most implementations, - pin construction implicitly alters the state of the pin (e.g. setting - it to an input). This allows pin reservation to take place without - affecting the state of other components. - """ - raise NotImplementedError - def spi(self, **spi_args): """ Returns an instance of an :class:`SPI` interface, for the specified SPI @@ -89,21 +132,6 @@ class Factory(object): def _get_address(self): raise NotImplementedError - address = property( - lambda self: self._get_address(), - doc="""\ - Returns a tuple of strings representing the address of the factory. - For the Pi itself this is a tuple of one string representing the Pi's - address (e.g. "localhost"). Expander chips can return a tuple appending - whatever string they require to uniquely identify the expander chip - amongst all factories in the system. - - .. note:: - - This property *must* return an immutable object capable of being - used as a dictionary key. - """) - def _get_pi_info(self): return None @@ -128,7 +156,6 @@ class Pin(object): represent the capabilities of pins. Descendents *must* override the following methods: - * :meth:`_get_address` * :meth:`_get_function` * :meth:`_set_function` * :meth:`_get_state` @@ -153,7 +180,7 @@ class Pin(object): """ def __repr__(self): - return self.address[-1] + return "" def close(self): """ @@ -195,18 +222,6 @@ class Pin(object): self.function = 'input' self.pull = pull - def _get_address(self): - raise NotImplementedError - - address = property( - lambda self: self._get_address(), - doc="""\ - The address of the pin. This property is a tuple of strings constructed - from the owning factory's address with the unique address of the pin - appended to it. The tuple as a whole uniquely identifies the pin - amongst all pins attached to the system. - """) - def _get_function(self): return "input" diff --git a/gpiozero/pins/local.py b/gpiozero/pins/local.py index 9121dac..65dbcf6 100644 --- a/gpiozero/pins/local.py +++ b/gpiozero/pins/local.py @@ -8,6 +8,8 @@ str = type('') import io import warnings +from collections import defaultdict +from threading import Lock try: from spidev import SpiDev @@ -31,6 +33,8 @@ class LocalPiFactory(PiFactory): :class:`~gpiozero.pins.native.NativePin`). """ pins = {} + _reservations = defaultdict(list) + _res_lock = Lock() def __init__(self): super(LocalPiFactory, self).__init__() @@ -40,14 +44,13 @@ class LocalPiFactory(PiFactory): ('software', 'exclusive'): LocalPiSoftwareSPI, ('software', 'shared'): LocalPiSoftwareSPIShared, } - # Override the pins dict to be this class' pins dict. This is a bit of - # a dirty hack, but ensures that anyone evil enough to mix pin - # implementations doesn't try and control the same pin with different - # backends + # Override the reservations and pins dict to be this class' attributes. + # This is a bit of a dirty hack, but ensures that anyone evil enough to + # mix pin implementations doesn't try and control the same pin with + # different backends self.pins = LocalPiFactory.pins - - def _get_address(self): - return ('localhost',) + self._reservations = LocalPiFactory._reservations + self._res_lock = LocalPiFactory._res_lock def _get_revision(self): # Cache the result as we can reasonably assume it won't change during @@ -74,19 +77,19 @@ class LocalPiPin(PiPin): class LocalPiHardwareSPI(SPI, Device): def __init__(self, factory, port, device): - if SpiDev is None: - raise ImportError('failed to import spidev') self._port = port self._device = device self._interface = None - self._address = factory.address + ('SPI(port=%d, device=%d)' % (port, device),) + if SpiDev is None: + raise ImportError('failed to import spidev') super(LocalPiHardwareSPI, self).__init__() pins = SPI_HARDWARE_PINS[port] - self._reserve_pins( - factory.pin_address(pins['clock']), - factory.pin_address(pins['mosi']), - factory.pin_address(pins['miso']), - factory.pin_address(pins['select'][device]) + self.pin_factory.reserve_pins( + self, + pins['clock'], + pins['mosi'], + pins['miso'], + pins['select'][device] ) self._interface = SpiDev() self._interface.open(port, device) @@ -98,7 +101,7 @@ class LocalPiHardwareSPI(SPI, Device): self._interface.close() finally: self._interface = None - self._release_all() + self.pin_factory.release_all(self) super(LocalPiHardwareSPI, self).close() @property @@ -148,10 +151,6 @@ class LocalPiHardwareSPI(SPI, Device): class LocalPiSoftwareSPI(SPI, OutputDevice): def __init__(self, factory, clock_pin, mosi_pin, miso_pin, select_pin): self._bus = None - self._address = factory.address + ( - 'SPI(clock_pin=%d, mosi_pin=%d, miso_pin=%d, select_pin=%d)' % ( - clock_pin, mosi_pin, miso_pin, select_pin), - ) super(LocalPiSoftwareSPI, self).__init__(select_pin, active_high=False) try: self._clock_phase = False @@ -163,6 +162,7 @@ class LocalPiSoftwareSPI(SPI, OutputDevice): raise def _conflicts_with(self, other): + # XXX Need to refine this return not ( isinstance(other, LocalPiSoftwareSPI) and (self.pin.number != other.pin.number) diff --git a/gpiozero/pins/mock.py b/gpiozero/pins/mock.py index 2bcf5a5..23a0e4f 100644 --- a/gpiozero/pins/mock.py +++ b/gpiozero/pins/mock.py @@ -40,7 +40,7 @@ class MockPin(PiPin): def __init__(self, factory, number): super(MockPin, self).__init__(factory, number) self._function = 'input' - self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' + self._pull = 'up' if factory.pi_info.pulled_up(repr(self)) else 'floating' self._state = self._pull == 'up' self._bounce = None self._edges = 'both' @@ -94,7 +94,7 @@ class MockPin(PiPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]): + if value != 'up' and self.factory.pi_info.pulled_up(repr(self)): raise PinFixedPull('%r has a physical pull-up resistor' % self) if value not in ('floating', 'up', 'down'): raise PinInvalidPull('pull must be floating, up, or down') @@ -423,14 +423,12 @@ class MockFactory(LocalPiFactory): pin_class = pkg_resources.load_entry_point(dist, group, pin_class.lower()) self.pin_class = pin_class - def _get_address(self): - return ('mock',) - def _get_revision(self): return self._revision def reset(self): self.pins.clear() + self._reservations.clear() def pin(self, spec, pin_class=None, **kwargs): if pin_class is None: diff --git a/gpiozero/pins/native.py b/gpiozero/pins/native.py index eebf0b3..b7de08a 100644 --- a/gpiozero/pins/native.py +++ b/gpiozero/pins/native.py @@ -228,7 +228,7 @@ class NativePin(LocalPiPin): self._change_thread = None self._change_event = Event() self.function = 'input' - self.pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' + self.pull = 'up' if self.factory.pi_info.pulled_up(repr(self)) else 'floating' self.bounce = None self.edges = 'both' @@ -236,7 +236,7 @@ class NativePin(LocalPiPin): self.frequency = None self.when_changed = None self.function = 'input' - self.pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating' + self.pull = 'up' if self.factory.pi_info.pulled_up(repr(self)) else 'floating' def _get_function(self): return self.GPIO_FUNCTION_NAMES[(self.factory.mem[self._func_offset] >> self._func_shift) & 7] @@ -269,7 +269,7 @@ class NativePin(LocalPiPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]): + if value != 'up' and self.factory.pi_info.pulled_up(repr(self)): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: value = self.GPIO_PULL_UPS[value] diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index 1ec024d..f2c02a8 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -7,8 +7,9 @@ from __future__ import ( str = type('') import io -from threading import RLock +from threading import RLock, Lock from types import MethodType +from collections import defaultdict try: from weakref import ref, WeakMethod except ImportError: @@ -48,6 +49,7 @@ class PiFactory(Factory): forms the base of :class:`~gpiozero.pins.local.LocalPiFactory`. """ def __init__(self): + super(PiFactory, self).__init__() self._info = None self.pins = {} self.pin_class = None @@ -72,10 +74,6 @@ class PiFactory(Factory): self.pins[n] = pin return pin - def pin_address(self, spec): - n = self._to_gpio(spec) - return self.address + ('GPIO%d' % n,) - def _to_gpio(self, spec): """ Converts the pin *spec* to a GPIO port number. @@ -240,23 +238,23 @@ class PiPin(Pin): self._when_changed = None self._number = number try: - factory.pi_info.physical_pin(self.address[-1]) + factory.pi_info.physical_pin('GPIO%d' % self.number) except PinNoPins: warnings.warn( PinNonPhysical( - 'no physical pins exist for %s' % self.address[-1])) + 'no physical pins exist for GPIO%d' % self.number)) @property def number(self): return self._number + def __repr__(self): + return 'GPIO%d' % self._number + @property def factory(self): return self._factory - def _get_address(self): - return self.factory.address + ('GPIO%d' % self.number,) - def _call_when_changed(self): """ Called to fire the :attr:`when_changed` event handler; override this diff --git a/gpiozero/pins/pigpio.py b/gpiozero/pins/pigpio.py index fe5e59e..af82597 100644 --- a/gpiozero/pins/pigpio.py +++ b/gpiozero/pins/pigpio.py @@ -7,7 +7,6 @@ from __future__ import ( str = type('') import os -from weakref import proxy import pigpio @@ -126,9 +125,6 @@ class PiGPIOFactory(PiFactory): def _get_revision(self): return self.connection.get_hardware_revision() - def _get_address(self): - return ("%s:%d" % (self.host, self.port),) - def spi(self, **spi_args): intf = super(PiGPIOFactory, self).spi(**spi_args) self._spis.append(intf) @@ -166,7 +162,7 @@ class PiGPIOPin(PiPin): def __init__(self, factory, number): super(PiGPIOPin, self).__init__(factory, number) - self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' + self._pull = 'up' if factory.pi_info.pulled_up(repr(self)) else 'floating' self._pwm = False self._bounce = None self._callback = None @@ -183,7 +179,7 @@ class PiGPIOPin(PiPin): self.frequency = None self.when_changed = None self.function = 'input' - self.pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating' + self.pull = 'up' if self.factory.pi_info.pulled_up(repr(self)) else 'floating' def _get_function(self): return self.GPIO_FUNCTION_NAMES[self.factory.connection.get_mode(self.number)] @@ -225,7 +221,7 @@ class PiGPIOPin(PiPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]): + if value != 'up' and self.factory.pi_info.pulled_up(repr(self)): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: self.factory.connection.set_pull_up_down(self.number, self.GPIO_PULL_UPS[value]) @@ -296,19 +292,17 @@ class PiGPIOHardwareSPI(SPI, Device): def __init__(self, factory, port, device): self._port = port self._device = device - self._factory = proxy(factory) + self._factory = factory self._handle = None super(PiGPIOHardwareSPI, self).__init__() pins = SPI_HARDWARE_PINS[port] - self._reserve_pins(*( - factory.address + ('GPIO%d' % pin,) - for pin in ( - pins['clock'], - pins['mosi'], - pins['miso'], - pins['select'][device] - ) - )) + self._factory.reserve_pins( + self, + pins['clock'], + pins['mosi'], + pins['miso'], + pins['select'][device] + ) self._spi_flags = 8 << 16 self._baud = 500000 self._handle = self._factory.connection.spi_open( @@ -330,7 +324,7 @@ class PiGPIOHardwareSPI(SPI, Device): if not self.closed: self._factory.connection.spi_close(self._handle) self._handle = None - self._release_all() + self._factory.release_all(self) super(PiGPIOHardwareSPI, self).close() @property @@ -397,13 +391,14 @@ class PiGPIOSoftwareSPI(SPI, Device): self._clock_pin = clock_pin self._mosi_pin = mosi_pin self._miso_pin = miso_pin - self._factory = proxy(factory) + self._factory = factory super(PiGPIOSoftwareSPI, self).__init__() - self._reserve_pins( - factory.pin_address(clock_pin), - factory.pin_address(mosi_pin), - factory.pin_address(miso_pin), - factory.pin_address(select_pin), + self._factory.reserve_pins( + self, + clock_pin, + mosi_pin, + miso_pin, + select_pin, ) self._spi_flags = 0 self._baud = 100000 @@ -434,7 +429,7 @@ class PiGPIOSoftwareSPI(SPI, Device): if not self.closed: self._closed = True self._factory.connection.bb_spi_close(self._select_pin) - self._release_all() + self.factory.release_all(self) super(PiGPIOSoftwareSPI, self).close() @property diff --git a/gpiozero/pins/rpigpio.py b/gpiozero/pins/rpigpio.py index e0274b6..4c43712 100644 --- a/gpiozero/pins/rpigpio.py +++ b/gpiozero/pins/rpigpio.py @@ -85,7 +85,7 @@ class RPiGPIOPin(LocalPiPin): def __init__(self, factory, number): super(RPiGPIOPin, self).__init__(factory, number) - self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' + self._pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating' self._pwm = None self._frequency = None self._duty_cycle = None diff --git a/gpiozero/pins/rpio.py b/gpiozero/pins/rpio.py index 12fced2..5a51e41 100644 --- a/gpiozero/pins/rpio.py +++ b/gpiozero/pins/rpio.py @@ -80,7 +80,7 @@ class RPIOPin(LocalPiPin): def __init__(self, factory, number): super(RPIOPin, self).__init__(factory, number) - self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' + self._pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating' self._pwm = False self._duty_cycle = None self._bounce = None diff --git a/tests/test_boards.py b/tests/test_boards.py index 983bfee..6251b73 100644 --- a/tests/test_boards.py +++ b/tests/test_boards.py @@ -36,7 +36,6 @@ def setup_function(function): def teardown_function(function): Device.pin_factory.reset() - Device._reservations.clear() def teardown_module(module): # make sure we reset the default @@ -47,7 +46,7 @@ def test_composite_output_on_off(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device: + with CompositeOutputDevice(OutputDevice(2), OutputDevice(3), foo=OutputDevice(4)) as device: device.on() assert all((pin1.state, pin2.state, pin3.state)) device.off() @@ -57,7 +56,7 @@ def test_composite_output_toggle(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device: + with CompositeOutputDevice(OutputDevice(2), OutputDevice(3), foo=OutputDevice(4)) as device: device.toggle() assert all((pin1.state, pin2.state, pin3.state)) device[0].off() @@ -70,7 +69,7 @@ def test_composite_output_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device: + with CompositeOutputDevice(OutputDevice(2), OutputDevice(3), foo=OutputDevice(4)) as device: assert device.value == (0, 0, 0) device.toggle() assert device.value == (1, 1, 1) @@ -83,7 +82,7 @@ def test_led_board_on_off(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBoard(pin1, pin2, foo=pin3) as board: + with LEDBoard(2, 3, foo=4) as board: assert isinstance(board[0], LED) assert isinstance(board[1], LED) assert isinstance(board[2], LED) @@ -140,7 +139,7 @@ def test_led_board_active_low(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBoard(pin1, pin2, foo=pin3, active_high=False) as board: + with LEDBoard(2, 3, foo=4, active_high=False) as board: assert not board.active_high assert not board[0].active_high assert not board[1].active_high @@ -164,7 +163,7 @@ def test_led_board_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBoard(pin1, pin2, foo=pin3) as board: + with LEDBoard(2, 3, foo=4) as board: assert board.value == (0, 0, 0) board.value = (0, 1, 0) assert board.value == (0, 1, 0) @@ -175,7 +174,7 @@ def test_led_board_pwm_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBoard(pin1, pin2, foo=pin3, pwm=True) as board: + with LEDBoard(2, 3, foo=4, pwm=True) as board: assert board.value == (0, 0, 0) board.value = (0, 1, 0) assert board.value == (0, 1, 0) @@ -186,7 +185,7 @@ def test_led_board_pwm_bad_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBoard(pin1, pin2, foo=pin3, pwm=True) as board: + with LEDBoard(2, 3, foo=4, pwm=True) as board: with pytest.raises(ValueError): board.value = (-1, 0, 0) with pytest.raises(ValueError): @@ -196,20 +195,20 @@ def test_led_board_initial_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBoard(pin1, pin2, foo=pin3, initial_value=0) as board: + with LEDBoard(2, 3, foo=4, initial_value=0) as board: assert board.value == (0, 0, 0) - with LEDBoard(pin1, pin2, foo=pin3, initial_value=1) as board: + with LEDBoard(2, 3, foo=4, initial_value=1) as board: assert board.value == (1, 1, 1) def test_led_board_pwm_initial_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=0) as board: + with LEDBoard(2, 3, foo=4, pwm=True, initial_value=0) as board: assert board.value == (0, 0, 0) - with LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=1) as board: + with LEDBoard(2, 3, foo=4, pwm=True, initial_value=1) as board: assert board.value == (1, 1, 1) - with LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=0.5) as board: + with LEDBoard(2, 3, foo=4, pwm=True, initial_value=0.5) as board: assert board.value == (0.5, 0.5, 0.5) def test_led_board_pwm_bad_initial_value(): @@ -217,15 +216,15 @@ def test_led_board_pwm_bad_initial_value(): pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) with pytest.raises(ValueError): - LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=-1) + LEDBoard(2, 3, foo=4, pwm=True, initial_value=-1) with pytest.raises(ValueError): - LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=2) + LEDBoard(2, 3, foo=4, pwm=True, initial_value=2) def test_led_board_nested(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + with LEDBoard(2, LEDBoard(3, 4)) as board: assert list(led.pin for led in board.leds) == [pin1, pin2, pin3] assert board.value == (0, (0, 0)) board.value = (1, (0, 1)) @@ -237,7 +236,7 @@ def test_led_board_bad_blink(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + with LEDBoard(2, LEDBoard(3, 4)) as board: with pytest.raises(ValueError): board.blink(fade_in_time=1, fade_out_time=1) with pytest.raises(ValueError): @@ -251,7 +250,7 @@ def test_led_board_blink_background(): pin1 = Device.pin_factory.pin(4) pin2 = Device.pin_factory.pin(5) pin3 = Device.pin_factory.pin(6) - with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + with LEDBoard(4, LEDBoard(5, 6)) as board: # Instantiation takes a long enough time that it throws off our timing # here! pin1.clear_states() @@ -276,7 +275,7 @@ def test_led_board_blink_foreground(): pin1 = Device.pin_factory.pin(4) pin2 = Device.pin_factory.pin(5) pin3 = Device.pin_factory.pin(6) - with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + with LEDBoard(4, LEDBoard(5, 6)) as board: pin1.clear_states() pin2.clear_states() pin3.clear_states() @@ -298,7 +297,7 @@ def test_led_board_blink_control(): pin1 = Device.pin_factory.pin(4) pin2 = Device.pin_factory.pin(5) pin3 = Device.pin_factory.pin(6) - with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + with LEDBoard(4, LEDBoard(5, 6)) as board: pin1.clear_states() pin2.clear_states() pin3.clear_states() @@ -326,7 +325,7 @@ def test_led_board_blink_take_over(): pin1 = Device.pin_factory.pin(4) pin2 = Device.pin_factory.pin(5) pin3 = Device.pin_factory.pin(6) - with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + with LEDBoard(4, LEDBoard(5, 6)) as board: pin1.clear_states() pin2.clear_states() pin3.clear_states() @@ -351,7 +350,7 @@ def test_led_board_blink_control_all(): pin1 = Device.pin_factory.pin(4) pin2 = Device.pin_factory.pin(5) pin3 = Device.pin_factory.pin(6) - with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + with LEDBoard(4, LEDBoard(5, 6)) as board: pin1.clear_states() pin2.clear_states() pin3.clear_states() @@ -376,7 +375,7 @@ def test_led_board_blink_interrupt_on(): pin1 = Device.pin_factory.pin(4) pin2 = Device.pin_factory.pin(5) pin3 = Device.pin_factory.pin(6) - with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + with LEDBoard(4, LEDBoard(5, 6)) as board: board.blink(1, 0.1) sleep(0.2) board.off() # should interrupt while on @@ -388,7 +387,7 @@ def test_led_board_blink_interrupt_off(): pin1 = Device.pin_factory.pin(4) pin2 = Device.pin_factory.pin(5) pin3 = Device.pin_factory.pin(6) - with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + with LEDBoard(4, LEDBoard(5, 6)) as board: pin1.clear_states() pin2.clear_states() pin3.clear_states() @@ -405,7 +404,7 @@ def test_led_board_fade_background(): pin1 = Device.pin_factory.pin(4) pin2 = Device.pin_factory.pin(5) pin3 = Device.pin_factory.pin(6) - with LEDBoard(pin1, LEDBoard(pin2, pin3, pwm=True), pwm=True) as board: + with LEDBoard(4, LEDBoard(5, 6, pwm=True), pwm=True) as board: pin1.clear_states() pin2.clear_states() pin3.clear_states() @@ -442,7 +441,7 @@ def test_led_bar_graph_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBarGraph(pin1, pin2, pin3) as graph: + with LEDBarGraph(2, 3, 4) as graph: assert isinstance(graph[0], LED) assert isinstance(graph[1], LED) assert isinstance(graph[2], LED) @@ -475,7 +474,7 @@ def test_led_bar_graph_active_low(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBarGraph(pin1, pin2, pin3, active_high=False) as graph: + with LEDBarGraph(2, 3, 4, active_high=False) as graph: assert not graph.active_high assert not graph[0].active_high assert not graph[1].active_high @@ -497,7 +496,7 @@ def test_led_bar_graph_pwm_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBarGraph(pin1, pin2, pin3, pwm=True) as graph: + with LEDBarGraph(2, 3, 4, pwm=True) as graph: assert isinstance(graph[0], PWMLED) assert isinstance(graph[1], PWMLED) assert isinstance(graph[2], PWMLED) @@ -524,7 +523,7 @@ def test_led_bar_graph_bad_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBarGraph(pin1, pin2, pin3) as graph: + with LEDBarGraph(2, 3, 4) as graph: with pytest.raises(ValueError): graph.value = -2 with pytest.raises(ValueError): @@ -535,20 +534,20 @@ def test_led_bar_graph_bad_init(): pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) with pytest.raises(TypeError): - LEDBarGraph(pin1, pin2, foo=pin3) + LEDBarGraph(2, 3, foo=4) with pytest.raises(ValueError): - LEDBarGraph(pin1, pin2, pin3, initial_value=-2) + LEDBarGraph(2, 3, 4, initial_value=-2) with pytest.raises(ValueError): - LEDBarGraph(pin1, pin2, pin3, initial_value=2) + LEDBarGraph(2, 3, 4, initial_value=2) def test_led_bar_graph_initial_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBarGraph(pin1, pin2, pin3, initial_value=1/3) as graph: + with LEDBarGraph(2, 3, 4, initial_value=1/3) as graph: assert graph.value == 1/3 assert pin1.state and not (pin2.state or pin3.state) - with LEDBarGraph(pin1, pin2, pin3, initial_value=-1/3) as graph: + with LEDBarGraph(2, 3, 4, initial_value=-1/3) as graph: assert graph.value == -1/3 assert pin3.state and not (pin1.state or pin2.state) @@ -556,10 +555,10 @@ def test_led_bar_graph_pwm_initial_value(): pin1 = Device.pin_factory.pin(2) pin2 = Device.pin_factory.pin(3) pin3 = Device.pin_factory.pin(4) - with LEDBarGraph(pin1, pin2, pin3, pwm=True, initial_value=0.5) as graph: + with LEDBarGraph(2, 3, 4, pwm=True, initial_value=0.5) as graph: assert graph.value == 0.5 assert (pin1.state, pin2.state, pin3.state) == (1, 0.5, 0) - with LEDBarGraph(pin1, pin2, pin3, pwm=True, initial_value=-0.5) as graph: + with LEDBarGraph(2, 3, 4, pwm=True, initial_value=-0.5) as graph: assert graph.value == -0.5 assert (pin1.state, pin2.state, pin3.state) == (0, 0.5, 1) @@ -585,7 +584,7 @@ def test_traffic_lights(): red_pin = Device.pin_factory.pin(2) amber_pin = Device.pin_factory.pin(3) green_pin = Device.pin_factory.pin(4) - with TrafficLights(red_pin, amber_pin, green_pin) as board: + with TrafficLights(2, 3, 4) as board: board.red.on() assert board.red.value assert not board.amber.value @@ -598,7 +597,7 @@ def test_traffic_lights(): assert amber_pin.state board.yellow.off() assert not amber_pin.state - with TrafficLights(red=red_pin, yellow=amber_pin, green=green_pin) as board: + with TrafficLights(red=2, yellow=3, green=4) as board: board.yellow.on() assert not board.red.value assert board.amber.value @@ -618,7 +617,7 @@ def test_traffic_lights_bad_init(): green_pin = Device.pin_factory.pin(4) yellow_pin = Device.pin_factory.pin(5) with pytest.raises(ValueError): - TrafficLights(red=red_pin, amber=amber_pin, yellow=yellow_pin, green=green_pin) + TrafficLights(red=2, amber=3, yellow=5, green=4) def test_pi_traffic(): pins = [Device.pin_factory.pin(n) for n in (9, 10, 11)] @@ -677,9 +676,9 @@ def test_traffic_lights_buzzer(): buzzer_pin = Device.pin_factory.pin(5) button_pin = Device.pin_factory.pin(6) with TrafficLightsBuzzer( - TrafficLights(red_pin, amber_pin, green_pin), - Buzzer(buzzer_pin), - Button(button_pin)) as board: + TrafficLights(2, 3, 4), + Buzzer(5), + Button(6)) as board: board.lights.red.on() board.buzzer.on() assert red_pin.state diff --git a/tests/test_devices.py b/tests/test_devices.py index 7293741..aa7c83c 100644 --- a/tests/test_devices.py +++ b/tests/test_devices.py @@ -33,7 +33,7 @@ def test_device_non_physical(): def test_device_init(): pin = Device.pin_factory.pin(2) - with GPIODevice(pin) as device: + with GPIODevice(2) as device: assert not device.closed assert device.pin == pin @@ -56,9 +56,9 @@ def test_device_close(): def test_device_reopen_same_pin(): pin = Device.pin_factory.pin(2) - with GPIODevice(pin) as device: + with GPIODevice(2) as device: pass - with GPIODevice(pin) as device2: + with GPIODevice(2) as device2: assert not device2.closed assert device2.pin is pin assert device.closed diff --git a/tests/test_inputs.py b/tests/test_inputs.py index d05940c..0d9c80a 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -18,22 +18,21 @@ from gpiozero import * def teardown_function(function): Device.pin_factory.reset() - Device._reservations.clear() def test_input_initial_values(): pin = Device.pin_factory.pin(4) - with InputDevice(pin, pull_up=True) as device: + with InputDevice(4, pull_up=True) as device: assert pin.function == 'input' assert pin.pull == 'up' assert device.pull_up - with InputDevice(pin, pull_up=False) as device: + with InputDevice(4, pull_up=False) as device: assert pin.pull == 'down' assert not device.pull_up def test_input_is_active_low(): pin = Device.pin_factory.pin(2) - with InputDevice(pin, pull_up=True) as device: + with InputDevice(2, pull_up=True) as device: pin.drive_high() assert not device.is_active assert repr(device) == '' @@ -43,7 +42,7 @@ def test_input_is_active_low(): def test_input_is_active_high(): pin = Device.pin_factory.pin(4) - with InputDevice(pin, pull_up=False) as device: + with InputDevice(4, pull_up=False) as device: pin.drive_high() assert device.is_active assert repr(device) == '' @@ -54,12 +53,12 @@ def test_input_is_active_high(): def test_input_pulled_up(): pin = Device.pin_factory.pin(2) with pytest.raises(PinFixedPull): - InputDevice(pin, pull_up=False) + InputDevice(2, pull_up=False) def test_input_event_activated(): event = Event() pin = Device.pin_factory.pin(4) - with DigitalInputDevice(pin) as device: + with DigitalInputDevice(4) as device: device.when_activated = lambda: event.set() assert not event.is_set() pin.drive_high() @@ -68,7 +67,7 @@ def test_input_event_activated(): def test_input_event_deactivated(): event = Event() pin = Device.pin_factory.pin(4) - with DigitalInputDevice(pin) as device: + with DigitalInputDevice(4) as device: device.when_deactivated = lambda: event.set() assert not event.is_set() pin.drive_high() @@ -84,7 +83,7 @@ def test_input_partial_callback(): return a + b bar = partial(foo, 1) baz = partial(bar, 2) - with DigitalInputDevice(pin) as device: + with DigitalInputDevice(4) as device: device.when_activated = baz assert not event.is_set() pin.drive_high() @@ -92,20 +91,20 @@ def test_input_partial_callback(): def test_input_wait_active(): pin = Device.pin_factory.pin(4) - with DigitalInputDevice(pin) as device: + with DigitalInputDevice(4) as device: pin.drive_high() assert device.wait_for_active(1) assert not device.wait_for_inactive(0) def test_input_wait_inactive(): pin = Device.pin_factory.pin(4) - with DigitalInputDevice(pin) as device: + with DigitalInputDevice(4) as device: assert device.wait_for_inactive(1) assert not device.wait_for_active(0) def test_input_smoothed_attrib(): pin = Device.pin_factory.pin(4) - with SmoothedInputDevice(pin, threshold=0.5, queue_len=5, partial=False) as device: + with SmoothedInputDevice(4, threshold=0.5, queue_len=5, partial=False) as device: assert repr(device) == '' assert device.threshold == 0.5 assert device.queue_len == 5 @@ -117,7 +116,7 @@ def test_input_smoothed_attrib(): def test_input_smoothed_values(): pin = Device.pin_factory.pin(4) - with SmoothedInputDevice(pin) as device: + with SmoothedInputDevice(4) as device: device._queue.start() assert not device.is_active pin.drive_high() @@ -127,7 +126,7 @@ def test_input_smoothed_values(): def test_input_button(): pin = Device.pin_factory.pin(2) - with Button(pin) as button: + with Button(2) as button: assert pin.pull == 'up' assert not button.is_pressed pin.drive_low() @@ -139,7 +138,7 @@ def test_input_button(): def test_input_line_sensor(): pin = Device.pin_factory.pin(4) - with LineSensor(pin) as sensor: + with LineSensor(4) as sensor: pin.drive_low() # logic is inverted for line sensor assert sensor.wait_for_line(1) assert sensor.line_detected @@ -149,7 +148,7 @@ def test_input_line_sensor(): def test_input_motion_sensor(): pin = Device.pin_factory.pin(4) - with MotionSensor(pin) as sensor: + with MotionSensor(4) as sensor: pin.drive_high() assert sensor.wait_for_motion(1) assert sensor.motion_detected @@ -161,7 +160,7 @@ def test_input_motion_sensor(): reason='timing is too random on pypy') def test_input_light_sensor(): pin = Device.pin_factory.pin(4, pin_class=MockChargingPin) - with LightSensor(pin) as sensor: + with LightSensor(4) as sensor: pin.charge_time = 0.1 assert sensor.wait_for_dark(1) pin.charge_time = 0.0 @@ -173,10 +172,10 @@ def test_input_distance_sensor(): echo_pin = Device.pin_factory.pin(4) trig_pin = Device.pin_factory.pin(5, pin_class=MockTriggerPin, echo_pin=echo_pin, echo_time=0.02) with pytest.raises(ValueError): - DistanceSensor(echo_pin, trig_pin, max_distance=-1) + DistanceSensor(4, 5, max_distance=-1) # normal queue len is large (because the sensor is *really* jittery) but # we want quick tests and we've got precisely controlled pins :) - with DistanceSensor(echo_pin, trig_pin, queue_len=5, max_distance=1) as sensor: + with DistanceSensor(4, 5, queue_len=5, max_distance=1) as sensor: assert sensor.max_distance == 1 assert sensor.trigger is trig_pin assert sensor.echo is echo_pin diff --git a/tests/test_outputs.py b/tests/test_outputs.py index b50dda5..5403023 100644 --- a/tests/test_outputs.py +++ b/tests/test_outputs.py @@ -16,29 +16,73 @@ except ImportError: import pytest -from gpiozero.pins.mock import MockPWMPin +from gpiozero.pins.mock import MockPin, MockPWMPin from gpiozero import * +def setup_function(function): + # dirty, but it does the job + Device.pin_factory.pin_class = MockPWMPin if function.__name__ in ( + 'test_output_pwm_states', + 'test_output_pwm_read', + 'test_output_pwm_write', + 'test_output_pwm_toggle', + 'test_output_pwm_active_high_read', + 'test_output_pwm_bad_value', + 'test_output_pwm_write_closed', + 'test_output_pwm_write_silly', + 'test_output_pwm_blink_background', + 'test_output_pwm_blink_foreground', + 'test_output_pwm_fade_background', + 'test_output_pwm_fade_foreground', + 'test_output_pwm_pulse_background', + 'test_output_pwm_pulse_foreground', + 'test_output_pwm_blink_interrupt', + 'test_rgbled_initial_value', + 'test_rgbled_initial_bad_value', + 'test_rgbled_value', + 'test_rgbled_bad_value', + 'test_rgbled_toggle', + 'test_rgbled_blink_background', + 'test_rgbled_blink_foreground', + 'test_rgbled_fade_background', + 'test_rgbled_fade_foreground', + 'test_rgbled_pulse_background', + 'test_rgbled_pulse_foreground', + 'test_rgbled_blink_interrupt', + 'test_rgbled_close', + 'test_motor_pins', + 'test_motor_close', + 'test_motor_value', + 'test_motor_bad_value', + 'test_motor_reverse', + 'test_servo_pins', + 'test_servo_bad_value', + 'test_servo_close', + 'test_servo_pulse_width', + 'test_servo_values', + 'test_angular_servo_range', + 'test_angular_servo_angles', + ) else MockPin + def teardown_function(function): Device.pin_factory.reset() - Device._reservations.clear() def test_output_initial_values(): pin = Device.pin_factory.pin(2) - with OutputDevice(pin, initial_value=False) as device: + with OutputDevice(2, initial_value=False) as device: assert pin.function == 'output' assert not pin.state - with OutputDevice(pin, initial_value=True) as device: + with OutputDevice(2, initial_value=True) as device: assert pin.state state = pin.state - with OutputDevice(pin, initial_value=None) as device: + with OutputDevice(2, initial_value=None) as device: assert state == pin.state def test_output_write_active_high(): pin = Device.pin_factory.pin(2) - with OutputDevice(pin) as device: + with OutputDevice(2) as device: device.on() assert pin.state device.off() @@ -46,14 +90,14 @@ def test_output_write_active_high(): def test_output_write_active_low(): pin = Device.pin_factory.pin(2) - with OutputDevice(pin, active_high=False) as device: + with OutputDevice(2, active_high=False) as device: device.on() assert not pin.state device.off() assert pin.state def test_output_write_closed(): - with OutputDevice(Device.pin_factory.pin(2)) as device: + with OutputDevice(2) as device: device.close() assert device.closed device.close() @@ -63,14 +107,14 @@ def test_output_write_closed(): def test_output_write_silly(): pin = Device.pin_factory.pin(2) - with OutputDevice(pin) as device: + with OutputDevice(2) as device: pin.function = 'input' with pytest.raises(AttributeError): device.on() def test_output_value(): pin = Device.pin_factory.pin(2) - with OutputDevice(pin) as device: + with OutputDevice(2) as device: assert not device.value assert not pin.state device.on() @@ -82,7 +126,7 @@ def test_output_value(): def test_output_digital_toggle(): pin = Device.pin_factory.pin(2) - with DigitalOutputDevice(pin) as device: + with DigitalOutputDevice(2) as device: assert not device.value assert not pin.state device.toggle() @@ -96,7 +140,7 @@ def test_output_digital_toggle(): reason='timing is too random on pypy') def test_output_blink_background(): pin = Device.pin_factory.pin(4) - with DigitalOutputDevice(pin) as device: + with DigitalOutputDevice(4) as device: start = time() device.blink(0.1, 0.1, n=2) assert isclose(time() - start, 0, abs_tol=0.05) @@ -114,7 +158,7 @@ def test_output_blink_background(): reason='timing is too random on pypy') def test_output_blink_foreground(): pin = Device.pin_factory.pin(4) - with DigitalOutputDevice(pin) as device: + with DigitalOutputDevice(4) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) assert isclose(time() - start, 0.4, abs_tol=0.05) @@ -128,7 +172,7 @@ def test_output_blink_foreground(): def test_output_blink_interrupt_on(): pin = Device.pin_factory.pin(4) - with DigitalOutputDevice(pin) as device: + with DigitalOutputDevice(4) as device: device.blink(1, 0.1) sleep(0.2) device.off() # should interrupt while on @@ -136,7 +180,7 @@ def test_output_blink_interrupt_on(): def test_output_blink_interrupt_off(): pin = Device.pin_factory.pin(4) - with DigitalOutputDevice(pin) as device: + with DigitalOutputDevice(4) as device: device.blink(0.1, 1) sleep(0.2) device.off() # should interrupt while off @@ -144,23 +188,23 @@ def test_output_blink_interrupt_off(): def test_output_pwm_bad_initial_value(): with pytest.raises(ValueError): - PWMOutputDevice(Device.pin_factory.pin(2), initial_value=2) + PWMOutputDevice(2, initial_value=2) def test_output_pwm_not_supported(): with pytest.raises(AttributeError): - PWMOutputDevice(Device.pin_factory.pin(2)) + PWMOutputDevice(2) def test_output_pwm_states(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: device.value = 0.1 device.value = 0.2 device.value = 0.0 pin.assert_states([0.0, 0.1, 0.2, 0.0]) def test_output_pwm_read(): - pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with PWMOutputDevice(pin, frequency=100) as device: + pin = Device.pin_factory.pin(2) + with PWMOutputDevice(2, frequency=100) as device: assert device.frequency == 100 device.value = 0.1 assert isclose(device.value, 0.1) @@ -172,15 +216,15 @@ def test_output_pwm_read(): assert device.frequency is None def test_output_pwm_write(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: device.on() device.off() pin.assert_states([False, True, False]) def test_output_pwm_toggle(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: device.toggle() device.value = 0.5 device.value = 0.1 @@ -189,8 +233,8 @@ def test_output_pwm_toggle(): pin.assert_states([False, True, 0.5, 0.1, 0.9, False]) def test_output_pwm_active_high_read(): - pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with PWMOutputDevice(pin, active_high=False) as device: + pin = Device.pin_factory.pin(2) + with PWMOutputDevice(2, active_high=False) as device: device.value = 0.1 assert isclose(device.value, 0.1) assert isclose(pin.state, 0.9) @@ -198,19 +242,21 @@ def test_output_pwm_active_high_read(): assert device.value def test_output_pwm_bad_value(): - with PWMOutputDevice(Device.pin_factory.pin(2, pin_class=MockPWMPin)) as device: + pin = Device.pin_factory.pin(2) + with PWMOutputDevice(2) as device: with pytest.raises(ValueError): device.value = 2 def test_output_pwm_write_closed(): - with PWMOutputDevice(Device.pin_factory.pin(2, pin_class=MockPWMPin)) as device: + pin = Device.pin_factory.pin(2) + with PWMOutputDevice(2) as device: device.close() with pytest.raises(GPIODeviceClosed): device.on() def test_output_pwm_write_silly(): - pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(2) + with PWMOutputDevice(2) as device: pin.function = 'input' with pytest.raises(AttributeError): device.off() @@ -218,8 +264,8 @@ def test_output_pwm_write_silly(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_blink_background(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: start = time() device.blink(0.1, 0.1, n=2) assert isclose(time() - start, 0, abs_tol=0.05) @@ -236,8 +282,8 @@ def test_output_pwm_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_blink_foreground(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) assert isclose(time() - start, 0.4, abs_tol=0.05) @@ -252,8 +298,8 @@ def test_output_pwm_blink_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_fade_background(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2) assert isclose(time() - start, 0, abs_tol=0.05) @@ -286,8 +332,8 @@ def test_output_pwm_fade_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_fade_foreground(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2, background=False) assert isclose(time() - start, 0.8, abs_tol=0.05) @@ -318,8 +364,8 @@ def test_output_pwm_fade_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_pulse_background(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: start = time() device.pulse(0.2, 0.2, n=2) assert isclose(time() - start, 0, abs_tol=0.05) @@ -352,8 +398,8 @@ def test_output_pwm_pulse_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_pulse_foreground(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: start = time() device.pulse(0.2, 0.2, n=2, background=False) assert isclose(time() - start, 0.8, abs_tol=0.05) @@ -382,8 +428,8 @@ def test_output_pwm_pulse_foreground(): ]) def test_output_pwm_blink_interrupt(): - pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) - with PWMOutputDevice(pin) as device: + pin = Device.pin_factory.pin(4) + with PWMOutputDevice(4) as device: device.blink(1, 0.1) sleep(0.2) device.off() # should interrupt while on @@ -394,8 +440,8 @@ def test_rgbled_missing_pins(): RGBLED() def test_rgbled_initial_value(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) - with RGBLED(r, g, b, initial_value=(0.1, 0.2, 0)) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) + with RGBLED(1, 2, 3, initial_value=(0.1, 0.2, 0)) as device: assert r.frequency assert g.frequency assert b.frequency @@ -405,24 +451,24 @@ def test_rgbled_initial_value(): def test_rgbled_initial_value_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False, initial_value=(0, 1, 1)) as device: + with RGBLED(1, 2, 3, pwm=False, initial_value=(0, 1, 1)) as device: assert r.state == 0 assert g.state == 1 assert b.state == 1 def test_rgbled_initial_bad_value(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) with pytest.raises(ValueError): - RGBLED(r, g, b, initial_value=(0.1, 0.2, 1.2)) + RGBLED(1, 2, 3, initial_value=(0.1, 0.2, 1.2)) def test_rgbled_initial_bad_value_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) with pytest.raises(ValueError): - RGBLED(r, g, b, pwm=False, initial_value=(0.1, 0.2, 0)) + RGBLED(1, 2, 3, pwm=False, initial_value=(0.1, 0.2, 0)) def test_rgbled_value(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) + with RGBLED(1, 2, 3) as device: assert isinstance(device._leds[0], PWMLED) assert isinstance(device._leds[1], PWMLED) assert isinstance(device._leds[2], PWMLED) @@ -440,7 +486,7 @@ def test_rgbled_value(): def test_rgbled_value_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: assert isinstance(device._leds[0], LED) assert isinstance(device._leds[1], LED) assert isinstance(device._leds[2], LED) @@ -454,35 +500,35 @@ def test_rgbled_value_nonpwm(): assert device.value == (0, 0, 0) def test_rgbled_bad_value(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) + with RGBLED(1, 2, 3) as device: with pytest.raises(ValueError): device.value = (2, 0, 0) - with RGBLED(r, g, b) as device: + with RGBLED(1, 2, 3) as device: with pytest.raises(ValueError): device.value = (0, -1, 0) def test_rgbled_bad_value_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.value = (2, 0, 0) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.value = (0, -1, 0) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.value = (0.5, 0, 0) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.value = (0, 0.5, 0) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.value = (0, 0, 0.5) def test_rgbled_toggle(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) + with RGBLED(1, 2, 3) as device: assert not device.is_active assert device.value == (0, 0, 0) device.toggle() @@ -494,7 +540,7 @@ def test_rgbled_toggle(): def test_rgbled_toggle_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: assert not device.is_active assert device.value == (0, 0, 0) device.toggle() @@ -506,7 +552,7 @@ def test_rgbled_toggle_nonpwm(): def test_rgbled_blink_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.blink(fade_in_time=1) with pytest.raises(ValueError): @@ -515,8 +561,8 @@ def test_rgbled_blink_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_background(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) + with RGBLED(1, 2, 3) as device: start = time() device.blink(0.1, 0.1, n=2) assert isclose(time() - start, 0, abs_tol=0.05) @@ -537,7 +583,7 @@ def test_rgbled_blink_background(): reason='timing is too random on pypy') def test_rgbled_blink_background_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: start = time() device.blink(0.1, 0.1, n=2) assert isclose(time() - start, 0, abs_tol=0.05) @@ -557,8 +603,8 @@ def test_rgbled_blink_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_foreground(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) + with RGBLED(1, 2, 3) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) assert isclose(time() - start, 0.4, abs_tol=0.05) @@ -577,7 +623,7 @@ def test_rgbled_blink_foreground(): reason='timing is too random on pypy') def test_rgbled_blink_foreground_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) assert isclose(time() - start, 0.4, abs_tol=0.05) @@ -595,8 +641,8 @@ def test_rgbled_blink_foreground_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_background(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) + with RGBLED(1, 2, 3) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2) assert isclose(time() - start, 0, abs_tol=0.05) @@ -631,15 +677,15 @@ def test_rgbled_fade_background(): def test_rgbled_fade_background_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.blink(0, 0, 0.2, 0.2, n=2) @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_foreground(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) + with RGBLED(1, 2, 3) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2, background=False) assert isclose(time() - start, 0.8, abs_tol=0.05) @@ -672,15 +718,15 @@ def test_rgbled_fade_foreground(): def test_rgbled_fade_foreground_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.blink(0, 0, 0.2, 0.2, n=2, background=False) @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_background(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) + with RGBLED(1, 2, 3) as device: start = time() device.pulse(0.2, 0.2, n=2) assert isclose(time() - start, 0, abs_tol=0.05) @@ -715,15 +761,15 @@ def test_rgbled_pulse_background(): def test_rgbled_pulse_background_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.pulse(0.2, 0.2, n=2) @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_foreground(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) + with RGBLED(1, 2, 3) as device: start = time() device.pulse(0.2, 0.2, n=2, background=False) assert isclose(time() - start, 0.8, abs_tol=0.05) @@ -756,13 +802,13 @@ def test_rgbled_pulse_foreground(): def test_rgbled_pulse_foreground_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: with pytest.raises(ValueError): device.pulse(0.2, 0.2, n=2, background=False) def test_rgbled_blink_interrupt(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) + with RGBLED(1, 2, 3) as device: device.blink(1, 0.1) sleep(0.2) device.off() # should interrupt while on @@ -772,7 +818,7 @@ def test_rgbled_blink_interrupt(): def test_rgbled_blink_interrupt_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: device.blink(1, 0.1) sleep(0.2) device.off() # should interrupt while on @@ -781,8 +827,8 @@ def test_rgbled_blink_interrupt_nonpwm(): b.assert_states([0, 1, 0]) def test_rgbled_close(): - r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) - with RGBLED(r, g, b) as device: + r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) + with RGBLED(1, 2, 3) as device: assert not device.closed device.close() assert device.closed @@ -791,7 +837,7 @@ def test_rgbled_close(): def test_rgbled_close_nonpwm(): r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) - with RGBLED(r, g, b, pwm=False) as device: + with RGBLED(1, 2, 3, pwm=False) as device: assert not device.closed device.close() assert device.closed @@ -803,9 +849,9 @@ def test_motor_missing_pins(): Motor() def test_motor_pins(): - f = Device.pin_factory.pin(1, pin_class=MockPWMPin) - b = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with Motor(f, b) as device: + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) + with Motor(1, 2) as device: assert device.forward_device.pin is f assert isinstance(device.forward_device, PWMOutputDevice) assert device.backward_device.pin is b @@ -814,16 +860,16 @@ def test_motor_pins(): def test_motor_pins_nonpwm(): f = Device.pin_factory.pin(1) b = Device.pin_factory.pin(2) - with Motor(f, b, pwm=False) as device: + with Motor(1, 2, pwm=False) as device: assert device.forward_device.pin is f assert isinstance(device.forward_device, DigitalOutputDevice) assert device.backward_device.pin is b assert isinstance(device.backward_device, DigitalOutputDevice) def test_motor_close(): - f = Device.pin_factory.pin(1, pin_class=MockPWMPin) - b = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with Motor(f, b) as device: + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) + with Motor(1, 2) as device: device.close() assert device.closed assert device.forward_device.pin is None @@ -834,16 +880,16 @@ def test_motor_close(): def test_motor_close_nonpwm(): f = Device.pin_factory.pin(1) b = Device.pin_factory.pin(2) - with Motor(f, b, pwm=False) as device: + with Motor(1, 2, pwm=False) as device: device.close() assert device.closed assert device.forward_device.pin is None assert device.backward_device.pin is None def test_motor_value(): - f = Device.pin_factory.pin(1, pin_class=MockPWMPin) - b = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with Motor(f, b) as device: + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) + with Motor(1, 2) as device: device.value = -1 assert device.is_active assert device.value == -1 @@ -868,7 +914,7 @@ def test_motor_value(): def test_motor_value_nonpwm(): f = Device.pin_factory.pin(1) b = Device.pin_factory.pin(2) - with Motor(f, b, pwm=False) as device: + with Motor(1, 2, pwm=False) as device: device.value = -1 assert device.is_active assert device.value == -1 @@ -883,9 +929,9 @@ def test_motor_value_nonpwm(): assert b.state == 0 and f.state == 0 def test_motor_bad_value(): - f = Device.pin_factory.pin(1, pin_class=MockPWMPin) - b = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with Motor(f, b) as device: + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) + with Motor(1, 2) as device: with pytest.raises(ValueError): device.value = -2 with pytest.raises(ValueError): @@ -898,7 +944,7 @@ def test_motor_bad_value(): def test_motor_bad_value_nonpwm(): f = Device.pin_factory.pin(1) b = Device.pin_factory.pin(2) - with Motor(f, b, pwm=False) as device: + with Motor(1, 2, pwm=False) as device: with pytest.raises(ValueError): device.value = -2 with pytest.raises(ValueError): @@ -909,9 +955,9 @@ def test_motor_bad_value_nonpwm(): device.value = -0.5 def test_motor_reverse(): - f = Device.pin_factory.pin(1, pin_class=MockPWMPin) - b = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with Motor(f, b) as device: + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) + with Motor(1, 2) as device: device.forward() assert device.value == 1 assert b.state == 0 and f.state == 1 @@ -928,7 +974,7 @@ def test_motor_reverse(): def test_motor_reverse_nonpwm(): f = Device.pin_factory.pin(1) b = Device.pin_factory.pin(2) - with Motor(f, b, pwm=False) as device: + with Motor(1, 2, pwm=False) as device: device.forward() assert device.value == 1 assert b.state == 0 and f.state == 1 @@ -937,28 +983,28 @@ def test_motor_reverse_nonpwm(): assert b.state == 1 and f.state == 0 def test_servo_pins(): - p = Device.pin_factory.pin(1, pin_class=MockPWMPin) - with Servo(p) as device: + p = Device.pin_factory.pin(1) + with Servo(1) as device: assert device.pwm_device.pin is p assert isinstance(device.pwm_device, PWMOutputDevice) def test_servo_bad_value(): - p = Device.pin_factory.pin(1, pin_class=MockPWMPin) + p = Device.pin_factory.pin(1) with pytest.raises(ValueError): - Servo(p, initial_value=2) + Servo(1, initial_value=2) with pytest.raises(ValueError): - Servo(p, min_pulse_width=30/1000) + Servo(1, min_pulse_width=30/1000) with pytest.raises(ValueError): - Servo(p, max_pulse_width=30/1000) + Servo(1, max_pulse_width=30/1000) def test_servo_pins_nonpwm(): p = Device.pin_factory.pin(2) with pytest.raises(PinPWMUnsupported): - Servo(p) + Servo(1) def test_servo_close(): - p = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with Servo(p) as device: + p = Device.pin_factory.pin(2) + with Servo(1) as device: device.close() assert device.closed assert device.pwm_device.pin is None @@ -966,8 +1012,8 @@ def test_servo_close(): assert device.closed def test_servo_pulse_width(): - p = Device.pin_factory.pin(2, pin_class=MockPWMPin) - with Servo(p, min_pulse_width=5/10000, max_pulse_width=25/10000) as device: + p = Device.pin_factory.pin(2) + with Servo(1, min_pulse_width=5/10000, max_pulse_width=25/10000) as device: assert isclose(device.min_pulse_width, 5/10000) assert isclose(device.max_pulse_width, 25/10000) assert isclose(device.frame_width, 20/1000) @@ -980,8 +1026,8 @@ def test_servo_pulse_width(): assert device.pulse_width is None def test_servo_values(): - p = Device.pin_factory.pin(1, pin_class=MockPWMPin) - with Servo(p) as device: + p = Device.pin_factory.pin(1) + with Servo(1) as device: device.min() assert device.is_active assert device.value == -1 @@ -1007,14 +1053,14 @@ def test_servo_values(): assert device.value is None def test_angular_servo_range(): - p = Device.pin_factory.pin(1, pin_class=MockPWMPin) - with AngularServo(p, initial_angle=15, min_angle=0, max_angle=90) as device: + p = Device.pin_factory.pin(1) + with AngularServo(1, initial_angle=15, min_angle=0, max_angle=90) as device: assert device.min_angle == 0 assert device.max_angle == 90 def test_angular_servo_angles(): - p = Device.pin_factory.pin(1, pin_class=MockPWMPin) - with AngularServo(p) as device: + p = Device.pin_factory.pin(1) + with AngularServo(1) as device: device.angle = 0 assert device.angle == 0 assert isclose(device.value, 0) @@ -1026,7 +1072,7 @@ def test_angular_servo_angles(): assert isclose(device.value, -1) device.detach() assert device.angle is None - with AngularServo(p, initial_angle=15, min_angle=0, max_angle=90) as device: + with AngularServo(1, initial_angle=15, min_angle=0, max_angle=90) as device: assert device.angle == 15 assert isclose(device.value, -2/3) device.angle = 0 @@ -1037,7 +1083,7 @@ def test_angular_servo_angles(): assert isclose(device.value, 1) device.angle = None assert device.angle is None - with AngularServo(p, min_angle=45, max_angle=-45) as device: + with AngularServo(1, min_angle=45, max_angle=-45) as device: assert device.angle == 0 assert isclose(device.value, 0) device.angle = -45 diff --git a/tests/test_spi.py b/tests/test_spi.py index 6ae6967..f9dcf9f 100644 --- a/tests/test_spi.py +++ b/tests/test_spi.py @@ -33,50 +33,50 @@ def test_spi_hardware_params(): with patch('os.open'), patch('mmap.mmap') as mmap_mmap, patch('io.open') as io_open: mmap_mmap.return_value = array(nstr('B'), (0,) * 4096) io_open.return_value.__enter__.return_value = ['Revision: a21042'] - with patch('gpiozero.devices.Device.pin_factory', NativeFactory()), \ - patch('gpiozero.pins.local.SpiDev'): - with Device.pin_factory.spi() as device: + factory = NativeFactory() + with patch('gpiozero.pins.local.SpiDev'): + with factory.spi() as device: assert isinstance(device, LocalPiHardwareSPI) - with Device.pin_factory.spi(port=0, device=0) as device: + with factory.spi(port=0, device=0) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device.pin_factory.spi(port=0, device=1) as device: + with factory.spi(port=0, device=1) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device.pin_factory.spi(clock_pin=11) as device: + with factory.spi(clock_pin=11) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device.pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=8) as device: + with factory.spi(clock_pin=11, mosi_pin=10, select_pin=8) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device.pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=7) as device: + with factory.spi(clock_pin=11, mosi_pin=10, select_pin=7) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device.pin_factory.spi(shared=True) as device: + with factory.spi(shared=True) as device: assert isinstance(device, LocalPiHardwareSPIShared) with pytest.raises(ValueError): - Device.pin_factory.spi(port=1) + factory.spi(port=1) with pytest.raises(ValueError): - Device.pin_factory.spi(device=2) + factory.spi(device=2) with pytest.raises(ValueError): - Device.pin_factory.spi(port=0, clock_pin=12) + factory.spi(port=0, clock_pin=12) with pytest.raises(ValueError): - Device.pin_factory.spi(foo='bar') + factory.spi(foo='bar') def test_spi_software_params(): with patch('os.open'), patch('mmap.mmap') as mmap_mmap, patch('io.open') as io_open: mmap_mmap.return_value = array(nstr('B'), (0,) * 4096) io_open.return_value.__enter__.return_value = ['Revision: a21042'] - with patch('gpiozero.devices.Device.pin_factory', NativeFactory()), \ - patch('gpiozero.pins.local.SpiDev'): - with Device.pin_factory.spi(select_pin=6) as device: + factory = NativeFactory() + with patch('gpiozero.pins.local.SpiDev'): + with factory.spi(select_pin=6) as device: assert isinstance(device, LocalPiSoftwareSPI) - with Device.pin_factory.spi(clock_pin=11, mosi_pin=9, miso_pin=10) as device: + with factory.spi(clock_pin=11, mosi_pin=9, miso_pin=10) as device: assert isinstance(device, LocalPiSoftwareSPI) - with Device.pin_factory.spi(select_pin=6, shared=True) as device: + with factory.spi(select_pin=6, shared=True) as device: assert isinstance(device, LocalPiSoftwareSPIShared) - with patch('gpiozero.devices.Device.pin_factory', NativeFactory()), \ - patch('gpiozero.pins.local.SpiDev', None): - # Clear out the old factory's pins cache (this is only necessary - # because we're being very naughty switching out pin factories) - Device.pin_factory.pins.clear() + with patch('gpiozero.pins.local.SpiDev', None): + # Clear out the old factory's caches (this is only necessary because + # we're being naughty switching out patches) + factory.pins.clear() + factory._reservations.clear() # Ensure software fallback works when SpiDev isn't present - with Device.pin_factory.spi() as device: + with factory.spi() as device: assert isinstance(device, LocalPiSoftwareSPI) def test_spi_hardware_conflict():