Ticket #4847: serialports-endpoint-4847-4.patch

File serialports-endpoint-4847-4.patch, 13.0 KB (added by Mike Mattice, 7 years ago)

patch on f2877a7

  • twisted/internet/address.py

    diff --git twisted/internet/address.py twisted/internet/address.py
    index f017f55..f559763 100644
    class HostnameAddress(FancyEqMixin, object): 
    116116
    117117
    118118@implementer(IAddress)
     119class SerialAddress(object):
     120    """
     121    An L{interfaces.IAddress} provider for serial port connections.
     122    """
     123
     124
     125
     126@implementer(IAddress)
    119127class UNIXAddress(FancyEqMixin, object):
    120128    """
    121129    Object representing a UNIX socket endpoint.
  • twisted/internet/endpoints.py

    diff --git twisted/internet/endpoints.py twisted/internet/endpoints.py
    index 7ba25db..3257cc0 100644
    from twisted.python.systemd import ListenFDs 
    3535from twisted.internet.abstract import isIPv6Address
    3636from twisted.python.failure import Failure
    3737from twisted.python import log
    38 from twisted.internet.address import _ProcessAddress, HostnameAddress
     38from twisted.internet.address import _ProcessAddress, HostnameAddress, SerialAddress
    3939from twisted.python.components import proxyForInterface
    4040from twisted.internet.task import LoopingCall
    4141
    __all__ = ["clientFromString", "serverFromString", 
    5858           "SSL4ServerEndpoint", "SSL4ClientEndpoint",
    5959           "AdoptedStreamServerEndpoint", "StandardIOEndpoint",
    6060           "ProcessEndpoint", "HostnameEndpoint",
     61           "SerialPortEndpoint",
    6162           "StandardErrorBehavior", "connectProtocol"]
    6263
    6364__all3__ = ["TCP4ServerEndpoint", "TCP6ServerEndpoint",
    class SSL4ClientEndpoint(object): 
    875876            return defer.fail()
    876877
    877878
     879@implementer(interfaces.IStreamClientEndpoint)
     880class SerialPortEndpoint(object):
     881    """
     882    A Serial Port endpoint.
     883
     884    @ivar _serialport: A hook used for testing availability of serial port
     885        support.
     886    """
     887    try:
     888        from twisted.internet.serialport import (
     889            EIGHTBITS, PARITY_NONE, STOPBITS_ONE)
     890        from twisted.internet import serialport as _serialport
     891    except ImportError:
     892        _serialport = None
     893        EIGHTBITS = None
     894        PARITY_NONE = None
     895        STOPBITS_ONE = None
     896
     897
     898    def __init__(self, deviceNameOrPortNumber, reactor,
     899                 baudrate=9600, bytesize=EIGHTBITS,
     900                 parity=PARITY_NONE, stopbits=STOPBITS_ONE,
     901                 timeout=0, xonxoff=False, rtscts=False):
     902        """
     903        @see: L{serialport.SerialPort}
     904        """
     905        self._deviceNameOrPortNumber = deviceNameOrPortNumber
     906        self._reactor = reactor
     907        self._baudrate = baudrate
     908        self._bytesize = bytesize
     909        self._parity = parity
     910        self._stopbits = stopbits
     911        self._timeout = timeout
     912        self._xonxoff = xonxoff
     913        self._rtscts = rtscts
     914
     915
     916    def connect(self, serialFactory):
     917        """
     918        Implement L{IStreamClientEndpoint.connect} to connect to serial ports
     919
     920        @param serialFactory: The protocol factory which will build protocols
     921            for connections to this service.
     922        @type serialFactory: L{twisted.internet.interfaces.IProtocolFactory}
     923        """
     924        try:
     925            if self._serialport == None:
     926                raise ImportError
     927            else:
     928                proto = serialFactory.buildProtocol(SerialAddress())
     929                self._serialport.SerialPort(proto, self._deviceNameOrPortNumber,
     930                        self._reactor, self._baudrate, self._bytesize,
     931                        self._parity, self._stopbits, self._timeout,
     932                        self._xonxoff, self._rtscts)
     933                return defer.succeed(proto)
     934        except:
     935            return defer.fail()
     936
     937
    878938
    879939@implementer(interfaces.IStreamServerEndpoint)
    880940class UNIXServerEndpoint(object):
  • twisted/internet/test/test_endpoints.py

    diff --git twisted/internet/test/test_endpoints.py twisted/internet/test/test_endpoints.py
    index 0b2ef41..7791501 100644
    from twisted.trial import unittest 
    2020from twisted.internet import (
    2121    error, interfaces, defer, endpoints, protocol, reactor, threads)
    2222from twisted.internet.address import (
    23     IPv4Address, IPv6Address, UNIXAddress, _ProcessAddress, HostnameAddress)
     23    IPv4Address, IPv6Address, UNIXAddress, _ProcessAddress, HostnameAddress,
     24    SerialAddress)
    2425from twisted.internet.protocol import ClientFactory, Protocol
    2526from twisted.test.proto_helpers import RaisingMemoryReactor, StringTransport
    2627from twisted.python.failure import Failure
    from twisted.test.proto_helpers import (MemoryReactorClock as MemoryReactor) 
    3435from twisted.test import __file__ as testInitPath
    3536pemPath = FilePath(testInitPath.encode("utf-8")).sibling(b"server.pem")
    3637
     38try:
     39    from twisted.internet import serialport
     40except ImportError:
     41    serialport = None
     42
    3743if not _PY3:
    3844    from twisted.plugin import getPlugins
    3945    from twisted import plugins
    class StandardIOEndpointsTestCase(unittest.TestCase): 
    628634
    629635    def test_standardIOInstance(self):
    630636        """
    631         The endpoint creates an L{endpoints.StandardIO} instance.
     637        The endpoint creates an L{stdio.StandardIO} instance.
    632638        """
    633639        d = self.ep.listen(StdioFactory())
    634640
    class SSL4EndpointsTestCase(EndpointTestCaseMixin, 
    20912097
    20922098
    20932099
     2100class SerialFactory(StdioFactory):
     2101    pass
     2102
     2103
     2104
     2105class SerialPortEndpointFailureTestCase(unittest.TestCase):
     2106    """
     2107    Test Case for Serial Port Endpoints when serial port support is not
     2108    available.
     2109    """
     2110    def test_importError(self):
     2111        """
     2112        Serial port support is not available, i.e., pyserial is not installed.
     2113        """
     2114        endpoint = endpoints.SerialPortEndpoint('/dev/ttyS0', reactor)
     2115        endpoint._serialport = None
     2116        d = endpoint.connect(SerialFactory())
     2117        self.assertIsInstance(self.failureResultOf(d).value, ImportError)
     2118
     2119
     2120
     2121class SerialPortEndpointsTestCase(unittest.TestCase):
     2122    """
     2123    Tests for Serial Port Endpoints
     2124    """
     2125    if serialport is None:
     2126        skip = "Serial port support is not available."
     2127    else:
     2128        deviceNameOrPortNumber = '/dev/ttyS0'
     2129
     2130    def setUp(self):
     2131        self.ep = endpoints.SerialPortEndpoint(self.deviceNameOrPortNumber,
     2132                                reactor)
     2133
     2134
     2135    def test_constructorDefaultArgs(self):
     2136        """
     2137        The parameters passed to the endpoints are stored in it, while
     2138        the optional arguments get their respective default values.
     2139        """
     2140        endpoint = endpoints.SerialPortEndpoint('/dev/ttyS0', reactor)
     2141        self.assertEqual(endpoint._reactor, reactor)
     2142        self.assertEqual(endpoint._baudrate, 9600)
     2143        self.assertEqual(endpoint._bytesize, serialport.EIGHTBITS)
     2144        self.assertEqual(endpoint._parity, serialport.PARITY_NONE)
     2145        self.assertEqual(endpoint._stopbits, serialport.STOPBITS_ONE)
     2146        self.assertEqual(endpoint._timeout, 0)
     2147        self.assertEqual(endpoint._xonxoff, False)
     2148        self.assertEqual(endpoint._rtscts, False)
     2149
     2150
     2151    def test_serialPortInstanceParameters(self):
     2152        """
     2153        The endpoint creates a L{serialport.SerialPort} instance and
     2154        passes the required arguments to its constructor.
     2155        """
     2156        baudrate = 4800
     2157        bytesize = serialport.SEVENBITS
     2158        parity = serialport.PARITY_EVEN
     2159        stopbits = serialport.STOPBITS_TWO
     2160        timeout = 3
     2161        xonxoff = True
     2162        rtscts = True
     2163        expectedArgs = [(self.deviceNameOrPortNumber, baudrate, bytesize, parity,
     2164            stopbits, timeout, xonxoff, rtscts)]
     2165        portArgs = []
     2166        class _DummySerialPort(object):
     2167            def __init__(self, protocol, deviceNameOrPortNumber, reactor,
     2168                         baudrate, bytesize, parity, stopbits, timeout,
     2169                         xonxoff, rtscts):
     2170                self.protocol = protocol
     2171                self.protocol.makeConnection(self)
     2172                portArgs.append((deviceNameOrPortNumber, baudrate, bytesize,
     2173                    parity, stopbits, timeout, xonxoff, rtscts))
     2174
     2175        self.patch(serialport, 'SerialPort', _DummySerialPort)
     2176        argep = endpoints.SerialPortEndpoint(self.deviceNameOrPortNumber,
     2177                                             reactor, baudrate, bytesize,
     2178                                             parity, stopbits, timeout,
     2179                                             xonxoff, rtscts)
     2180        d = argep.connect(SerialFactory())
     2181
     2182        def checkArgs(proto):
     2183            self.assertIsInstance(proto, basic.LineReceiver)
     2184            self.assertIsInstance(proto.transport, serialport.SerialPort)
     2185            self.assertEqual(expectedArgs, portArgs)
     2186
     2187        d.addCallback(checkArgs)
     2188        return d
     2189
     2190
     2191    def test_xonxoff(self):
     2192        """
     2193        The value of xonxoff that is stored in the endpoint is passed
     2194        on to the L{SerialPort} instance.
     2195        """
     2196        expectedValue = True
     2197        endpoint = endpoints.SerialPortEndpoint(self.deviceNameOrPortNumber,
     2198                                reactor, xonxoff=expectedValue)
     2199        xonxoffVal = []
     2200        class _DummySerialPort(object):
     2201            def __init__(self, protocol, deviceNameOrPortNumber, reactor,
     2202                         baudrate, bytesize, parity, stopbits, timeout,
     2203                         xonxoff, rtscts):
     2204                xonxoffVal.append(xonxoff)
     2205
     2206        self.patch(serialport, 'SerialPort', _DummySerialPort)
     2207        d = endpoint.connect(SerialFactory())
     2208
     2209        def checkArg(proto):
     2210            self.assertEqual(xonxoffVal.pop(), expectedValue)
     2211
     2212        d.addCallback(checkArg)
     2213        return d
     2214
     2215
     2216    def test_rtscts(self):
     2217        """
     2218        The value of rtscts stored in the endpoint is passed on to the
     2219        L{SerialPort} instance.
     2220        """
     2221        expectedValue = True
     2222        endpoint = endpoints.SerialPortEndpoint(self.deviceNameOrPortNumber,
     2223                                reactor, rtscts=expectedValue)
     2224        rtsctsVal = []
     2225        class _DummySerialPort(object):
     2226            def __init__(self, protocol, deviceNameOrPortNumber, reactor,
     2227                         baudrate, bytesize, parity, stopbits, timeout,
     2228                         xonxoff, rtscts):
     2229                rtsctsVal.append(rtscts)
     2230
     2231        self.patch(serialport, 'SerialPort', _DummySerialPort)
     2232        d = endpoint.connect(SerialFactory())
     2233
     2234        def checkArg(proto):
     2235            self.assertEqual(rtsctsVal.pop(), expectedValue)
     2236
     2237        d.addCallback(checkArg)
     2238        return d
     2239
     2240
     2241    def test_address(self):
     2242        """
     2243        The address passed to the factory's buildProtocol in the
     2244        endpoint is a SerialAddress instance.
     2245        """
     2246        class TestAddrFactory(protocol.Factory):
     2247            protocol = basic.LineReceiver
     2248            _address = None
     2249            def buildProtocol(self, addr):
     2250                self._address = addr
     2251                p = self.protocol()
     2252                p.factory = self
     2253                return p
     2254            def getAddress(self):
     2255                return self._address
     2256
     2257        f = TestAddrFactory()
     2258
     2259        class _DummySerialPort(object):
     2260            def __init__(self, protocol, deviceNameOrPortNumber, reactor,
     2261                         baudrate, bytesize, parity, stopbits, timeout,
     2262                         xonxoff, rtscts):
     2263                self.protocol = protocol
     2264                self.protocol.makeConnection(self)
     2265
     2266        self.patch(serialport, 'SerialPort', _DummySerialPort)
     2267        d = self.ep.connect(f)
     2268
     2269        def checkAddress(proto):
     2270            self.assertIsInstance(f.getAddress(), SerialAddress)
     2271
     2272        d.addCallback(checkAddress)
     2273        return d
     2274
     2275
     2276    def test_connectFailure(self):
     2277        """
     2278        In case of failure, L{SerialPortEndpoint.connect} returns a
     2279        Deferred that fails.
     2280        """
     2281        class _DummySerialPortThatFails(object):
     2282            def __init__(self, *args):
     2283                raise Exception
     2284
     2285        receivedExceptions = []
     2286        self.patch(serialport, 'SerialPort', _DummySerialPortThatFails)
     2287        d = self.ep.connect(SerialFactory())
     2288        self.assertIsInstance(self.failureResultOf(d).value, Exception)
     2289
     2290
     2291    def test_buildProtocolFailure(self):
     2292        """
     2293        In case of failure, L{SerialPortEndpoint.connect} returns a
     2294        Deferred that fires with a failure.
     2295        """
     2296        class FailingSerialFactory(SerialFactory):
     2297            def buildProtocol(self, addr):
     2298                raise Exception
     2299
     2300        receivedExceptions = []
     2301        d = self.ep.connect(FailingSerialFactory())
     2302
     2303        def checkFailure(failure):
     2304            receivedExceptions.append(failure.value)
     2305
     2306        d.addErrback(checkFailure)
     2307        self.assertEqual(len(receivedExceptions), 1)
     2308        self.assertIsInstance(receivedExceptions.pop(), Exception)
     2309
     2310
     2311
    20942312class UNIXEndpointsTestCase(EndpointTestCaseMixin,
    20952313                            unittest.TestCase):
    20962314    """
  • new file twisted/topfiles/4847.feature

    diff --git twisted/topfiles/4847.feature twisted/topfiles/4847.feature
    new file mode 100644
    index 0000000..640baf4
    - +  
     1twisted.internet.endpoints now provides SerialPortEndpoint, a Serial Port endpoint.