Skip to content

Python: Do not do I/O in __init__() #1

@uSpike

Description

@uSpike

It's bad practice to do I/O inside __init__ which should only initialize the class instance.

self._card_rev_major = self.bus.read_byte_data(self._hw_address_, I2C_MEM.REVISION_HW_MAJOR_ADD)

class SM16uout: 
    """Python class to control the Sixteen 0-10V Analog Outputs

    Args:
        stack (int): Stack level/device number.
        i2c (int): i2c bus number
    """
    def __init__(self, stack=0, i2c=1):
        if stack < 0 or stack > data.STACK_LEVEL_MAX:
            raise ValueError("Invalid stack level!")
        self._hw_address_ = data.SLAVE_OWN_ADDRESS_BASE + stack
        self._i2c_bus_no = i2c
        self.bus = SMBus(self._i2c_bus_no)
        try:
            self._card_rev_major = self.bus.read_byte_data(self._hw_address_, I2C_MEM.REVISION_HW_MAJOR_ADD)
            self._card_rev_minor = self.bus.read_byte_data(self._hw_address_, I2C_MEM.REVISION_HW_MINOR_ADD)
        except Exception:
            print("{} not detected!".format(data.CARD_NAME))
            raise

This creates a real problem with the hardware, this program doesn't work:

from SM16uout import SM16uout

m = SM16uout()
m.set_led(0, 1)
Traceback (most recent call last):
  File "/home/pi/script.py", line 8, in <module>
    m.set_led(0, 1)
  File "/home/pi/venv/lib/python3.11/site-packages/SM16uout/__init__.py", line 165, in set_led
    self._set_byte(I2C_MEM.LED_SET, led)
  File "/home/pi/venv/lib/python3.11/site-packages/SM16uout/__init__.py", line 56, in _set_byte
    self.bus.write_byte_data(self._hw_address_, address, int(value))
  File "/home/pi/venv/lib/python3.11/site-packages/smbus2/smbus2.py", line 457, in write_byte_data
    ioctl(self.fd, I2C_SMBUS, msg)
OSError: [Errno 5] Input/output error

It seems that your embedded controller doesn't accept new commands quickly after reading the card rev data, so it's necessary to add a time.sleep(0.1) after creating the SM16uout class.


self._card_rev_major and self._card_rev_minor are not used, I recommend removing them. Or, make a property:

    @property
    def card_rev(self):
        major = self.bus.read_byte_data(self._hw_address_, I2C_MEM.REVISION_HW_MAJOR_ADD)
        minor = self.bus.read_byte_data(self._hw_address_, I2C_MEM.REVISION_HW_MINOR_ADD)
        return (major, minor)

This way you won't do any I/O unless the user asks for it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions