0

Short version of the question:

How do I prevent python interpreter to see and import modules that are not installed; do not belong to the system I am using; and are not required if I choose to run the code under System X instead of System Y?

From a C perspective I would do something on those lines:

#if defined(__SerialCOM__)
// Do stuff, import stuff
#elif defined(__SPI_Over_Raspberry__)
// Do stuff, import stuff
#elif defined(__SPI_Over_BeagleBone__)
// Do stuff, import stuff
#endif

I would like to avoid creating different projects for different boards. This I know how to do.


Long Version

I am trying to implement in my project an interface to communicate to an ADC IC from texas. The end goal is to be able to read from it with several different devices:

ADC <---SPIbus (With C code)---> ArduinoDue <-----Serial (With Python)----> LinuxPC
ADC <---SPIbus (With Python)---> Raspberry Pi3
ADC <---SPIbus (With Python)---> BeagleBone Black
ADC <---SPIbus (With Python)---> Intel Edson

For such, I created an interface, that receives a reader object, this reader object inherits from an abstract reader class.

I would like to avoid creating different projects for different boards. This I know how to do.

readerhandler.py

from readers import SerialReader,PiSPIreader


class ReaderHandler:
    def __init__(self, readertype="PiSPI"):
        self.reader = self.getreader(readertype)

    def getreader(self, readertype):
        aReader = []
        if readertype == "PiSPI":
            aReader = PiSPIreader()
        elif readertype == "Serial":
            aReader = SerialReader()
        elif readertype == "BBSPI":
            aReader = BBSPIreader()
        else:
            print("reader type invalid")
        return aReader
    # Do other stuff

readers.py

from abc import ABCMeta, abstractmethod
import serial  # For Serial Reader object (Should only be interpreted in a pc device)
import piSPI  # For piSPI Reader object (Should only be interpreted in a RasberryPi device)
import bbSPI  # For bbSPI Reader object (Should only be interpreted in a BeagleBone Black device)


class Reader(object): # My abstract class
    __metaclass__ = ABCMeta

    @abstractmethod
    def initialization(self):
    """Acquisitions setup"""

    @abstractmethod
    def _run(self):
        """function that acquires sample from device port on the bakcground"""

    @abstractmethod
    def readdata(self, nofsamples=100):
    """Read X buffered samples"""

class SerialReader(Reader): # (Should only be interpreted in a PC device)
    def __init__(self, portname='/dev/ttyACM2', baudrate=115200, magic0=0x42, magic1=0x41):
        super(SerialReader, self).__init__()
        self.ser = serial.Serial(portname, baudrate=baudrate, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=None)

    # Implements other abstract methods and **uses Serial object***


class PiSPIreader(Reader): # (Should only be interpreted in a Rasberry device)
    def __init__(self):
        super(PiSPIreader, self).__init__()
        self.piSPI = piSPI.SPI()

    # Implements other abstract methods and **uses piSPI object***


class BBSPIreader(Reader): # (Should only be interpreted in a BeagleBone Black device)
    def __init__(self):
        super(BBSPIreader, self).__init__()
        self.bbSPI = bbSPI.SPI()

    # Implements other abstract methods and **uses bbSPI object***
nico
  • 1,136
  • 1
  • 15
  • 33
  • What do you mean by "system"? It's already not possible for Python to import modules that aren't available. – BrenBarn Apr 11 '16 at 18:03
  • @BrenBarn , I mean different linux machines which do not have the same available modules. Like 'import Adafruit_BBIO' (BBB) or 'import RPi' (Raspberry). I don't plan to install these modules on systems that are not worth installing. – nico Apr 11 '16 at 18:15

2 Answers2

1

Use try/except.

try:
    import serial
except ImportError:
    pass    # couldn't import serial, so do nothing
else:       # we successfully imported serial, so define the class that uses it

    class SerialReader(Reader): # (Should only be interpreted in a PC device)
        def __init__(self, portname='/dev/ttyACM2', baudrate=115200, magic0=0x42, magic1=0x41):
            super(SerialReader, self).__init__()
            self.ser = serial.Serial(portname, baudrate=baudrate, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=None)

        # Implements other abstract methods and **uses Serial object***
kindall
  • 178,883
  • 35
  • 278
  • 309
  • This is the right answer, but in practice it probably makes more sense to split the device-dependent code into separate device-specific modules, and then use code like this to decide which of them to import, rather than doing this sort of thing multiple times inside one big module. – BrenBarn Apr 11 '16 at 18:17
  • @kindall This is precisely what I wanted. What error does it raises when I try to call a constructor that was not a match for the platform `aReader = SerialReader()` ?. IE. class does not exist after try/ except – nico Apr 11 '16 at 18:24
  • It'll raise `NameError` in that case. – kindall Apr 11 '16 at 18:25
  • @BrenBarn This was the idea. I believe I will just have this N times for N devices. How could I improve that? My problematic sytem imports are actually inside the piSPI.py and bbSPI.py. – nico Apr 11 '16 at 18:30
1

How to check if a python module exists without importing it

you may also use os.name, for detecting the device kind.

Community
  • 1
  • 1
SocketPlayer
  • 166
  • 6