Gpiozero: "import gpiozero" shouldn't fail without a valid pin factory

Created on 30 Oct 2017  路  11Comments  路  Source: gpiozero/gpiozero

The following example is a valid method of setting the pin factory to mock:

import gpiozero
from gpiozero.pins.mock import MockFactory
gpiozero.Device.pin_factory = MockFactory()

but it only works if import gpiozero is successful, having found a valid pin factory.

If you're on a Raspberry Pi, that's easy - you just install rpi.gpio (even if you don't intend to use it).

If you're on a PC, the following will happen:

  • rpi.gpio will fail (even if it's installed - can only be run on a Pi)
  • rpio will fail (even it it's installed - can only be run on a Pi)
  • pigpio will fail (even if it's installed - pigpiod not running on localhost)
  • native will fail (can't access /dev/mem)

And it runs out of options.

The only way to get it to work is to set the pin factory in an environment variable.

It would be nice if you could get past import gpiozero, and if no pin factory is found, it's set to None and fails when you try to create a device. Would that be that possible?

bug

Most helpful comment

In case anyone else hits this, hacky workaround:

import os
os.environ['GPIOZERO_PIN_FACTORY'] = os.environ.get('GPIOZERO_PIN_FACTORY', 'mock')
import gpiozero

NOTE from gpiozero.pins.mock import MockFactory as documented in https://gpiozero.readthedocs.io/en/stable/api_pins.html#mock-pins isn't needed with this (nor does it work without this). Setting the explicit mock factory is not required.

All 11 comments

This would also resolve the issue with pinout on PCs needing pin factory set.

+1

This should probably be explained in the documentation in the meantime, I spent a while trying to figure out why the example code here was throwing errors when trying to run on my laptop without a pi connected.

I am frustated with this thing. Why does a mock exist, when you can't even use it on a PC?

In [3]: from gpiozero.pins.mock import MockFactory
/home/dev/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py:452: PinFactoryFallback: Falling back from rpigpio: No module named 'RPi'
  'Falling back from %s: %s' % (name, str(e))))
/home/dev/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py:452: PinFactoryFallback: Falling back from rpio: No module named 'RPIO'
  'Falling back from %s: %s' % (name, str(e))))
/home/dev/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py:452: PinFactoryFallback: Falling back from pigpio: No module named 'pigpio'
  'Falling back from %s: %s' % (name, str(e))))
/home/dev/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py:452: PinFactoryFallback: Falling back from native: unable to open /dev/gpiomem or /dev/mem; upgrade your kernel or run as root
  'Falling back from %s: %s' % (name, str(e))))
---------------------------------------------------------------------------
BadPinFactory                             Traceback (most recent call last)
<ipython-input-3-456f994e72a8> in <module>()
----> 1 from gpiozero.pins.mock import MockFactory

~/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/pins/mock.py in <module>()
     26     PinInvalidPull,
     27     )
---> 28 from ..devices import Device
     29 from .pi import PiPin
     30 from .local import LocalPiFactory

~/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/__init__.py in <module>()
     20 # contamination here ... and besides, have you *seen* the list lately?!
     21 from .exc import *
---> 22 from .devices import (
     23     Device,
     24     GPIODevice,

~/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py in <module>()
    484 
    485 
--> 486 Device.pin_factory = _default_pin_factory()
    487 atexit.register(_shutdown)

~/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py in _default_pin_factory(name)
    451                     PinFactoryFallback(
    452                         'Falling back from %s: %s' % (name, str(e))))
--> 453         raise BadPinFactory('Unable to load any default pin factory!')
    454     else:
    455         # Try with the name verbatim first. If that fails, attempt with the

BadPinFactory: Unable to load any default pin factory!

when i run it as root

In [1]: from gpiozero.pins.mock import MockFactory
/home/dev/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py:452: PinFactoryFallback: Falling back from rpigpio: No module named 'RPi'
  'Falling back from %s: %s' % (name, str(e))))
/home/dev/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py:452: PinFactoryFallback: Falling back from rpio: No module named 'RPIO'
  'Falling back from %s: %s' % (name, str(e))))
/home/dev/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py:452: PinFactoryFallback: Falling back from pigpio: No module named 'pigpio'
  'Falling back from %s: %s' % (name, str(e))))
/home/dev/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py:452: PinFactoryFallback: Falling back from native: unable to determine peripheral base
  'Falling back from %s: %s' % (name, str(e))))
---------------------------------------------------------------------------
BadPinFactory                             Traceback (most recent call last)
<ipython-input-1-456f994e72a8> in <module>()
----> 1 from gpiozero.pins.mock import MockFactory

~/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/__init__.py in <module>()
     20 # contamination here ... and besides, have you *seen* the list lately?!
     21 from .exc import *
---> 22 from .devices import (
     23     Device,
     24     GPIODevice,

~/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py in <module>()
    484 
    485 
--> 486 Device.pin_factory = _default_pin_factory()
    487 atexit.register(_shutdown)

~/.pyenv/versions/3.6.4/lib/python3.6/site-packages/gpiozero/devices.py in _default_pin_factory(name)
    451                     PinFactoryFallback(
    452                         'Falling back from %s: %s' % (name, str(e))))
--> 453         raise BadPinFactory('Unable to load any default pin factory!')
    454     else:
    455         # Try with the name verbatim first. If that fails, attempt with the

BadPinFactory: Unable to load any default pin factory!

I am frustated with this thing. Why does a mock exist, when you can't even use it on a PC?

@devxpy It does. You just have to set it in an environment variable, like I said above.

I see you're running on Linux so you should be able to launch IPython with the env var set in-line:

$ GPIOZERO_PIN_FACTORY=mock ipython

or export it:

$ export GPIOZERO_PIN_FACTORY=mock
$ ipython

or add it to your .bashrc or equivalent.

This issue points out that it's not currently possible to set the pin factory to mock if the default pin factory fails to load. There are situations where it does, like on a Pi, but as you have also discovered, there are situations where it doesn't, and it's impossible to import without a fatal error.

For now, this is easily resolved by setting the pin factory to mock in an environment variable, and we'll try to fix it for the next release.

@bennuttall. I'm sorry, i was in a virtualenv and was exporting outside the virtualenv

How about if importing gpiozero without a valid pin factory just shows a warning?

>>> import gpiozero
Warning: No default pin factory found. Please set gpiozero.Device.pin_factory
>>> led = LED(2)
InvalidPinFactory: No default pin factory set
>>> gpiozero.Device.pin_factory = MockFactory()
>>> led = LED(2)
>>> led
<gpiozero.LED object on pin GPIO2, active_high=True, is_active=False>

@waveform80 agrees - let's get this in v1.5

In case anyone else hits this, hacky workaround:

import os
os.environ['GPIOZERO_PIN_FACTORY'] = os.environ.get('GPIOZERO_PIN_FACTORY', 'mock')
import gpiozero

NOTE from gpiozero.pins.mock import MockFactory as documented in https://gpiozero.readthedocs.io/en/stable/api_pins.html#mock-pins isn't needed with this (nor does it work without this). Setting the explicit mock factory is not required.

Note that if/when this gets fixed, the note I added to the docs will need removing: https://gpiozero.readthedocs.io/en/latest/remote_gpio.html#pin-factories

Note that if/when this gets fixed, the note I added to the docs will need removing: https://gpiozero.readthedocs.io/en/latest/remote_gpio.html#pin-factories

Seems that #722 forgot to do that? :wink:

EDIT: But #727 fixed this :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tombennet picture tombennet  路  12Comments

claussoegaard picture claussoegaard  路  10Comments

bootsmann picture bootsmann  路  8Comments

Martchus picture Martchus  路  8Comments

lurch picture lurch  路  6Comments