Ben Bass avatar Ben Bass committed fed55e4

flake8 fixups; improve and extend tests

Comments (0)

Files changed (20)

 *.pyc
 *.pyo
 .idea
+build
 docs/_build
 MANIFEST
 pylibftdi changes
 =================
 
+0.9pre
+ * improved and extended tests
+ * added some Sphinx-based documentation
+ * allow the PID/VID to be changed
+ * add new example - basic web server to toggle / read IO bits
 0.8.1
  * fix issue with bitbang following API changes in 0.8
  * add tests for bitbang mode
 # All configuration values have a default; values that are commented out
 # serve to show the default.
 
-import sys, os
+import sys
+import os
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the

pylibftdi/__init__.py

 
 
 __ALL__ = ['Driver', 'Device', 'BitBangDevice', 'Bus', 'FtdiError',
-           'ALL_OUTPUTS', 'ALL_INPUTS', 'BB_OUTPUT', 'BB_INPUT']
+           'ALL_OUTPUTS', 'ALL_INPUTS', 'BB_OUTPUT', 'BB_INPUT',
+           'examples', 'tests']
 
 from pylibftdi import _base, driver, util, bitbang
 
 
 # LEGACY SUPPORT
 
+
 class BitBangDriver(bitbang.BitBangDevice):
     def __init__(self, direction=ALL_OUTPUTS):
         import warnings

pylibftdi/_base.py

 
 __ALL__ = ['Refuser', 'ParrotEgg', 'DeadParrot', 'FtdiError']
 
+
 class Refuser(object):
+
     def __getattribute__(self, key):
         # perhaps we should produce an appropriate quote at random...
         raise TypeError(object.__getattribute__(self, 'message'))
+
     def __setattr__(self, key, val):
         raise TypeError(object.__getattribute__(self, 'message'))
+
     def __call__(self, *o, **kw):
         raise TypeError(object.__getattribute__(self, 'message'))
 
+
 class ParrotEgg(Refuser):
     message = "This object is not yet... (missing open()?)"
 
+
 class DeadParrot(Refuser):
     message = "This object is no more!"
 
+
 class FtdiError(Exception):
     pass
-

pylibftdi/bitbang.py

 BB_OUTPUT = 1
 BB_INPUT = 0
 
+
 class BitBangDevice(Device):
     """
     simple subclass to support bit-bang mode
      port: 8 bit IO port, as defined by direction.
     """
     def __init__(self,
-                 device_id = None,
-                 direction = ALL_OUTPUTS,
-                 lazy_open = False):
+                 device_id=None,
+                 direction=ALL_OUTPUTS,
+                 lazy_open=False):
         # initialise the super-class, but don't open yet. We really want
         # two-part initialisation here - set up all the instance variables
         # here in the super class, then open it after having set more
         # of our own variables.
-        super(BitBangDevice, self).__init__(device_id = device_id,
-                                            mode = 'b',
-                                            lazy_open = True)
+        super(BitBangDevice, self).__init__(device_id=device_id,
+                                            mode='b',
+                                            lazy_open=True)
         self.direction = direction
         self._last_set_dir = None
         self._latch = 0
             self.direction = self._direction
         return self
 
-
     # direction property - 8 bit value determining whether an IO line
     # is output (if set to 1) or input (set to 0)
     @property
             self.ftdi_fn.ftdi_set_bitmode(dir, 0x01)
             self._last_set_dir = dir
 
-
     # port property - 8 bit read/write value
     @property
     def port(self):
     def port(self, value):
         self._latch = value
         return super(BitBangDevice, self).write(chr(value))
-

pylibftdi/driver.py

 
 from pylibftdi._base import FtdiError
 
+
 class UsbDevList(Structure):
     _fields_ = [('next', c_void_p),
                 ('usb_dev', c_void_p)]
 # (at least for 64-bit) they only worked if argtypes was declared
 # (c_void_p for ctx), and that's too much like hard work to maintain.
 # So I've reverted to using create_string_buffer for memory management,
-# byref(ctx) to pass in the context instance, and ftdi_init() / 
+# byref(ctx) to pass in the context instance, and ftdi_init() /
 # ftdi_deinit() pair to manage the driver resources. It's very nice
 # how layered the libftdi code is, with access to each layer.
 
 USB_VID = 0x0403
 USB_PID = 0x6001
 
+
 class Driver(object):
     """
     This is where it all happens...
     LEGACY_ATTRIBUTES = ['open', 'close', 'ftdi_fn', 'baudrate',
                          'read', 'write', 'get_error_string',
                          '__enter__', '__exit__']
+
     @property
     def legacy_device(self):
         warnings.warn("using Device() methods on Driver(); see CHANGES.txt",
             return getattr(self.legacy_device, key)
         else:
             return object.__getattr__(self, key)
+
     def __setattr__(self, key, value):
         if key in Driver.LEGACY_ATTRIBUTES:
             return setattr(self.legacy_device, key, value)
         else:
             self.__dict__[key] = value
+
     def __delattr__(self, key):
         if key in Driver.LEGACY_ATTRIBUTES:
             delattr(self.legacy_device, key)
                     while dev_list_ptr:
                         self.fdll.ftdi_usb_get_strings(byref(ctx),
                                 dev_list_ptr.contents.usb_dev,
-                                manuf,127, desc,127, serial,127)
+                                manuf, 127, desc, 127, serial, 127)
                         devices.append((manuf.value, desc.value, serial.value))
                         # step to next in linked-list if not
                         dev_list_ptr = cast(dev_list_ptr.contents.next,
         # fdll and ctx objects in the closure are up-to-date, though.
         class FtdiForwarder(object):
             def __getattr__(innerself, key):
-                 return functools.partial(getattr(self.fdll, key),
-                                          byref(self.ctx))
+                return functools.partial(getattr(self.fdll, key),
+                                         byref(self.ctx))
         return FtdiForwarder()
 
-
     def __enter__(self):
         """
         support for context manager.
             else:
                 raise StopIteration
     next = __next__
-

pylibftdi/examples/bit_server.py

  - pylibftdi
 """
 
+import sys
+import threading
+import time
+import webbrowser
 from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
 from cStringIO import StringIO
 from SocketServer import ThreadingMixIn
-import sys
 from pylibftdi import BitBangDevice
 
 HTTP_PORT = 8008
 <div>
 """ % port
     for i in range(8):
-        bit = 7-i
+        bit = 7 - i
         is_on = port & (1 << bit)
         color = '#00FF00' if is_on else '#FF0000'
         page += """
 """ % port
     return page
 
+
 class ReqHandler(BaseHTTPRequestHandler):
     def do_GET(self):
         f = self.send_head()
             if value:
                 switch.port |= (1 << bit)
             else:
-                switch.port &= 255^(1 << bit)
+                switch.port &= 255 ^ (1 << bit)
 
         f = self.send_head()
         if f:
         self.end_headers()
         return f
 
-def runserver(port = HTTP_PORT):
+
+def runserver(port=HTTP_PORT):
     serveraddr = ('', port)
     srvr = ThreadingServer(serveraddr, ReqHandler)
     srvr.serve_forever()
 
 if __name__ == '__main__':
-    import threading, time, webbrowser
     switch = BitBangDevice()
 
     try:
     except IndexError:
         pass
 
-    t = threading.Thread(target = runserver, args = (HTTP_PORT,))
+    t = threading.Thread(target=runserver, args=(HTTP_PORT,))
     t.setDaemon(True)
     t.start()
     time.sleep(0.5)
     retry = 10
     while retry:
         try:
-            webbrowser.open('http://localhost:%d'%HTTP_PORT)
+            webbrowser.open('http://localhost:%d' % HTTP_PORT)
         except EnvironmentError:
             time.sleep(1)
             retry -= 1
 
     # wait for Ctrl-C
     try:
-        while 1: time.sleep(1)
+        while 1:
+            time.sleep(1)
     except KeyboardInterrupt:
         pass

pylibftdi/examples/lcd.py

         # attribute which provides a port
         self.driver = driver
 
+    def _trigger(self):
+        "generate a falling edge"
+        self.e = 1
+        self.e = 0
+
     def init_four_bit(self):
         """
         set the LCD's 4 bit mode, since we only have
         """
         self.rs = 0
         self.data = 3
-        self.e = 1; self.e = 0
-        self.e = 1; self.e = 0
-        self.e = 1; self.e = 0
+        for _ in range(3):
+            self._trigger()
         self.data = 2
-        self.e = 1; self.e = 0
+        self._trigger()
 
     def _write_raw(self, rs, x):
         # rs determines whether this is a command
         # nibbles. Ahhh... nibbles. QBasic anyone?
         self.rs = rs
         self.data = x >> 4
-        self.e = 1; self.e = 0
+        self._trigger()
         self.data = x & 0x0F
-        self.e = 1; self.e = 0
+        self._trigger()
 
     def write_cmd(self, x):
         self._write_raw(0, x)
     def write_data(self, x):
         self._write_raw(1, x)
 
+
 def display(string, device_id=None):
     """
     Display the given string on an attached LCD

pylibftdi/examples/led_flash.py

 import time
 from pylibftdi import BitBangDriver
 
+
 def flash_forever(rate):
     "toggle bit zero at rate Hz"
     # put an LED with 1Kohm or similar series resistor
     # on D0 pin
     with BitBangDriver() as bb:
         while True:
-            time.sleep(1.0/(2*rate))
+            time.sleep(1.0 / (2 * rate))
             bb.port ^= 1
 
 if __name__ == '__main__':

pylibftdi/test_bitbang.py

-"""
-pylibftdi - python wrapper for libftdi
-
-Copyright (c) 2010-2011 Ben Bass <benbass@codedstructure.net>
-See LICENSE file for details and (absence of) warranty
-
-pylibftdi: http://bitbucket.org/codedstructure/pylibftdi
-
-This module contains some basic tests for the higher-level
-functionality without requiring an actual hardware device
-to be attached.
-"""
-
-from test_common import (LoopDevice, CallCheckMixin, unittest)
-from pylibftdi.bitbang import BitBangDevice
-from pylibftdi import FtdiError
-
-class TestBitBangDevice(BitBangDevice, LoopDevice):
-    pass
-
-BitBangDevice = TestBitBangDevice
-
-# and now some test cases...
-class BitBangFunctions(unittest.TestCase, CallCheckMixin):
-
-    def testContextManager(self):
-        def _():
-            with BitBangDevice() as dev:
-                pass
-        self.assertCallsExact(_,
-                ['ftdi_init', 'ftdi_usb_open',
-                 'ftdi_set_bitmode',
-                 'ftdi_usb_close', 'ftdi_deinit'])
-
-    def testOpen(self):
-        """
-        check same opening things as a normal Device still work
-        for BitBangDevice
-        """
-        # a lazy_open open() shouldn't do anything
-        self.assertCallsExact(lambda: BitBangDevice(lazy_open=True), [])
-        # a non-lazy_open open() should open the port...
-        self.assertCalls(lambda: BitBangDevice(), 'ftdi_usb_open')
-        # and set the bit mode
-        self.assertCalls(lambda: BitBangDevice(), 'ftdi_set_bitmode')
-        # and given a device_id, it should do a open_desc
-        self.assertCalls(lambda: BitBangDevice('bogus'), 'ftdi_usb_open_desc')
-
-    def testInitDirection(self):
-        # check that a direction can be given on open and is honoured
-        for dir_test in (0,1,4,12,120,255):
-
-            dev = BitBangDevice(direction = dir_test)
-            self.assertEqual(dev.direction, dir_test)
-            self.assertEqual(dev._direction, dir_test)
-            self.assertEqual(dev._last_set_dir, dir_test)
-        # check an invalid direction on open gives error
-        self.assertRaises(FtdiError, lambda: BitBangDevice(direction=300))
-
-    def testDirection(self):
-        dev = BitBangDevice()
-        # check that a direction can be given on open and is honoured
-        for dir_test in (0,1,4,12,120,255):
-            def _(dt):
-                dev.direction = dt
-            self.assertCalls(lambda : _(dir_test), 'ftdi_set_bitmode')
-            self.assertEqual(dev.direction, dir_test)
-            self.assertEqual(dev._direction, dir_test)
-            self.assertEqual(dev._last_set_dir, dir_test)
-        # check an invalid direction on open gives error
-        def _():
-            dev.direction = 300
-        self.assertRaises(FtdiError, _)
-
-    def testPort(self):
-        dev = BitBangDevice()
-        # check that a direction can be given on open and is honoured
-        for port_test in (0,1,4,12,120,255):
-            def _(pt):
-                dev.port = pt
-            self.assertCalls(lambda : _(port_test), 'ftdi_write_data')
-            self.assertEqual(dev._latch, port_test)
-            self.assertEqual(dev.port, port_test)
-        # XXX: this is incomplete.
-        # could check for various directions and how that impacts
-        # port read / write, as well as r/m/w operations.
-
-if __name__ == "__main__":
-    unittest.main()
-

pylibftdi/test_common.py

-"""
-pylibftdi - python wrapper for libftdi
-
-Copyright (c) 2010-2011 Ben Bass <benbass@codedstructure.net>
-See LICENSE file for details and (absence of) warranty
-
-pylibftdi: http://bitbucket.org/codedstructure/pylibftdi
-
-This module contains some basic tests for the higher-level
-functionality without requiring an actual hardware device
-to be attached.
-"""
-
-import sys
-if sys.version_info < (2,7):
-    try:
-        import unittest2 as unittest
-    except ImportError:
-        raise SystemExit("The test functionality is only supported in"
-                "Python 2.7+ unless unittest2 is installed")
-else:
-    import unittest
-
-VERBOSE = False
-
-class SimpleMock(object):
-    """
-    This is a simple mock plugin for fdll which logs any calls
-    made through it to fn_log, which is currently rather ugly
-    global state.
-    """
-    def __init__(self, name="<base>"):
-        self.__name = name
-
-    def __getattr__(self, key):
-        return SimpleMock(key)
-
-    def __call__(self, *o, **k):
-        CallLog.append(self.__name)
-        if VERBOSE:
-            print("%s(*%s, **%s)" % (self.__name, o, k))
-        return 0
-
-class CallLog(object):
-
-    fn_log = []
-
-    @classmethod
-    def reset(cls):
-        del cls.fn_log[:]
-
-    @classmethod
-    def append(cls, value):
-        cls.fn_log.append(value)
-
-    @classmethod
-    def get(cls):
-        return cls.fn_log[:]
-
-class CallCheckMixin(object):
-    """
-    this should be used as a mixin for unittest.TestCase classes,
-    where it allows the calls through the MockDriver to be checked
-    this does not support multi-threading.
-    """
-    def assertCalls(self, fn, methodname):
-        CallLog.reset()
-        fn()
-        self.assertIn(methodname, CallLog.get())
-
-    def assertCallsExact(self, fn, call_list):
-        CallLog.reset()
-        fn()
-        self.assertEqual(call_list, CallLog.get())
-
-
-# monkey patch the Driver class to be the mock thing above.
-class MockDriver(object):
-    def __init__(self, *o, **k):
-        self.fdll = SimpleMock()
-
-
-import pylibftdi.driver
-from pylibftdi.driver import Device
-
-class LoopDevice(Device):
-    """
-    a mock device object which overrides read and write
-    to operate as an unbounded loopback pair
-    """
-    def __init__(self, *o, **k):
-        super(LoopDevice, self).__init__(*o, **k)
-        self.__buffer = []
-
-    def _read(self, size):
-        super(LoopDevice, self)._read(size)  # discard result
-        result = bytes(bytearray(self.__buffer[:size]))
-        self.__buffer = self.__buffer[size:]
-        return result
-
-    def _write(self, data):
-        super(LoopDevice, self)._write(data)  # discard result
-        self.__buffer.extend(bytearray(data))
-        return len(data)
-
-# importing this _does_ things...
-pylibftdi.driver.Driver = MockDriver
-
-if set(['-v', '--verbose']) & set(sys.argv):
-    VERBOSE = True

pylibftdi/test_driver.py

-"""
-pylibftdi - python wrapper for libftdi
-
-Copyright (c) 2010-2011 Ben Bass <benbass@codedstructure.net>
-See LICENSE file for details and (absence of) warranty
-
-pylibftdi: http://bitbucket.org/codedstructure/pylibftdi
-
-This module contains some basic tests for the higher-level
-functionality without requiring an actual hardware device
-to be attached.
-"""
-
-from test_common import (LoopDevice, Device, CallCheckMixin, unittest)
-
-# and now some test cases...
-
-class DeviceFunctions(unittest.TestCase, CallCheckMixin):
-
-    def testContextManager(self):
-        def _():
-            with Device() as dev:
-                pass
-        self.assertCallsExact(_,
-                ['ftdi_init', 'ftdi_usb_open',
-                 'ftdi_usb_close', 'ftdi_deinit'])
-
-    def testOpen(self):
-        # a lazy_open open() shouldn't do anything
-        self.assertCallsExact(lambda: Device(lazy_open=True), [])
-        # a non-lazy_open open() should open the port...
-        self.assertCalls(lambda: Device(), 'ftdi_usb_open')
-        # and given a device_id, it should do a open_desc
-        self.assertCalls(lambda: Device('bogus'), 'ftdi_usb_open_desc')
-
-    def testReadWrite(self):
-        with Device() as dev:
-            self.assertCalls(lambda : dev.write('xxx'), 'ftdi_write_data')
-            self.assertCalls(lambda : dev.read(10), 'ftdi_read_data')
-
-    def testFlush(self):
-        with Device() as dev:
-            self.assertCalls(dev.flush_input, 'ftdi_usb_purge_rx_buffer')
-            self.assertCalls(dev.flush_output, 'ftdi_usb_purge_tx_buffer')
-            self.assertCalls(dev.flush, 'ftdi_usb_purge_buffers')
-
-class LoopbackTest(unittest.TestCase):
-    """
-    these all require mode='t' to pass in Python3
-    """
-
-    def testPrint(self):
-        d = LoopDevice(mode='t')
-        d.write('Hello')
-        d.write(' World\n')
-        d.write('Bye')
-        self.assertEqual(d.readline(), 'Hello World\n')
-        self.assertEqual(d.readline(), 'Bye')
-
-    def testLines(self):
-        d = LoopDevice(mode='t')
-        lines = ['Hello\n', 'World\n', 'And\n', 'Goodbye\n']
-        d.writelines(lines)
-        self.assertEqual(d.readlines(), lines)
-
-    def testIterate(self):
-        d = LoopDevice(mode='t')
-        lines = ['Hello\n', 'World\n', 'And\n', 'Goodbye\n']
-        d.writelines(lines)
-        for idx,line in enumerate(d):
-            self.assertEqual(line, lines[idx])
-
-
-if __name__ == "__main__":
-    unittest.main()

pylibftdi/tests/__init__.py

+"""tests for pylibftdi"""

pylibftdi/tests/test_all.py

+
+#from pylibftdi.tests.test_common import unittest
+#from pylibftdi.tests import test_bitbang, test_driver
+
+#unittest.main()

pylibftdi/tests/test_bitbang.py

+"""
+pylibftdi - python wrapper for libftdi
+
+Copyright (c) 2010-2011 Ben Bass <benbass@codedstructure.net>
+See LICENSE file for details and (absence of) warranty
+
+pylibftdi: http://bitbucket.org/codedstructure/pylibftdi
+
+This module contains some basic tests for the higher-level
+functionality without requiring an actual hardware device
+to be attached.
+"""
+
+from pylibftdi.tests.test_common import (LoopDevice, CallCheckMixin, unittest)
+from pylibftdi.bitbang import BitBangDevice
+from pylibftdi import FtdiError
+
+
+class TestBitBangDevice(BitBangDevice, LoopDevice):
+    pass
+
+BitBangDevice = TestBitBangDevice
+
+
+# and now some test cases...
+class BitBangFunctions(CallCheckMixin, unittest.TestCase):
+
+    def testContextManager(self):
+        def _():
+            with BitBangDevice():
+                pass
+        self.assertCallsExact(_,
+                ['ftdi_init', 'ftdi_usb_open',
+                 'ftdi_set_bitmode',
+                 'ftdi_usb_close', 'ftdi_deinit'])
+
+    def testOpen(self):
+        """
+        check same opening things as a normal Device still work
+        for BitBangDevice
+        """
+        # a lazy_open open() shouldn't do anything
+        self.assertCallsExact(lambda: BitBangDevice(lazy_open=True), [])
+        # a non-lazy_open open() should open the port...
+        self.assertCalls(lambda: BitBangDevice(), 'ftdi_usb_open')
+        # and set the bit mode
+        self.assertCalls(lambda: BitBangDevice(), 'ftdi_set_bitmode')
+        # and given a device_id, it should do a open_desc
+        self.assertCalls(lambda: BitBangDevice('bogus'), 'ftdi_usb_open_desc')
+
+    def testInitDirection(self):
+        # check that a direction can be given on open and is honoured
+        for dir_test in (0, 1, 4, 12, 120, 255):
+
+            dev = BitBangDevice(direction=dir_test)
+            self.assertEqual(dev.direction, dir_test)
+            self.assertEqual(dev._direction, dir_test)
+            self.assertEqual(dev._last_set_dir, dir_test)
+        # check an invalid direction on open gives error
+        self.assertRaises(FtdiError, lambda: BitBangDevice(direction=300))
+
+    def testDirection(self):
+        dev = BitBangDevice()
+        # check that a direction can be given on open and is honoured
+        for dir_test in (0, 1, 4, 12, 120, 255):
+            def _(dt):
+                dev.direction = dt
+            self.assertCalls(lambda: _(dir_test), 'ftdi_set_bitmode')
+            self.assertEqual(dev.direction, dir_test)
+            self.assertEqual(dev._direction, dir_test)
+            self.assertEqual(dev._last_set_dir, dir_test)
+        # check an invalid direction on open gives error
+        def _():  # NOQA
+            dev.direction = 300
+        self.assertRaises(FtdiError, _)
+
+    def testPort(self):
+        dev = BitBangDevice()
+        # check that a direction can be given on open and is honoured
+        for port_test in (0, 1, 4, 12, 120, 255):
+            def _(pt):
+                dev.port = pt
+            self.assertCalls(lambda: _(port_test), 'ftdi_write_data')
+            self.assertEqual(dev._latch, port_test)
+            self.assertEqual(dev.port, port_test)
+        # XXX: this is incomplete.
+        # could check for various directions and how that impacts
+        # port read / write, as well as r/m/w operations.
+
+if __name__ == "__main__":
+    unittest.main()

pylibftdi/tests/test_bus.py

+
+from pylibftdi.tests.test_common import unittest
+from pylibftdi.util import Bus
+
+
+class TestBus(unittest.TestCase):
+
+    class MockDriver(object):
+        port = 0
+
+    class Bus1(object):
+        a = Bus(0, 2)
+        b = Bus(2, 1)
+        c = Bus(3, 5)
+
+        def __init__(self):
+            self.driver = TestBus.MockDriver()
+
+    def test_bus_write(self):
+        test_bus = TestBus.Bus1()
+        # test writing to the bus
+        self.assertEqual(test_bus.driver.port, 0)
+        test_bus.a = 3
+        test_bus.b = 1
+        test_bus.c = 31
+        self.assertEqual(test_bus.driver.port, 255)
+        test_bus.b = 0
+        self.assertEqual(test_bus.driver.port, 251)
+        test_bus.c = 16
+        self.assertEqual(test_bus.driver.port, 131)
+
+    def test_bus_read(self):
+        test_bus = TestBus.Bus1()
+        # test reading from the bus
+        test_bus.driver.port = 0x55
+        assert test_bus.a == 1
+        assert test_bus.b == 1
+        assert test_bus.c == 10
+        test_bus.driver.port = 0xAA
+        assert test_bus.a == 2
+        assert test_bus.b == 0
+        assert test_bus.c == 21

pylibftdi/tests/test_common.py

+"""
+pylibftdi - python wrapper for libftdi
+
+Copyright (c) 2010-2011 Ben Bass <benbass@codedstructure.net>
+See LICENSE file for details and (absence of) warranty
+
+pylibftdi: http://bitbucket.org/codedstructure/pylibftdi
+
+This module contains some basic tests for the higher-level
+functionality without requiring an actual hardware device
+to be attached.
+"""
+
+import sys
+if sys.version_info < (2, 7):
+    try:
+        import unittest2 as unittest
+    except ImportError:
+        raise SystemExit("The test functionality is only supported in"
+                "Python 2.7+ unless unittest2 is installed")
+else:
+    import unittest  # NOQA
+
+VERBOSE = False
+
+
+class SimpleMock(object):
+    """
+    This is a simple mock plugin for fdll which logs any calls
+    made through it to fn_log, which is currently rather ugly
+    global state.
+    """
+    def __init__(self, name="<base>"):
+        self.__name = name
+
+    def __getattr__(self, key):
+        return SimpleMock(key)
+
+    def __call__(self, *o, **k):
+        CallLog.append(self.__name)
+        if VERBOSE:
+            print("%s(*%s, **%s)" % (self.__name, o, k))
+        return 0
+
+
+class CallLog(object):
+
+    fn_log = []
+
+    @classmethod
+    def reset(cls):
+        del cls.fn_log[:]
+
+    @classmethod
+    def append(cls, value):
+        cls.fn_log.append(value)
+
+    @classmethod
+    def get(cls):
+        return cls.fn_log[:]
+
+
+class CallCheckMixin(object):
+    """
+    this should be used as a mixin for unittest.TestCase classes,
+    where it allows the calls through the MockDriver to be checked
+    this does not support multi-threading.
+    """
+
+    def setUp(self):
+        super(CallCheckMixin, self).setUp()
+
+    def assertCalls(self, fn, methodname):
+        CallLog.reset()
+        fn()
+        self.assertIn(methodname, CallLog.get())
+
+    def assertCallsExact(self, fn, call_list):
+        CallLog.reset()
+        fn()
+        self.assertEqual(call_list, CallLog.get())
+
+
+# monkey patch the Driver class to be the mock thing above.
+class MockDriver(object):
+    def __init__(self, *o, **k):
+        self.fdll = SimpleMock()
+
+
+import pylibftdi.driver
+from pylibftdi.driver import Device
+
+
+class LoopDevice(Device):
+    """
+    a mock device object which overrides read and write
+    to operate as an unbounded loopback pair
+    """
+    def __init__(self, *o, **k):
+        super(LoopDevice, self).__init__(*o, **k)
+        self.__buffer = []
+
+    def _read(self, size):
+        super(LoopDevice, self)._read(size)  # discard result
+        result = bytes(bytearray(self.__buffer[:size]))
+        self.__buffer = self.__buffer[size:]
+        return result
+
+    def _write(self, data):
+        super(LoopDevice, self)._write(data)  # discard result
+        self.__buffer.extend(bytearray(data))
+        return len(data)
+
+# importing this _does_ things...
+pylibftdi.driver.Driver = MockDriver
+
+if set(['-v', '--verbose']) & set(sys.argv):
+    VERBOSE = True

pylibftdi/tests/test_driver.py

+"""
+pylibftdi - python wrapper for libftdi
+
+Copyright (c) 2010-2011 Ben Bass <benbass@codedstructure.net>
+See LICENSE file for details and (absence of) warranty
+
+pylibftdi: http://bitbucket.org/codedstructure/pylibftdi
+
+This module contains some basic tests for the higher-level
+functionality without requiring an actual hardware device
+to be attached.
+"""
+
+from pylibftdi.tests.test_common import (LoopDevice, Device, CallCheckMixin, unittest)
+
+# and now some test cases...
+
+
+class DeviceFunctions(CallCheckMixin, unittest.TestCase):
+
+    def testContextManager(self):
+        def _():
+            with Device():
+                pass
+        self.assertCallsExact(_,
+                ['ftdi_init', 'ftdi_usb_open',
+                 'ftdi_usb_close', 'ftdi_deinit'])
+
+    def testOpen(self):
+        # a lazy_open open() shouldn't do anything
+        self.assertCallsExact(lambda: Device(lazy_open=True), [])
+        # a non-lazy_open open() should open the port...
+        self.assertCalls(lambda: Device(), 'ftdi_usb_open')
+        # and given a device_id, it should do a open_desc
+        self.assertCalls(lambda: Device('bogus'), 'ftdi_usb_open_desc')
+
+    def testReadWrite(self):
+        with Device() as dev:
+            self.assertCalls(lambda: dev.write('xxx'), 'ftdi_write_data')
+            self.assertCalls(lambda: dev.read(10), 'ftdi_read_data')
+
+    def testFlush(self):
+        with Device() as dev:
+            self.assertCalls(dev.flush_input, 'ftdi_usb_purge_rx_buffer')
+            self.assertCalls(dev.flush_output, 'ftdi_usb_purge_tx_buffer')
+            self.assertCalls(dev.flush, 'ftdi_usb_purge_buffers')
+
+
+class LoopbackTest(unittest.TestCase):
+    """
+    these all require mode='t' to pass in Python3
+    """
+
+    def testPrint(self):
+        d = LoopDevice(mode='t')
+        d.write('Hello')
+        d.write(' World\n')
+        d.write('Bye')
+        self.assertEqual(d.readline(), 'Hello World\n')
+        self.assertEqual(d.readline(), 'Bye')
+
+    def testLines(self):
+        d = LoopDevice(mode='t')
+        lines = ['Hello\n', 'World\n', 'And\n', 'Goodbye\n']
+        d.writelines(lines)
+        self.assertEqual(d.readlines(), lines)
+
+    def testIterate(self):
+        d = LoopDevice(mode='t')
+        lines = ['Hello\n', 'World\n', 'And\n', 'Goodbye\n']
+        d.writelines(lines)
+        for idx, line in enumerate(d):
+            self.assertEqual(line, lines[idx])
+
+
+if __name__ == "__main__":
+    unittest.main()

pylibftdi/util.py

 # to, which has a 'port' property which is readable and
 # writable.
 
+
 class Bus(object):
     """
     This class is a descriptor for a bus of a given width starting
     def __init__(self, offset, width=1):
         self.offset = offset
         self.width = width
-        self._mask = ((1<<width)-1)
+        self._mask = ((1 << width) - 1)
 
     def __get__(self, obj, type):
         val = obj.driver.port
         val &= ~(self._mask << self.offset)
         val |= value << self.offset
         obj.driver.port = val
-
-def test_bus_class():
-    class MockDriver(object):
-        port = 0
-    class TestBus(object):
-        a = Bus(0, 2)
-        b = Bus(2, 1)
-        c = Bus(3, 5)
-        def __init__(self):
-            self.driver = MockDriver()
-    test_bus = TestBus()
-    # test writing to the bus
-    assert test_bus.driver.port == 0
-    test_bus.a = 3
-    test_bus.b = 1
-    test_bus.c = 31
-    assert test_bus.driver.port == 255
-    test_bus.b = 0
-    assert test_bus.driver.port == 251
-    test_bus.c = 16
-    assert test_bus.driver.port == 131
-    # test reading from the bus
-    test_bus.driver.port = 0x55
-    assert test_bus.a == 1
-    assert test_bus.b == 1
-    assert test_bus.c == 10
-    test_bus.driver.port = 0xAA
-    assert test_bus.a == 2
-    assert test_bus.b == 0
-    assert test_bus.c == 21
-
-if __name__ == '__main__':
-    test_bus_class()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.