From b45475753a30ce07630b9564b6b601616549ea6e Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sat, 16 Jan 2021 14:28:37 -0500 Subject: [PATCH 01/60] Enable Windows testing on GHA --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd0ed6107..1598f5679 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,10 +40,10 @@ jobs: 3.9: docker://python:3.9-buster pypy2: docker://pypy:2-jessie pypy3: docker://pypy:3-stretch -# - name: Windows -# runs-on: windows-latest -# python_platform: win32 -# matrix: windows + - name: Windows + runs-on: windows-latest + python_platform: win32 + matrix: windows # - name: macOS # runs-on: macos-latest # python_platform: darwin From 635f0a7ec7f523eb94f6ca176ea8f14302393386 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sat, 16 Jan 2021 14:29:09 -0500 Subject: [PATCH 02/60] Enable macOS testing on GHA --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd0ed6107..e71e8286d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,10 +44,10 @@ jobs: # runs-on: windows-latest # python_platform: win32 # matrix: windows -# - name: macOS -# runs-on: macos-latest -# python_platform: darwin -# matrix: macos + - name: macOS + runs-on: macos-latest + python_platform: darwin + matrix: macos python: - name: CPython 2.7 tox: py27 From 4d2b44606913c063b3448b3971026ad8db93a73c Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 12:26:26 -0800 Subject: [PATCH 03/60] Hackily use Twisted serial testing classes --- .../client/asynchronous/factory/serial.py | 36 ++++++++++++- test/test_client_async.py | 51 +++++++++++-------- 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/pymodbus/client/asynchronous/factory/serial.py b/pymodbus/client/asynchronous/factory/serial.py index 62b719c5c..a5698314d 100644 --- a/pymodbus/client/asynchronous/factory/serial.py +++ b/pymodbus/client/asynchronous/factory/serial.py @@ -37,7 +37,39 @@ def buildProtocol(self): proto.factory = self return proto - class SerialModbusClient(SerialPort): + import serial + import serial.win32 + + class RegularFileSerial(serial.Serial): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.captured_args = args + self.captured_kwargs = kwargs + + def _reconfigurePort(self): + pass + + def _reconfigure_port(self): + pass + + class RegularFileSerialPort(SerialPort): + _serialFactory = RegularFileSerial + + def __init__(self, *args, **kwargs): + cbInQue = kwargs.get("cbInQue") + + if "cbInQue" in kwargs: + del kwargs["cbInQue"] + + self.comstat = serial.win32.COMSTAT + self.comstat.cbInQue = cbInQue + + super().__init__(*args, **kwargs) + + def _clearCommError(self): + return True, self.comstat + + class SerialModbusClient(RegularFileSerialPort): def __init__(self, framer, *args, **kwargs): ''' Setup the client and start listening on the serial port @@ -47,7 +79,7 @@ def __init__(self, framer, *args, **kwargs): self.decoder = ClientDecoder() proto_cls = kwargs.pop("proto_cls", None) proto = SerialClientFactory(framer, proto_cls).buildProtocol() - SerialPort.__init__(self, proto, *args, **kwargs) + super(SerialModbusClient, self).__init__(proto, *args, **kwargs) proto = EventLoopThread("reactor", reactor.run, reactor.stop, installSignalHandlers=0) diff --git a/test/test_client_async.py b/test/test_client_async.py index 97aaae8bd..3e4178e2f 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -182,33 +182,42 @@ def testUdpAsycioClient(self, mock_gather, mock_event_loop): def testSerialTwistedClient(self, method, framer): """ Test the serial twisted client client initialize """ from serial import Serial - with patch("serial.Serial") as mock_sp: - from twisted.internet import reactor - from twisted.internet.serialport import SerialPort + from twisted.internet import reactor + from twisted.internet.serialport import SerialPort + + with patch('twisted.internet.reactor') as mock_reactor: + import os.path + import tempfile + directory = tempfile.mkdtemp() + path = os.path.join(directory, "fake_serial") + + data = b"1234" + with open(path, "wb") as f: + f.write(data) - with patch('twisted.internet.reactor') as mock_reactor: + SERIAL_PORT = path - protocol, client = AsyncModbusSerialClient(schedulers.REACTOR, - method=method, - port=SERIAL_PORT, - proto_cls=ModbusSerClientProtocol) + protocol, client = AsyncModbusSerialClient(schedulers.REACTOR, + method=method, + port=SERIAL_PORT, + proto_cls=ModbusSerClientProtocol) - assert (isinstance(client, SerialPort)) - assert (isinstance(client.protocol, ModbusSerClientProtocol)) - assert (0 == len(list(client.protocol.transaction))) - assert (isinstance(client.protocol.framer, framer)) - assert (client.protocol._connected) + assert (isinstance(client, SerialPort)) + assert (isinstance(client.protocol, ModbusSerClientProtocol)) + assert (0 == len(list(client.protocol.transaction))) + assert (isinstance(client.protocol.framer, framer)) + assert (client.protocol._connected) - def handle_failure(failure): - assert (isinstance(failure.exception(), ConnectionException)) + def handle_failure(failure): + assert (isinstance(failure.exception(), ConnectionException)) - d = client.protocol._buildResponse(0x00) - d.addCallback(handle_failure) + d = client.protocol._buildResponse(0x00) + d.addCallback(handle_failure) - assert (client.protocol._connected) - client.protocol.close() - protocol.stop() - assert (not client.protocol._connected) + assert (client.protocol._connected) + client.protocol.close() + protocol.stop() + assert (not client.protocol._connected) @pytest.mark.parametrize("method, framer", [("rtu", ModbusRtuFramer), ("socket", ModbusSocketFramer), From de69322ef181edff6ef9b98bf869b8868c0a04f1 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 13:20:53 -0800 Subject: [PATCH 04/60] Resupport Linux too --- .../client/asynchronous/factory/serial.py | 76 +++++++++++-------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/pymodbus/client/asynchronous/factory/serial.py b/pymodbus/client/asynchronous/factory/serial.py index a5698314d..85421bace 100644 --- a/pymodbus/client/asynchronous/factory/serial.py +++ b/pymodbus/client/asynchronous/factory/serial.py @@ -5,6 +5,7 @@ from __future__ import absolute_import import logging +import sys import time from pymodbus.client.asynchronous import schedulers from pymodbus.client.asynchronous.thread import EventLoopThread @@ -37,49 +38,62 @@ def buildProtocol(self): proto.factory = self return proto - import serial - import serial.win32 + if sys.platform == "win32": + import serial + import serial.win32 - class RegularFileSerial(serial.Serial): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.captured_args = args - self.captured_kwargs = kwargs + class RegularFileSerial(serial.Serial): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.captured_args = args + self.captured_kwargs = kwargs - def _reconfigurePort(self): - pass + def _reconfigurePort(self): + pass - def _reconfigure_port(self): - pass + def _reconfigure_port(self): + pass - class RegularFileSerialPort(SerialPort): - _serialFactory = RegularFileSerial + class RegularFileSerialPort(SerialPort): + _serialFactory = RegularFileSerial - def __init__(self, *args, **kwargs): - cbInQue = kwargs.get("cbInQue") + def __init__(self, *args, **kwargs): + cbInQue = kwargs.get("cbInQue") - if "cbInQue" in kwargs: - del kwargs["cbInQue"] + if "cbInQue" in kwargs: + del kwargs["cbInQue"] - self.comstat = serial.win32.COMSTAT - self.comstat.cbInQue = cbInQue + self.comstat = serial.win32.COMSTAT + self.comstat.cbInQue = cbInQue - super().__init__(*args, **kwargs) + super().__init__(*args, **kwargs) - def _clearCommError(self): - return True, self.comstat + def _clearCommError(self): + return True, self.comstat - class SerialModbusClient(RegularFileSerialPort): + class SerialModbusClient(RegularFileSerialPort): - def __init__(self, framer, *args, **kwargs): - ''' Setup the client and start listening on the serial port + def __init__(self, framer, *args, **kwargs): + ''' Setup the client and start listening on the serial port - :param factory: The factory to build clients with - ''' - self.decoder = ClientDecoder() - proto_cls = kwargs.pop("proto_cls", None) - proto = SerialClientFactory(framer, proto_cls).buildProtocol() - super(SerialModbusClient, self).__init__(proto, *args, **kwargs) + :param factory: The factory to build clients with + ''' + self.decoder = ClientDecoder() + proto_cls = kwargs.pop("proto_cls", None) + proto = SerialClientFactory(framer, proto_cls).buildProtocol() + super(SerialModbusClient, self).__init__(proto, *args, **kwargs) + else: + class SerialModbusClient(SerialPort): + + def __init__(self, framer, *args, **kwargs): + ''' Setup the client and start listening on the serial port + + :param factory: The factory to build clients with + ''' + self.decoder = ClientDecoder() + proto_cls = kwargs.pop("proto_cls", None) + proto = SerialClientFactory(framer, proto_cls).buildProtocol() + super(SerialModbusClient, self).__init__(proto, *args, **kwargs) proto = EventLoopThread("reactor", reactor.run, reactor.stop, installSignalHandlers=0) From 8db334cd57453366eb673ecc71b15da3994f13c4 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 13:27:24 -0800 Subject: [PATCH 05/60] more hacky fixup for linux --- test/test_client_async.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/test/test_client_async.py b/test/test_client_async.py index 3e4178e2f..6113be1cf 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +import sys import unittest import pytest from pymodbus.compat import IS_PYTHON3, PYTHON_VERSION @@ -186,16 +187,17 @@ def testSerialTwistedClient(self, method, framer): from twisted.internet.serialport import SerialPort with patch('twisted.internet.reactor') as mock_reactor: - import os.path - import tempfile - directory = tempfile.mkdtemp() - path = os.path.join(directory, "fake_serial") + if sys.platform == "win32": + import os.path + import tempfile + directory = tempfile.mkdtemp() + path = os.path.join(directory, "fake_serial") - data = b"1234" - with open(path, "wb") as f: - f.write(data) + data = b"1234" + with open(path, "wb") as f: + f.write(data) - SERIAL_PORT = path + SERIAL_PORT = path protocol, client = AsyncModbusSerialClient(schedulers.REACTOR, method=method, From 27ae242927f48fe291f19e7aae2ca8fce4bc7b4b Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 16:30:14 -0500 Subject: [PATCH 06/60] even hackier --- test/test_client_async.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_client_async.py b/test/test_client_async.py index 6113be1cf..f8ecf09e9 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -196,7 +196,7 @@ def testSerialTwistedClient(self, method, framer): data = b"1234" with open(path, "wb") as f: f.write(data) - + global SERIAL_PORT SERIAL_PORT = path protocol, client = AsyncModbusSerialClient(schedulers.REACTOR, From f30e961a947174270dbdca5fecc9445be26e9028 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 13:52:58 -0800 Subject: [PATCH 07/60] mocks -> bind_and_activate=False --- test/test_server_sync.py | 74 ++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/test/test_server_sync.py b/test/test_server_sync.py index 74ba0cfa5..93e8a3e48 100644 --- a/test/test_server_sync.py +++ b/test/test_server_sync.py @@ -260,13 +260,12 @@ def _callback(a, b): #-----------------------------------------------------------------------# def testTcpServerClose(self): ''' test that the synchronous TCP server closes correctly ''' - with patch.object(socket.socket, 'bind') as mock_socket: - identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) - server = ModbusTcpServer(context=None, identity=identity) - server.threads.append(Mock(**{'running': True})) - server.server_close() - self.assertEqual(server.control.Identity.VendorName, 'VendorName') - self.assertFalse(server.threads[0].running) + identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) + server = ModbusTcpServer(context=None, identity=identity, bind_and_activate=False) + server.threads.append(Mock(**{'running': True})) + server.server_close() + self.assertEqual(server.control.Identity.VendorName, 'VendorName') + self.assertFalse(server.threads[0].running) def testTcpServerProcess(self): ''' test that the synchronous TCP server processes requests ''' @@ -280,30 +279,28 @@ def testTcpServerProcess(self): #-----------------------------------------------------------------------# def testTlsServerInit(self): ''' test that the synchronous TLS server intial correctly ''' - with patch.object(socket.socket, 'bind') as mock_socket: - with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: - identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) - server = ModbusTlsServer(context=None, identity=identity) - self.assertIsNotNone(server.sslctx) - self.assertEqual(type(server.socket), ssl.SSLSocket) - server.server_close() - sslctx = ssl.create_default_context() - server = ModbusTlsServer(context=None, identity=identity, - sslctx=sslctx) - self.assertEqual(server.sslctx, sslctx) - self.assertEqual(type(server.socket), ssl.SSLSocket) - server.server_close() + with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: + identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) + server = ModbusTlsServer(context=None, identity=identity, bind_and_activate=False) + self.assertIsNotNone(server.sslctx) + self.assertEqual(type(server.socket), ssl.SSLSocket) + server.server_close() + sslctx = ssl.create_default_context() + server = ModbusTlsServer(context=None, identity=identity, + sslctx=sslctx) + self.assertEqual(server.sslctx, sslctx) + self.assertEqual(type(server.socket), ssl.SSLSocket) + server.server_close() def testTlsServerClose(self): ''' test that the synchronous TLS server closes correctly ''' - with patch.object(socket.socket, 'bind') as mock_socket: - with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: - identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) - server = ModbusTlsServer(context=None, identity=identity) - server.threads.append(Mock(**{'running': True})) - server.server_close() - self.assertEqual(server.control.Identity.VendorName, 'VendorName') - self.assertFalse(server.threads[0].running) + with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: + identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) + server = ModbusTlsServer(context=None, identity=identity, bind_and_activate=False) + server.threads.append(Mock(**{'running': True})) + server.server_close() + self.assertEqual(server.control.Identity.VendorName, 'VendorName') + self.assertFalse(server.threads[0].running) def testTlsServerProcess(self): ''' test that the synchronous TLS server processes requests ''' @@ -318,13 +315,12 @@ def testTlsServerProcess(self): #-----------------------------------------------------------------------# def testUdpServerClose(self): ''' test that the synchronous UDP server closes correctly ''' - with patch.object(socket.socket, 'bind') as mock_socket: - identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) - server = ModbusUdpServer(context=None, identity=identity) - server.threads.append(Mock(**{'running': True})) - server.server_close() - self.assertEqual(server.control.Identity.VendorName, 'VendorName') - self.assertFalse(server.threads[0].running) + identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) + server = ModbusUdpServer(context=None, identity=identity, bind_and_activate=False) + server.threads.append(Mock(**{'running': True})) + server.server_close() + self.assertEqual(server.control.Identity.VendorName, 'VendorName') + self.assertFalse(server.threads[0].running) def testUdpServerProcess(self): ''' test that the synchronous UDP server processes requests ''' @@ -383,15 +379,13 @@ def testSerialServerClose(self): def testStartTcpServer(self): ''' Test the tcp server starting factory ''' with patch.object(ModbusTcpServer, 'serve_forever') as mock_server: - with patch.object(socketserver.TCPServer, 'server_bind') as mock_binder: - StartTcpServer() + StartTcpServer(bind_and_activate=False) def testStartTlsServer(self): ''' Test the tls server starting factory ''' with patch.object(ModbusTlsServer, 'serve_forever') as mock_server: - with patch.object(socketserver.TCPServer, 'server_bind') as mock_binder: - with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: - StartTlsServer() + with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: + StartTlsServer(bind_and_activate=False) def testStartUdpServer(self): ''' Test the udp server starting factory ''' From 47de91cadccece58579a1b8140ef8ed4654ac2af Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 17:34:31 -0500 Subject: [PATCH 08/60] fixup for linux again --- pymodbus/server/sync.py | 13 +++++++------ test/test_server_sync.py | 5 ++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pymodbus/server/sync.py b/pymodbus/server/sync.py index f7b22454f..4deb39f03 100644 --- a/pymodbus/server/sync.py +++ b/pymodbus/server/sync.py @@ -327,16 +327,17 @@ def __init__(self, context, framer=None, identity=None, self.control = ModbusControlBlock() self.address = address or ("", Defaults.Port) self.handler = handler or ModbusConnectedRequestHandler - self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', + self.ignore_missing_slaves = kwargs.pop('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) - self.broadcast_enable = kwargs.get('broadcast_enable', + self.broadcast_enable = kwargs.pop('broadcast_enable', Defaults.broadcast_enable) if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) socketserver.ThreadingTCPServer.__init__(self, self.address, - self.handler) + self.handler, + **kwargs) def process_request(self, request, client): """ Callback for connecting a new client thread @@ -456,16 +457,16 @@ def __init__(self, context, framer=None, identity=None, address=None, self.control = ModbusControlBlock() self.address = address or ("", Defaults.Port) self.handler = handler or ModbusDisconnectedRequestHandler - self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', + self.ignore_missing_slaves = kwargs.pop('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) - self.broadcast_enable = kwargs.get('broadcast_enable', + self.broadcast_enable = kwargs.pop('broadcast_enable', Defaults.broadcast_enable) if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) socketserver.ThreadingUDPServer.__init__(self, - self.address, self.handler) + self.address, self.handler, **kwargs) # self._BaseServer__shutdown_request = True def process_request(self, request, client): diff --git a/test/test_server_sync.py b/test/test_server_sync.py index 93e8a3e48..0bfc4585d 100644 --- a/test/test_server_sync.py +++ b/test/test_server_sync.py @@ -282,12 +282,14 @@ def testTlsServerInit(self): with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) server = ModbusTlsServer(context=None, identity=identity, bind_and_activate=False) + server.server_activate() self.assertIsNotNone(server.sslctx) self.assertEqual(type(server.socket), ssl.SSLSocket) server.server_close() sslctx = ssl.create_default_context() server = ModbusTlsServer(context=None, identity=identity, - sslctx=sslctx) + sslctx=sslctx, bind_and_activate=False) + server.server_activate() self.assertEqual(server.sslctx, sslctx) self.assertEqual(type(server.socket), ssl.SSLSocket) server.server_close() @@ -317,6 +319,7 @@ def testUdpServerClose(self): ''' test that the synchronous UDP server closes correctly ''' identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) server = ModbusUdpServer(context=None, identity=identity, bind_and_activate=False) + server.server_activate() server.threads.append(Mock(**{'running': True})) server.server_close() self.assertEqual(server.control.Identity.VendorName, 'VendorName') From c63202fb2e4a123a16d3e8d850e7565e479ab0c2 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 19:44:45 -0800 Subject: [PATCH 09/60] no twisted serial on pypy --- requirements-tests.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements-tests.txt b/requirements-tests.txt index b7d4bb23c..e8ac5b37f 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -14,6 +14,7 @@ sqlalchemy>=1.1.15 #wsgiref>=0.1.2 verboselogs >= 1.5 tornado==4.5.3 -Twisted[serial]>=20.3.0 +Twisted[serial]>=20.3.0; implementation_name == "cpython" +Twisted>=20.3.0; implementation_name == "pypy" zope.interface>=4.4.0 asynctest>=0.10.0 From d12ae25073ec0b44548f1f18ebdc41a404d250de Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 19:51:21 -0800 Subject: [PATCH 10/60] add gha timeout of 10 minutes --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1598f5679..bf9d44547 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,8 @@ jobs: name: ${{ matrix.task.name }} - ${{ matrix.os.name }} ${{ matrix.qt_library.name }} ${{ matrix.python.name }} ${{ matrix.arch.name }} runs-on: ${{ matrix.os.runs-on }} container: ${{ matrix.os.container[matrix.python.docker] }} + # present runtime seems to be about 1 minute 30 seconds + timeout-minutes: 10 strategy: fail-fast: false matrix: From 1a8f0175b1214286692618e355793f8bf1db629c Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 19:56:11 -0800 Subject: [PATCH 11/60] platform_python_implementation --- requirements-tests.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-tests.txt b/requirements-tests.txt index e8ac5b37f..28e4c6ffc 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -14,7 +14,7 @@ sqlalchemy>=1.1.15 #wsgiref>=0.1.2 verboselogs >= 1.5 tornado==4.5.3 -Twisted[serial]>=20.3.0; implementation_name == "cpython" -Twisted>=20.3.0; implementation_name == "pypy" +Twisted[serial]>=20.3.0; platform_python_implementation == "CPython" +Twisted>=20.3.0; platform_python_implementation == "PyPy" zope.interface>=4.4.0 asynctest>=0.10.0 From b30b69131b57c2cba4bb99126fceee18d37e54dd Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 20:16:34 -0800 Subject: [PATCH 12/60] maybe we do not need cryptography for tests? --- requirements-tests.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-tests.txt b/requirements-tests.txt index 28e4c6ffc..936522047 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -1,7 +1,7 @@ bcrypt>=3.1.6 capturer >= 2.2 coverage >= 4.2 -cryptography>= 2.3 +#cryptography>= 2.3 mock >= 1.0.1 pyserial-asyncio>=0.4.0;python_version>="3.4" pep8>=1.7.0 From 9043ba7e9739491758efc59c323136b2cf3cce5c Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 18 Jan 2021 20:28:59 -0800 Subject: [PATCH 13/60] add back cryptography to testing and conch extra to twisted for manhole --- requirements-tests.txt | 10 +++++++--- setup.py | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/requirements-tests.txt b/requirements-tests.txt index 936522047..dbb1af2c4 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -1,7 +1,7 @@ bcrypt>=3.1.6 capturer >= 2.2 coverage >= 4.2 -#cryptography>= 2.3 +cryptography>= 2.3 mock >= 1.0.1 pyserial-asyncio>=0.4.0;python_version>="3.4" pep8>=1.7.0 @@ -14,7 +14,11 @@ sqlalchemy>=1.1.15 #wsgiref>=0.1.2 verboselogs >= 1.5 tornado==4.5.3 -Twisted[serial]>=20.3.0; platform_python_implementation == "CPython" -Twisted>=20.3.0; platform_python_implementation == "PyPy" +# using platform_python_implementation rather than +# implementation_name for Python 2 support +Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" +# pywin32 isn't supported on pypy +# https://github.com/mhammond/pywin32/issues/1289 +Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" zope.interface>=4.4.0 asynctest>=0.10.0 diff --git a/setup.py b/setup.py index 20b210c05..66606a0ab 100644 --- a/setup.py +++ b/setup.py @@ -83,8 +83,12 @@ 'sphinx_rtd_theme', 'humanfriendly'], 'twisted': [ - 'twisted[serial] >= 20.3.0', - 'pyasn1 >= 0.1.4', + # using platform_python_implementation rather than + # implementation_name for Python 2 support + 'Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython"', + # pywin32 isn't supported on pypy + # https://github.com/mhammond/pywin32/issues/1289 + 'Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy"', ], 'tornado': [ 'tornado == 4.5.3' From 2f84a96f9e98caa5542e8d4544e1963f115bd1f9 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 08:44:46 -0500 Subject: [PATCH 14/60] install openssl in github actions windows for pypy --- .github/workflows/ci.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf9d44547..df8255241 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,9 @@ jobs: runs-on: windows-latest python_platform: win32 matrix: windows + openssl: + x86: win32 + x64: win64 # - name: macOS # runs-on: macos-latest # python_platform: darwin @@ -61,6 +64,7 @@ jobs: action: pypy-2.7 docker: pypy2.7 implementation: pypy + openssl_msvc_version: 2019 - name: CPython 3.6 tox: py36 action: 3.6 @@ -86,11 +90,13 @@ jobs: action: pypy-3.6 docker: pypy3.6 implementation: pypy + openssl_msvc_version: 2019 - name: PyPy 3.7 tox: pypy37 action: pypy-3.7 docker: pypy3.7 implementation: pypy + openssl_msvc_version: 2019 arch: - name: x86 action: x86 @@ -126,6 +132,14 @@ jobs: with: python-version: '${{ matrix.python.action }}' architecture: '${{ matrix.arch.action }}' + #https://github.com/pyca/cryptography/blob/d6535b68455767be37402ad7ce185d2e459daec8/.github/workflows/ci.yml#L237-L242 + - name: Download OpenSSL + if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} + run: | + python .github/workflows/download_openssl.py windows openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }} + echo "INCLUDE=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/include;$INCLUDE" >> $GITHUB_ENV + echo "LIB=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/lib;$LIB" >> $GITHUB_ENV +# echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - name: Install run: | pip install --upgrade pip setuptools wheel From 9da283ba66a6d164d518275dab93efc1cfa65c3e Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 09:10:38 -0500 Subject: [PATCH 15/60] more openssl --- .github/workflows/ci.yml | 8 +-- .github/workflows/download_openssl.py | 74 +++++++++++++++++++++++++++ tox.ini | 3 ++ 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/download_openssl.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df8255241..82853abce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -132,6 +132,10 @@ jobs: with: python-version: '${{ matrix.python.action }}' architecture: '${{ matrix.arch.action }}' + - name: Install + run: | + pip install --upgrade pip setuptools wheel + pip install --upgrade tox coveralls requests urllib3 #https://github.com/pyca/cryptography/blob/d6535b68455767be37402ad7ce185d2e459daec8/.github/workflows/ci.yml#L237-L242 - name: Download OpenSSL if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} @@ -140,10 +144,6 @@ jobs: echo "INCLUDE=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/include;$INCLUDE" >> $GITHUB_ENV echo "LIB=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/lib;$LIB" >> $GITHUB_ENV # echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - - name: Install - run: | - pip install --upgrade pip setuptools wheel - pip install --upgrade tox coveralls - uses: twisted/python-info-action@v1.0.1 - name: Test run: | diff --git a/.github/workflows/download_openssl.py b/.github/workflows/download_openssl.py new file mode 100644 index 000000000..d3d0f03f2 --- /dev/null +++ b/.github/workflows/download_openssl.py @@ -0,0 +1,74 @@ +import io +import os +import sys +import time +import zipfile + +import requests + +from urllib3.util.retry import Retry + + +def get_response(session, url, token): + # Retry on non-502s + for i in range(5): + response = session.get( + url, headers={"Authorization": "token " + token} + ) + if response.status_code != 200: + print( + "HTTP error ({}) fetching {}, retrying".format( + response.status_code, url + ) + ) + time.sleep(2) + continue + return response + response = session.get(url, headers={"Authorization": "token " + token}) + if response.status_code != 200: + raise ValueError( + "Got HTTP {} fetching {}: ".format(response.status_code, url) + ) + return response + + +def main(platform, target): + if platform == "windows": + workflow = "build-windows-openssl.yml" + path = "C:/" + elif platform == "macos": + workflow = "build-macos-openssl.yml" + path = os.environ["HOME"] + else: + raise ValueError("Invalid platform") + + session = requests.Session() + adapter = requests.adapters.HTTPAdapter(max_retries=Retry()) + session.mount("https://", adapter) + session.mount("http://", adapter) + + token = os.environ["GITHUB_TOKEN"] + print("Looking for: {}".format(target)) + runs_url = ( + "https://api.github.com/repos/pyca/infra/actions/workflows/" + "{}/runs?branch=master&status=success".format(workflow) + ) + + response = get_response(session, runs_url, token).json() + artifacts_url = response["workflow_runs"][0]["artifacts_url"] + response = get_response(session, artifacts_url, token).json() + for artifact in response["artifacts"]: + if artifact["name"] == target: + print("Found artifact") + response = get_response( + session, artifact["archive_download_url"], token + ) + zipfile.ZipFile(io.BytesIO(response.content)).extractall( + os.path.join(path, artifact["name"]) + ) + return + raise ValueError("Didn't find {} in {}".format(target, response)) + + +if __name__ == "__main__": + main(sys.argv[1], sys.argv[2]) \ No newline at end of file diff --git a/tox.ini b/tox.ini index b0fb1fd25..3bc911b87 100644 --- a/tox.ini +++ b/tox.ini @@ -10,6 +10,9 @@ envlist = py{27,py27,36,37,38,py36,py37} deps = -r requirements-tests.txt commands = pytest {posargs:--cov=pymodbus/ --cov-report=term-missing --cov-report=xml} +passenv = + INCLUDE + LIB setenv = with_gmp=no From 710ed9cfa82ff4f1a6623a54b66d769c6206f553 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 09:24:47 -0500 Subject: [PATCH 16/60] let's try choco install openssl and see where it installs --- .github/workflows/ci.yml | 11 ++-- .github/workflows/download_openssl.py | 74 --------------------------- 2 files changed, 5 insertions(+), 80 deletions(-) delete mode 100644 .github/workflows/download_openssl.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82853abce..ca4e139dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,14 +136,13 @@ jobs: run: | pip install --upgrade pip setuptools wheel pip install --upgrade tox coveralls requests urllib3 - #https://github.com/pyca/cryptography/blob/d6535b68455767be37402ad7ce185d2e459daec8/.github/workflows/ci.yml#L237-L242 - - name: Download OpenSSL + - name: Install OpenSSL if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} run: | - python .github/workflows/download_openssl.py windows openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }} - echo "INCLUDE=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/include;$INCLUDE" >> $GITHUB_ENV - echo "LIB=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/lib;$LIB" >> $GITHUB_ENV -# echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV + choco install openssl + echo "INCLUDE=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/include;$INCLUDE" >> $GITHUB_ENV + echo "LIB=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/lib;$LIB" >> $GITHUB_ENV +# echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - uses: twisted/python-info-action@v1.0.1 - name: Test run: | diff --git a/.github/workflows/download_openssl.py b/.github/workflows/download_openssl.py deleted file mode 100644 index d3d0f03f2..000000000 --- a/.github/workflows/download_openssl.py +++ /dev/null @@ -1,74 +0,0 @@ -import io -import os -import sys -import time -import zipfile - -import requests - -from urllib3.util.retry import Retry - - -def get_response(session, url, token): - # Retry on non-502s - for i in range(5): - response = session.get( - url, headers={"Authorization": "token " + token} - ) - if response.status_code != 200: - print( - "HTTP error ({}) fetching {}, retrying".format( - response.status_code, url - ) - ) - time.sleep(2) - continue - return response - response = session.get(url, headers={"Authorization": "token " + token}) - if response.status_code != 200: - raise ValueError( - "Got HTTP {} fetching {}: ".format(response.status_code, url) - ) - return response - - -def main(platform, target): - if platform == "windows": - workflow = "build-windows-openssl.yml" - path = "C:/" - elif platform == "macos": - workflow = "build-macos-openssl.yml" - path = os.environ["HOME"] - else: - raise ValueError("Invalid platform") - - session = requests.Session() - adapter = requests.adapters.HTTPAdapter(max_retries=Retry()) - session.mount("https://", adapter) - session.mount("http://", adapter) - - token = os.environ["GITHUB_TOKEN"] - print("Looking for: {}".format(target)) - runs_url = ( - "https://api.github.com/repos/pyca/infra/actions/workflows/" - "{}/runs?branch=master&status=success".format(workflow) - ) - - response = get_response(session, runs_url, token).json() - artifacts_url = response["workflow_runs"][0]["artifacts_url"] - response = get_response(session, artifacts_url, token).json() - for artifact in response["artifacts"]: - if artifact["name"] == target: - print("Found artifact") - response = get_response( - session, artifact["archive_download_url"], token - ) - zipfile.ZipFile(io.BytesIO(response.content)).extractall( - os.path.join(path, artifact["name"]) - ) - return - raise ValueError("Didn't find {} in {}".format(target, response)) - - -if __name__ == "__main__": - main(sys.argv[1], sys.argv[2]) \ No newline at end of file From 37fae4afbc53d35cb8777efc027f1b79e520e4bb Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 09:33:33 -0500 Subject: [PATCH 17/60] more for chocolately --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca4e139dc..0e807b6ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -139,9 +139,9 @@ jobs: - name: Install OpenSSL if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} run: | - choco install openssl - echo "INCLUDE=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/include;$INCLUDE" >> $GITHUB_ENV - echo "LIB=C:/openssl-${{ matrix.os.openssl[matrix.arch.matrix] }}-${{ matrix.python.openssl_msvc_version }}/lib;$LIB" >> $GITHUB_ENV + choco install --no-progress openssl + echo "INCLUDE=C:/Program Files/OpenSSL-Win64/include;$INCLUDE" >> $GITHUB_ENV + echo "LIB=C:/Program Files/OpenSSL-Win64/lib;$LIB" >> $GITHUB_ENV # echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - uses: twisted/python-info-action@v1.0.1 - name: Test From 3cd4ae1655cf8f51b48f2b03bfb632640c07c6f3 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 09:37:17 -0500 Subject: [PATCH 18/60] python info before openssl --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e807b6ff..68e798bf9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,6 +136,7 @@ jobs: run: | pip install --upgrade pip setuptools wheel pip install --upgrade tox coveralls requests urllib3 + - uses: twisted/python-info-action@v1.0.1 - name: Install OpenSSL if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} run: | @@ -143,7 +144,6 @@ jobs: echo "INCLUDE=C:/Program Files/OpenSSL-Win64/include;$INCLUDE" >> $GITHUB_ENV echo "LIB=C:/Program Files/OpenSSL-Win64/lib;$LIB" >> $GITHUB_ENV # echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - - uses: twisted/python-info-action@v1.0.1 - name: Test run: | tox -vv -e ${{ matrix.python.tox }} From 63cd0cafc5bf43a2b2f44a3b6c6ef29896dda498 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 09:41:01 -0500 Subject: [PATCH 19/60] skip pypy 64 on windows since you still get 32 --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68e798bf9..388e65d3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,6 +113,12 @@ jobs: matrix: macos arch: matrix: x86 + - os: + matrix: windows + python: + implementation: pypy + arch: + matrix: x64 env: # Should match name above JOB_NAME: ${{ matrix.task.name }} - ${{ matrix.os.name }} ${{ matrix.qt_library.name }} ${{ matrix.python.name }} ${{ matrix.arch.name }} From 08631abd5506960eb4a095c3022c2347f1e9dcb3 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 10:29:28 -0500 Subject: [PATCH 20/60] use pypy's openssl build --- .github/workflows/ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 388e65d3c..05f7b9f1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -143,12 +143,13 @@ jobs: pip install --upgrade pip setuptools wheel pip install --upgrade tox coveralls requests urllib3 - uses: twisted/python-info-action@v1.0.1 - - name: Install OpenSSL + - name: Add PyPy Externals if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} run: | - choco install --no-progress openssl - echo "INCLUDE=C:/Program Files/OpenSSL-Win64/include;$INCLUDE" >> $GITHUB_ENV - echo "LIB=C:/Program Files/OpenSSL-Win64/lib;$LIB" >> $GITHUB_ENV + hg clone https://foss.heptapod.net/pypy/externals/ $GITHUB_WORKSPACE/pypy_externals + cd pypy_externals && hg update win32_14x + echo "INCLUDE=$GITHUB_WORKSPACE/pypy_externals/include;$INCLUDE" >> $GITHUB_ENV + echo "LIB=$GITHUB_WORKSPACE/pypy_externals/lib;$LIB" >> $GITHUB_ENV # echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - name: Test run: | From 8ea88d0fc1e258b16f19757ef0ff58ca19bf6181 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 10:35:10 -0500 Subject: [PATCH 21/60] env var --- .github/workflows/ci.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05f7b9f1d..db2303721 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,11 +145,13 @@ jobs: - uses: twisted/python-info-action@v1.0.1 - name: Add PyPy Externals if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} + env: + PYPY_EXTERNALS_PATH: $GITHUB_WORKSPACE/pypy_externals run: | - hg clone https://foss.heptapod.net/pypy/externals/ $GITHUB_WORKSPACE/pypy_externals - cd pypy_externals && hg update win32_14x - echo "INCLUDE=$GITHUB_WORKSPACE/pypy_externals/include;$INCLUDE" >> $GITHUB_ENV - echo "LIB=$GITHUB_WORKSPACE/pypy_externals/lib;$LIB" >> $GITHUB_ENV + hg clone https://foss.heptapod.net/pypy/externals/ $PYPY_EXTERNALS_PATH + cd $PYPY_EXTERNALS_PATH && hg update win32_14x + echo "INCLUDE=$PYPY_EXTERNALS_PATH/include;$INCLUDE" >> $GITHUB_ENV + echo "LIB=$PYPY_EXTERNALS_PATH/lib;$LIB" >> $GITHUB_ENV # echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - name: Test run: | From 7b7929163509163f20bb837c6c227d7190c939ce Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 10:40:59 -0500 Subject: [PATCH 22/60] hmm --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db2303721..d975d6088 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,7 +148,10 @@ jobs: env: PYPY_EXTERNALS_PATH: $GITHUB_WORKSPACE/pypy_externals run: | + echo $PYPY_EXTERNALS_PATH + mkdir --parents $(dirname $PYPY_EXTERNALS_PATH) hg clone https://foss.heptapod.net/pypy/externals/ $PYPY_EXTERNALS_PATH + dir $PYPY_EXTERNALS_PATH cd $PYPY_EXTERNALS_PATH && hg update win32_14x echo "INCLUDE=$PYPY_EXTERNALS_PATH/include;$INCLUDE" >> $GITHUB_ENV echo "LIB=$PYPY_EXTERNALS_PATH/lib;$LIB" >> $GITHUB_ENV From 47dc912ad94129172df304961b25b885a5fca173 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 10:43:26 -0500 Subject: [PATCH 23/60] shell: bash --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d975d6088..5ac362485 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -147,6 +147,7 @@ jobs: if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} env: PYPY_EXTERNALS_PATH: $GITHUB_WORKSPACE/pypy_externals + shell: bash run: | echo $PYPY_EXTERNALS_PATH mkdir --parents $(dirname $PYPY_EXTERNALS_PATH) From e34a13e632bcd79b6e3c1ee52dca3dd1863957de Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 10:49:47 -0500 Subject: [PATCH 24/60] ${{ env.GITHUB_WORKSPACE }} --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ac362485..1960a800d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,7 +146,7 @@ jobs: - name: Add PyPy Externals if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} env: - PYPY_EXTERNALS_PATH: $GITHUB_WORKSPACE/pypy_externals + PYPY_EXTERNALS_PATH: ${{ env.GITHUB_WORKSPACE }}/pypy_externals shell: bash run: | echo $PYPY_EXTERNALS_PATH From a6b8fb6155944d01ef48a3e0a5677711b51b5145 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 11:07:31 -0500 Subject: [PATCH 25/60] env.workspace --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1960a800d..578f5ddf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,7 +146,7 @@ jobs: - name: Add PyPy Externals if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} env: - PYPY_EXTERNALS_PATH: ${{ env.GITHUB_WORKSPACE }}/pypy_externals + PYPY_EXTERNALS_PATH: ${{ env.workspace }}/pypy_externals shell: bash run: | echo $PYPY_EXTERNALS_PATH From d4e5740e3efdb69bd28e0295e5377aca6f700b9f Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 11:14:03 -0500 Subject: [PATCH 26/60] github.workspace --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 578f5ddf1..b9a6fadb2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,7 +146,7 @@ jobs: - name: Add PyPy Externals if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} env: - PYPY_EXTERNALS_PATH: ${{ env.workspace }}/pypy_externals + PYPY_EXTERNALS_PATH: ${{ github.workspace }}/pypy_externals shell: bash run: | echo $PYPY_EXTERNALS_PATH From d42835540e7087f4126cc64add8ec9622302c0c4 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 10:19:38 -0800 Subject: [PATCH 27/60] mock out socketserver.TCPServer.server_activate --- test/test_server_sync.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/test/test_server_sync.py b/test/test_server_sync.py index 0bfc4585d..297333154 100644 --- a/test/test_server_sync.py +++ b/test/test_server_sync.py @@ -279,20 +279,19 @@ def testTcpServerProcess(self): #-----------------------------------------------------------------------# def testTlsServerInit(self): ''' test that the synchronous TLS server intial correctly ''' - with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: - identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) - server = ModbusTlsServer(context=None, identity=identity, bind_and_activate=False) - server.server_activate() - self.assertIsNotNone(server.sslctx) - self.assertEqual(type(server.socket), ssl.SSLSocket) - server.server_close() - sslctx = ssl.create_default_context() - server = ModbusTlsServer(context=None, identity=identity, - sslctx=sslctx, bind_and_activate=False) - server.server_activate() - self.assertEqual(server.sslctx, sslctx) - self.assertEqual(type(server.socket), ssl.SSLSocket) - server.server_close() + with patch.object(socketserver.TCPServer, 'server_activate'): + with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: + identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) + server = ModbusTlsServer(context=None, identity=identity) + self.assertIsNotNone(server.sslctx) + self.assertEqual(type(server.socket), ssl.SSLSocket) + server.server_close() + sslctx = ssl.create_default_context() + server = ModbusTlsServer(context=None, identity=identity, + sslctx=sslctx) + self.assertEqual(server.sslctx, sslctx) + self.assertEqual(type(server.socket), ssl.SSLSocket) + server.server_close() def testTlsServerClose(self): ''' test that the synchronous TLS server closes correctly ''' From a5a975b7244ee74e13c62cfaf2b4bda73a709ef1 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 10:23:40 -0800 Subject: [PATCH 28/60] just skipif tornado serial on windows for now --- test/test_client_async.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_client_async.py b/test/test_client_async.py index f8ecf09e9..342203660 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -221,6 +221,7 @@ def handle_failure(failure): protocol.stop() assert (not client.protocol._connected) + @pytest.mark.skipif(sys.platform == 'win32', reason="needs work on Windows") @pytest.mark.parametrize("method, framer", [("rtu", ModbusRtuFramer), ("socket", ModbusSocketFramer), ("binary", ModbusBinaryFramer), From ba6814ac49314a334a34bf127c52093a531b42c7 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 10:31:33 -0800 Subject: [PATCH 29/60] some more sleeps to help asyncio tests --- test/test_server_asyncio.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_server_asyncio.py b/test/test_server_asyncio.py index 42cb67ad4..cc06b0bd7 100755 --- a/test/test_server_asyncio.py +++ b/test/test_server_asyncio.py @@ -211,7 +211,9 @@ def connection_made(self, transport): transport, protocol = yield from self.loop.create_connection(BasicClient, host='127.0.0.1', port=random_port) yield from step1 - # await asyncio.sleep(1) + # On Windows we seem to need to give this an extra chance to finish, + # otherwise there ends up being an active connection at the assert. + yield from asyncio.sleep(0.0) self.assertTrue(len(server.active_connections) == 1) protocol.transport.close() # close isn't synchronous and there's no notification that it's done @@ -246,6 +248,9 @@ def connection_made(self, transport): transport, protocol = yield from self.loop.create_connection(BasicClient, host='127.0.0.1',port=random_port) yield from step1 + # On Windows we seem to need to give this an extra chance to finish, + # otherwise there ends up being an active connection at the assert. + yield from asyncio.sleep(0.0) server.server_close() # close isn't synchronous and there's no notification that it's done From 649ac09fdae1216cc03693df5758c89a9ce4726b Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 10:57:19 -0800 Subject: [PATCH 30/60] inet_pton skips --- test/test_client_sync.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_client_sync.py b/test/test_client_sync.py index 1014a9382..54c3b0279 100644 --- a/test/test_client_sync.py +++ b/test/test_client_sync.py @@ -9,6 +9,9 @@ import socket import serial import ssl +import sys + +import pytest from pymodbus.client.sync import ModbusTcpClient, ModbusUdpClient from pymodbus.client.sync import ModbusSerialClient, BaseModbusClient @@ -43,6 +46,15 @@ def setblocking(self, flag): return None def in_waiting(self): return None +inet_pton_skipif = pytest.mark.skipif( + sys.platform == "win32" and sys.version < (3, 4), + reason=( + "Uses socket.inet_pton() which wasn't available on Windows until" + " 3.4.", + ) +) + + # ---------------------------------------------------------------------------# # Fixture @@ -110,6 +122,7 @@ def testBasicSyncUdpClient(self): self.assertEqual("ModbusUdpClient(127.0.0.1:502)", str(client)) + @inet_pton_skipif def testUdpClientAddressFamily(self): ''' Test the Udp client get address family method''' client = ModbusUdpClient() @@ -117,6 +130,7 @@ def testUdpClientAddressFamily(self): client._get_address_family('127.0.0.1')) self.assertEqual(socket.AF_INET6, client._get_address_family('::1')) + @inet_pton_skipif def testUdpClientConnect(self): ''' Test the Udp client connection method''' with patch.object(socket, 'socket') as mock_method: From 74e34fce12978b78f5357428f4e5122e6d000984 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 11:06:41 -0800 Subject: [PATCH 31/60] it is sys.version_info for the tuple comparison --- test/test_client_sync.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_client_sync.py b/test/test_client_sync.py index 54c3b0279..706a9a009 100644 --- a/test/test_client_sync.py +++ b/test/test_client_sync.py @@ -47,7 +47,7 @@ def in_waiting(self): return None inet_pton_skipif = pytest.mark.skipif( - sys.platform == "win32" and sys.version < (3, 4), + sys.platform == "win32" and sys.version_info < (3, 4), reason=( "Uses socket.inet_pton() which wasn't available on Windows until" " 3.4.", From 892c8b4027260bef28a55720332c77497609c6b2 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 11:47:47 -0800 Subject: [PATCH 32/60] exclude Python 3.9 on Windows since twisted does not support it --- .github/workflows/ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9a6fadb2..c56cc920f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,43 +58,51 @@ jobs: tox: py27 action: 2.7 docker: 2.7 + matrix: 2.7 implementation: cpython - name: PyPy 2.7 tox: pypy27 action: pypy-2.7 docker: pypy2.7 + matrix: 2.7 implementation: pypy openssl_msvc_version: 2019 - name: CPython 3.6 tox: py36 action: 3.6 docker: 3.6 + matrix: 3.6 implementation: cpython - name: CPython 3.7 tox: py37 action: 3.7 docker: 3.7 + matrix: 3.7 implementation: cpython - name: CPython 3.8 tox: py38 action: 3.8 docker: 3.8 + matrix: 3.8 implementation: cpython - name: CPython 3.9 tox: py39 action: 3.9 docker: 3.9 + matrix: 3.9 implementation: cpython - name: PyPy 3.6 tox: pypy36 action: pypy-3.6 docker: pypy3.6 + matrix: 3.6 implementation: pypy openssl_msvc_version: 2019 - name: PyPy 3.7 tox: pypy37 action: pypy-3.7 docker: pypy3.7 + matrix: 3.7 implementation: pypy openssl_msvc_version: 2019 arch: @@ -119,6 +127,11 @@ jobs: implementation: pypy arch: matrix: x64 + # Twisted doesn't support Python 3.9 on Windows as of 20.3.0 + - os: + matrix: windows + python: + matrix: 3.9 env: # Should match name above JOB_NAME: ${{ matrix.task.name }} - ${{ matrix.os.name }} ${{ matrix.qt_library.name }} ${{ matrix.python.name }} ${{ matrix.arch.name }} From 5f5cc4a6d1a0bbd8d34283b16fc90d890894424d Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 12:25:31 -0800 Subject: [PATCH 33/60] only skip twisted" s serial extra on pypy/windows --- requirements-tests.txt | 4 ++-- setup.py | 4 ++-- test/test_server_sync.py | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/requirements-tests.txt b/requirements-tests.txt index dbb1af2c4..d12a7a941 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -16,9 +16,9 @@ verboselogs >= 1.5 tornado==4.5.3 # using platform_python_implementation rather than # implementation_name for Python 2 support -Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" +Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" or sys_platform != "win32" # pywin32 isn't supported on pypy # https://github.com/mhammond/pywin32/issues/1289 -Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" +Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" and sys_platform == "win32" zope.interface>=4.4.0 asynctest>=0.10.0 diff --git a/setup.py b/setup.py index 66606a0ab..e7331b01e 100644 --- a/setup.py +++ b/setup.py @@ -85,10 +85,10 @@ 'twisted': [ # using platform_python_implementation rather than # implementation_name for Python 2 support - 'Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython"', + 'Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" or sys_platform != "win32"', # pywin32 isn't supported on pypy # https://github.com/mhammond/pywin32/issues/1289 - 'Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy"', + 'Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" and sys_platform == "win32"', ], 'tornado': [ 'tornado == 4.5.3' diff --git a/test/test_server_sync.py b/test/test_server_sync.py index 297333154..30c2ba83d 100644 --- a/test/test_server_sync.py +++ b/test/test_server_sync.py @@ -282,7 +282,8 @@ def testTlsServerInit(self): with patch.object(socketserver.TCPServer, 'server_activate'): with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) - server = ModbusTlsServer(context=None, identity=identity) + server = ModbusTlsServer(context=None, identity=identity, bind_and_activate=False) + server.server_activate() self.assertIsNotNone(server.sslctx) self.assertEqual(type(server.socket), ssl.SSLSocket) server.server_close() From 5f6808f91c202d451c042c8319ba347b1d5c2935 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 12:30:07 -0800 Subject: [PATCH 34/60] another bind avoidance --- test/test_server_sync.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_server_sync.py b/test/test_server_sync.py index 30c2ba83d..ce359ee47 100644 --- a/test/test_server_sync.py +++ b/test/test_server_sync.py @@ -289,7 +289,8 @@ def testTlsServerInit(self): server.server_close() sslctx = ssl.create_default_context() server = ModbusTlsServer(context=None, identity=identity, - sslctx=sslctx) + sslctx=sslctx, bind_and_activate=False) + server.server_activate() self.assertEqual(server.sslctx, sslctx) self.assertEqual(type(server.socket), ssl.SSLSocket) server.server_close() From 29ef6b50cec88c60259ed4dc1dccc96ad3f4d10c Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 12:47:45 -0800 Subject: [PATCH 35/60] skip some twisted on windows in pypy --- test/test_server_async.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_server_async.py b/test/test_server_async.py index 4fe04add3..c88f6e4db 100644 --- a/test/test_server_async.py +++ b/test/test_server_async.py @@ -1,6 +1,7 @@ #!/usr/bin/env python from pymodbus.compat import IS_PYTHON3 import unittest +import pytest if IS_PYTHON3: # Python 3 from unittest.mock import patch, Mock, MagicMock else: # Python 2 @@ -32,6 +33,11 @@ IS_HIGH_SIERRA_OR_ABOVE = False SERIAL_PORT = "/dev/ptmx" +no_twisted_serial_on_windows_with_pypy = pytest.mark.skipif( + sys.platform == 'win32' and platform.python_implementation() == 'PyPy', + reason='Twisted serial requires pywin32 which is not compatible with PyPy', +) + class AsynchronousServerTest(unittest.TestCase): ''' @@ -188,6 +194,7 @@ def testUdpServerStartup(self): self.assertEqual(mock_reactor.listenUDP.call_count, 1) self.assertEqual(mock_reactor.run.call_count, 1) + @no_twisted_serial_on_windows_with_pypy @patch("twisted.internet.serialport.SerialPort") def testSerialServerStartup(self, mock_sp): ''' Test that the modbus serial asynchronous server starts correctly ''' @@ -195,6 +202,7 @@ def testSerialServerStartup(self, mock_sp): StartSerialServer(context=None, port=SERIAL_PORT) self.assertEqual(mock_reactor.run.call_count, 1) + @no_twisted_serial_on_windows_with_pypy @patch("twisted.internet.serialport.SerialPort") def testStopServerFromMainThread(self, mock_sp): """ @@ -207,6 +215,7 @@ def testStopServerFromMainThread(self, mock_sp): StopServer() self.assertEqual(mock_reactor.stop.call_count, 1) + @no_twisted_serial_on_windows_with_pypy @patch("twisted.internet.serialport.SerialPort") def testStopServerFromThread(self, mock_sp): """ From 960a74503f5f63c6fbad64c7a82849e2d70f8d25 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 13:24:36 -0800 Subject: [PATCH 36/60] more pypy/windows skipping --- test/test_client_async.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_client_async.py b/test/test_client_async.py index 342203660..494ec14b1 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -176,6 +176,10 @@ def testUdpAsycioClient(self, mock_gather, mock_event_loop): # Test Serial client # -----------------------------------------------------------------------# + @pytest.mark.skipif( + sys.platform == 'win32' and platform.python_implementation() == 'PyPy', + reason='Twisted serial requires pywin32 which is not compatible with PyPy', + ) @pytest.mark.parametrize("method, framer", [("rtu", ModbusRtuFramer), ("socket", ModbusSocketFramer), ("binary", ModbusBinaryFramer), From 0afe7e6070c48de2d2230d020298e4844c356831 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 22:06:33 -0500 Subject: [PATCH 37/60] remove pypy stuff --- .github/workflows/ci.yml | 53 ++------------------------------------- requirements-tests.txt | 7 +----- setup.py | 7 +----- test/test_client_async.py | 4 --- test/test_server_async.py | 8 ------ tox.ini | 6 +---- 6 files changed, 5 insertions(+), 80 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c56cc920f..7b871f00f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,8 +40,6 @@ jobs: 3.7: docker://python:3.7-buster 3.8: docker://python:3.8-buster 3.9: docker://python:3.9-buster - pypy2: docker://pypy:2-jessie - pypy3: docker://pypy:3-stretch - name: Windows runs-on: windows-latest python_platform: win32 @@ -60,13 +58,6 @@ jobs: docker: 2.7 matrix: 2.7 implementation: cpython - - name: PyPy 2.7 - tox: pypy27 - action: pypy-2.7 - docker: pypy2.7 - matrix: 2.7 - implementation: pypy - openssl_msvc_version: 2019 - name: CPython 3.6 tox: py36 action: 3.6 @@ -91,20 +82,6 @@ jobs: docker: 3.9 matrix: 3.9 implementation: cpython - - name: PyPy 3.6 - tox: pypy36 - action: pypy-3.6 - docker: pypy3.6 - matrix: 3.6 - implementation: pypy - openssl_msvc_version: 2019 - - name: PyPy 3.7 - tox: pypy37 - action: pypy-3.7 - docker: pypy3.7 - matrix: 3.7 - implementation: pypy - openssl_msvc_version: 2019 arch: - name: x86 action: x86 @@ -121,12 +98,6 @@ jobs: matrix: macos arch: matrix: x86 - - os: - matrix: windows - python: - implementation: pypy - arch: - matrix: x64 # Twisted doesn't support Python 3.9 on Windows as of 20.3.0 - os: matrix: windows @@ -139,37 +110,17 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Set up ${{ matrix.python.name }} (if CPython) - if: ${{ job.container == '' && matrix.python.implementation == 'cpython'}} + - name: Set up ${{ matrix.python.name }} + if: ${{ job.container == ''}} uses: actions/setup-python@v2 with: python-version: '${{ matrix.python.action }}.0-alpha - ${{ matrix.python.action }}.X' architecture: '${{ matrix.arch.action }}' - - name: Set up ${{ matrix.python.name }} (if PyPy) - if: ${{ job.container == '' && matrix.python.implementation == 'pypy'}} - uses: actions/setup-python@v2 - with: - python-version: '${{ matrix.python.action }}' - architecture: '${{ matrix.arch.action }}' - name: Install run: | pip install --upgrade pip setuptools wheel pip install --upgrade tox coveralls requests urllib3 - uses: twisted/python-info-action@v1.0.1 - - name: Add PyPy Externals - if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} - env: - PYPY_EXTERNALS_PATH: ${{ github.workspace }}/pypy_externals - shell: bash - run: | - echo $PYPY_EXTERNALS_PATH - mkdir --parents $(dirname $PYPY_EXTERNALS_PATH) - hg clone https://foss.heptapod.net/pypy/externals/ $PYPY_EXTERNALS_PATH - dir $PYPY_EXTERNALS_PATH - cd $PYPY_EXTERNALS_PATH && hg update win32_14x - echo "INCLUDE=$PYPY_EXTERNALS_PATH/include;$INCLUDE" >> $GITHUB_ENV - echo "LIB=$PYPY_EXTERNALS_PATH/lib;$LIB" >> $GITHUB_ENV -# echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - name: Test run: | tox -vv -e ${{ matrix.python.tox }} diff --git a/requirements-tests.txt b/requirements-tests.txt index d12a7a941..8216e41c8 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -14,11 +14,6 @@ sqlalchemy>=1.1.15 #wsgiref>=0.1.2 verboselogs >= 1.5 tornado==4.5.3 -# using platform_python_implementation rather than -# implementation_name for Python 2 support -Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" or sys_platform != "win32" -# pywin32 isn't supported on pypy -# https://github.com/mhammond/pywin32/issues/1289 -Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" and sys_platform == "win32" +Twisted[conch,serial]>=20.3.0 zope.interface>=4.4.0 asynctest>=0.10.0 diff --git a/setup.py b/setup.py index e7331b01e..1b6163ddb 100644 --- a/setup.py +++ b/setup.py @@ -83,12 +83,7 @@ 'sphinx_rtd_theme', 'humanfriendly'], 'twisted': [ - # using platform_python_implementation rather than - # implementation_name for Python 2 support - 'Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" or sys_platform != "win32"', - # pywin32 isn't supported on pypy - # https://github.com/mhammond/pywin32/issues/1289 - 'Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" and sys_platform == "win32"', + 'Twisted[conch,serial]>=20.3.0', ], 'tornado': [ 'tornado == 4.5.3' diff --git a/test/test_client_async.py b/test/test_client_async.py index 494ec14b1..342203660 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -176,10 +176,6 @@ def testUdpAsycioClient(self, mock_gather, mock_event_loop): # Test Serial client # -----------------------------------------------------------------------# - @pytest.mark.skipif( - sys.platform == 'win32' and platform.python_implementation() == 'PyPy', - reason='Twisted serial requires pywin32 which is not compatible with PyPy', - ) @pytest.mark.parametrize("method, framer", [("rtu", ModbusRtuFramer), ("socket", ModbusSocketFramer), ("binary", ModbusBinaryFramer), diff --git a/test/test_server_async.py b/test/test_server_async.py index c88f6e4db..f5a3b9cfd 100644 --- a/test/test_server_async.py +++ b/test/test_server_async.py @@ -33,11 +33,6 @@ IS_HIGH_SIERRA_OR_ABOVE = False SERIAL_PORT = "/dev/ptmx" -no_twisted_serial_on_windows_with_pypy = pytest.mark.skipif( - sys.platform == 'win32' and platform.python_implementation() == 'PyPy', - reason='Twisted serial requires pywin32 which is not compatible with PyPy', -) - class AsynchronousServerTest(unittest.TestCase): ''' @@ -194,7 +189,6 @@ def testUdpServerStartup(self): self.assertEqual(mock_reactor.listenUDP.call_count, 1) self.assertEqual(mock_reactor.run.call_count, 1) - @no_twisted_serial_on_windows_with_pypy @patch("twisted.internet.serialport.SerialPort") def testSerialServerStartup(self, mock_sp): ''' Test that the modbus serial asynchronous server starts correctly ''' @@ -202,7 +196,6 @@ def testSerialServerStartup(self, mock_sp): StartSerialServer(context=None, port=SERIAL_PORT) self.assertEqual(mock_reactor.run.call_count, 1) - @no_twisted_serial_on_windows_with_pypy @patch("twisted.internet.serialport.SerialPort") def testStopServerFromMainThread(self, mock_sp): """ @@ -215,7 +208,6 @@ def testStopServerFromMainThread(self, mock_sp): StopServer() self.assertEqual(mock_reactor.stop.call_count, 1) - @no_twisted_serial_on_windows_with_pypy @patch("twisted.internet.serialport.SerialPort") def testStopServerFromThread(self, mock_sp): """ diff --git a/tox.ini b/tox.ini index 3bc911b87..0d271857a 100644 --- a/tox.ini +++ b/tox.ini @@ -10,11 +10,7 @@ envlist = py{27,py27,36,37,38,py36,py37} deps = -r requirements-tests.txt commands = pytest {posargs:--cov=pymodbus/ --cov-report=term-missing --cov-report=xml} -passenv = - INCLUDE - LIB -setenv = - with_gmp=no +setenv = with_gmp=no [flake8] exclude = .tox From 20ffdf95a7a92cbc9db35ae740275cb97945dbee Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 20:08:47 -0800 Subject: [PATCH 38/60] way simplify the twisted --- .../client/asynchronous/factory/serial.py | 64 +++------------ test/test_client_async.py | 80 ++++++++++--------- 2 files changed, 51 insertions(+), 93 deletions(-) diff --git a/pymodbus/client/asynchronous/factory/serial.py b/pymodbus/client/asynchronous/factory/serial.py index 85421bace..62b719c5c 100644 --- a/pymodbus/client/asynchronous/factory/serial.py +++ b/pymodbus/client/asynchronous/factory/serial.py @@ -5,7 +5,6 @@ from __future__ import absolute_import import logging -import sys import time from pymodbus.client.asynchronous import schedulers from pymodbus.client.asynchronous.thread import EventLoopThread @@ -38,62 +37,17 @@ def buildProtocol(self): proto.factory = self return proto - if sys.platform == "win32": - import serial - import serial.win32 + class SerialModbusClient(SerialPort): - class RegularFileSerial(serial.Serial): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.captured_args = args - self.captured_kwargs = kwargs + def __init__(self, framer, *args, **kwargs): + ''' Setup the client and start listening on the serial port - def _reconfigurePort(self): - pass - - def _reconfigure_port(self): - pass - - class RegularFileSerialPort(SerialPort): - _serialFactory = RegularFileSerial - - def __init__(self, *args, **kwargs): - cbInQue = kwargs.get("cbInQue") - - if "cbInQue" in kwargs: - del kwargs["cbInQue"] - - self.comstat = serial.win32.COMSTAT - self.comstat.cbInQue = cbInQue - - super().__init__(*args, **kwargs) - - def _clearCommError(self): - return True, self.comstat - - class SerialModbusClient(RegularFileSerialPort): - - def __init__(self, framer, *args, **kwargs): - ''' Setup the client and start listening on the serial port - - :param factory: The factory to build clients with - ''' - self.decoder = ClientDecoder() - proto_cls = kwargs.pop("proto_cls", None) - proto = SerialClientFactory(framer, proto_cls).buildProtocol() - super(SerialModbusClient, self).__init__(proto, *args, **kwargs) - else: - class SerialModbusClient(SerialPort): - - def __init__(self, framer, *args, **kwargs): - ''' Setup the client and start listening on the serial port - - :param factory: The factory to build clients with - ''' - self.decoder = ClientDecoder() - proto_cls = kwargs.pop("proto_cls", None) - proto = SerialClientFactory(framer, proto_cls).buildProtocol() - super(SerialModbusClient, self).__init__(proto, *args, **kwargs) + :param factory: The factory to build clients with + ''' + self.decoder = ClientDecoder() + proto_cls = kwargs.pop("proto_cls", None) + proto = SerialClientFactory(framer, proto_cls).buildProtocol() + SerialPort.__init__(self, proto, *args, **kwargs) proto = EventLoopThread("reactor", reactor.run, reactor.stop, installSignalHandlers=0) diff --git a/test/test_client_async.py b/test/test_client_async.py index 342203660..45baebaff 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -31,13 +31,18 @@ import ssl IS_DARWIN = platform.system().lower() == "darwin" +IS_WINDOWS = platform.system().lower() == "windows" OSX_SIERRA = LooseVersion("10.12") if IS_DARWIN: IS_HIGH_SIERRA_OR_ABOVE = LooseVersion(platform.mac_ver()[0]) SERIAL_PORT = '/dev/ttyp0' if not IS_HIGH_SIERRA_OR_ABOVE else '/dev/ptyp0' else: IS_HIGH_SIERRA_OR_ABOVE = False - SERIAL_PORT = "/dev/ptmx" + if IS_WINDOWS: + # the use is mocked out + SERIAL_PORT = "" + else: + SERIAL_PORT = "/dev/ptmx" # ---------------------------------------------------------------------------# # Fixture @@ -182,44 +187,43 @@ def testUdpAsycioClient(self, mock_gather, mock_event_loop): ("ascii", ModbusAsciiFramer)]) def testSerialTwistedClient(self, method, framer): """ Test the serial twisted client client initialize """ + import contextlib + @contextlib.contextmanager + def maybe_manage(condition, manager): + if condition: + with manager as value: + yield value + else: + yield None + from serial import Serial - from twisted.internet import reactor - from twisted.internet.serialport import SerialPort - - with patch('twisted.internet.reactor') as mock_reactor: - if sys.platform == "win32": - import os.path - import tempfile - directory = tempfile.mkdtemp() - path = os.path.join(directory, "fake_serial") - - data = b"1234" - with open(path, "wb") as f: - f.write(data) - global SERIAL_PORT - SERIAL_PORT = path - - protocol, client = AsyncModbusSerialClient(schedulers.REACTOR, - method=method, - port=SERIAL_PORT, - proto_cls=ModbusSerClientProtocol) - - assert (isinstance(client, SerialPort)) - assert (isinstance(client.protocol, ModbusSerClientProtocol)) - assert (0 == len(list(client.protocol.transaction))) - assert (isinstance(client.protocol.framer, framer)) - assert (client.protocol._connected) - - def handle_failure(failure): - assert (isinstance(failure.exception(), ConnectionException)) - - d = client.protocol._buildResponse(0x00) - d.addCallback(handle_failure) - - assert (client.protocol._connected) - client.protocol.close() - protocol.stop() - assert (not client.protocol._connected) + with patch("serial.Serial") as mock_sp: + from twisted.internet import reactor + from twisted.internet.serialport import SerialPort + with maybe_manage(sys.platform == 'win32', patch.object(SerialPort, "_finishPortSetup")): + with patch('twisted.internet.reactor') as mock_reactor: + + protocol, client = AsyncModbusSerialClient(schedulers.REACTOR, + method=method, + port=SERIAL_PORT, + proto_cls=ModbusSerClientProtocol) + + assert (isinstance(client, SerialPort)) + assert (isinstance(client.protocol, ModbusSerClientProtocol)) + assert (0 == len(list(client.protocol.transaction))) + assert (isinstance(client.protocol.framer, framer)) + assert (client.protocol._connected) + + def handle_failure(failure): + assert (isinstance(failure.exception(), ConnectionException)) + + d = client.protocol._buildResponse(0x00) + d.addCallback(handle_failure) + + assert (client.protocol._connected) + client.protocol.close() + protocol.stop() + assert (not client.protocol._connected) @pytest.mark.skipif(sys.platform == 'win32', reason="needs work on Windows") @pytest.mark.parametrize("method, framer", [("rtu", ModbusRtuFramer), From e9309464f070cd580d0849175a6ef6d67b6c3316 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 20:18:55 -0800 Subject: [PATCH 39/60] un-ignore a couple test files --- pymodbus/client/asynchronous/tornado/__init__.py | 2 +- test/conftest.py | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pymodbus/client/asynchronous/tornado/__init__.py b/pymodbus/client/asynchronous/tornado/__init__.py index 29e0e4db2..bbf9585ed 100644 --- a/pymodbus/client/asynchronous/tornado/__init__.py +++ b/pymodbus/client/asynchronous/tornado/__init__.py @@ -315,7 +315,7 @@ def __init__(self, *args, **kwargs): self.silent_interval = 3.5 * self._t0 self.silent_interval = round(self.silent_interval, 6) self.last_frame_end = 0.0 - super().__init__(*args, **kwargs) + super(AsyncModbusSerialClient, self).__init__(*args, **kwargs) def get_socket(self): """ diff --git a/test/conftest.py b/test/conftest.py index c8e3a2df7..2dcc8a716 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -2,9 +2,5 @@ if PYTHON_VERSION < (3,): collect_ignore = [ - # TODO: do these really need to be ignored on py2 or can they just get - # super() etc fixed? - "test_client_async.py", - "test_client_async_tornado.py", "test_server_asyncio.py", ] From ceada4cc3bc1d5f725a0052632a4c549f021bdd8 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 20:25:53 -0800 Subject: [PATCH 40/60] formatting --- setup.py | 2 +- test/conftest.py | 5 +---- test/test_server_sync.py | 9 ++++++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 1b6163ddb..251943d3b 100644 --- a/setup.py +++ b/setup.py @@ -83,7 +83,7 @@ 'sphinx_rtd_theme', 'humanfriendly'], 'twisted': [ - 'Twisted[conch,serial]>=20.3.0', + 'Twisted[conch,serial] >= 20.3.0', ], 'tornado': [ 'tornado == 4.5.3' diff --git a/test/conftest.py b/test/conftest.py index 2dcc8a716..8086a84c8 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,6 +1,3 @@ from pymodbus.compat import PYTHON_VERSION - if PYTHON_VERSION < (3,): - collect_ignore = [ - "test_server_asyncio.py", - ] + collect_ignore = ["test_server_asyncio.py"] diff --git a/test/test_server_sync.py b/test/test_server_sync.py index ce359ee47..4741ad03e 100644 --- a/test/test_server_sync.py +++ b/test/test_server_sync.py @@ -282,7 +282,8 @@ def testTlsServerInit(self): with patch.object(socketserver.TCPServer, 'server_activate'): with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) - server = ModbusTlsServer(context=None, identity=identity, bind_and_activate=False) + server = ModbusTlsServer(context=None, identity=identity, + bind_and_activate=False) server.server_activate() self.assertIsNotNone(server.sslctx) self.assertEqual(type(server.socket), ssl.SSLSocket) @@ -299,7 +300,8 @@ def testTlsServerClose(self): ''' test that the synchronous TLS server closes correctly ''' with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method: identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) - server = ModbusTlsServer(context=None, identity=identity, bind_and_activate=False) + server = ModbusTlsServer(context=None, identity=identity, + bind_and_activate=False) server.threads.append(Mock(**{'running': True})) server.server_close() self.assertEqual(server.control.Identity.VendorName, 'VendorName') @@ -319,7 +321,8 @@ def testTlsServerProcess(self): def testUdpServerClose(self): ''' test that the synchronous UDP server closes correctly ''' identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) - server = ModbusUdpServer(context=None, identity=identity, bind_and_activate=False) + server = ModbusUdpServer(context=None, identity=identity, + bind_and_activate=False) server.server_activate() server.threads.append(Mock(**{'running': True})) server.server_close() From 6db6c6e12304ebc96ff05a02232c83fdde6a22b7 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 19 Jan 2021 20:39:27 -0800 Subject: [PATCH 41/60] mock for tornado on windows --- test/test_client_async.py | 58 ++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/test/test_client_async.py b/test/test_client_async.py index 45baebaff..6664af977 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +import contextlib import sys import unittest import pytest @@ -53,6 +54,15 @@ def mock_asyncio_gather(coro): return coro +@contextlib.contextmanager +def maybe_manage(condition, manager): + if condition: + with manager as value: + yield value + else: + yield None + + class TestAsynchronousClient(object): """ This is the unittest for the pymodbus.client.asynchronous module @@ -187,15 +197,6 @@ def testUdpAsycioClient(self, mock_gather, mock_event_loop): ("ascii", ModbusAsciiFramer)]) def testSerialTwistedClient(self, method, framer): """ Test the serial twisted client client initialize """ - import contextlib - @contextlib.contextmanager - def maybe_manage(condition, manager): - if condition: - with manager as value: - yield value - else: - yield None - from serial import Serial with patch("serial.Serial") as mock_sp: from twisted.internet import reactor @@ -225,31 +226,32 @@ def handle_failure(failure): protocol.stop() assert (not client.protocol._connected) - @pytest.mark.skipif(sys.platform == 'win32', reason="needs work on Windows") @pytest.mark.parametrize("method, framer", [("rtu", ModbusRtuFramer), ("socket", ModbusSocketFramer), ("binary", ModbusBinaryFramer), ("ascii", ModbusAsciiFramer)]) def testSerialTornadoClient(self, method, framer): """ Test the serial tornado client client initialize """ - protocol, future = AsyncModbusSerialClient(schedulers.IO_LOOP, method=method, port=SERIAL_PORT) - client = future.result() - assert(isinstance(client, AsyncTornadoModbusSerialClient)) - assert(0 == len(list(client.transaction))) - assert(isinstance(client.framer, framer)) - assert(client.port == SERIAL_PORT) - assert(client._connected) - - def handle_failure(failure): - assert(isinstance(failure.exception(), ConnectionException)) - - d = client._build_response(0x00) - d.add_done_callback(handle_failure) - - assert(client._connected) - client.close() - protocol.stop() - assert(not client._connected) + from serial import Serial + with maybe_manage(sys.platform == 'win32', patch.object(Serial, "open")): + protocol, future = AsyncModbusSerialClient(schedulers.IO_LOOP, method=method, port=SERIAL_PORT) + client = future.result() + assert(isinstance(client, AsyncTornadoModbusSerialClient)) + assert(0 == len(list(client.transaction))) + assert(isinstance(client.framer, framer)) + assert(client.port == SERIAL_PORT) + assert(client._connected) + + def handle_failure(failure): + assert(isinstance(failure.exception(), ConnectionException)) + + d = client._build_response(0x00) + d.add_done_callback(handle_failure) + + assert(client._connected) + client.close() + protocol.stop() + assert(not client._connected) @pytest.mark.skipif(IS_PYTHON3 , reason="requires python2.7") def testSerialAsyncioClientPython2(self): From 19fc04415ca5e957a8dfce91e5318dcb11d236cc Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 20 Jan 2021 14:54:30 -0500 Subject: [PATCH 42/60] mock serial.Serial in macOS --- test/test_client_async.py | 49 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/test/test_client_async.py b/test/test_client_async.py index 97aaae8bd..47ed1c730 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -1,4 +1,6 @@ #!/usr/bin/env python +import contextlib +import sys import unittest import pytest from pymodbus.compat import IS_PYTHON3, PYTHON_VERSION @@ -47,6 +49,15 @@ def mock_asyncio_gather(coro): return coro +@contextlib.contextmanager +def maybe_manage(condition, manager): + if condition: + with manager as value: + yield value + else: + yield None + + class TestAsynchronousClient(object): """ This is the unittest for the pymodbus.client.asynchronous module @@ -216,24 +227,26 @@ def handle_failure(failure): ("ascii", ModbusAsciiFramer)]) def testSerialTornadoClient(self, method, framer): """ Test the serial tornado client client initialize """ - protocol, future = AsyncModbusSerialClient(schedulers.IO_LOOP, method=method, port=SERIAL_PORT) - client = future.result() - assert(isinstance(client, AsyncTornadoModbusSerialClient)) - assert(0 == len(list(client.transaction))) - assert(isinstance(client.framer, framer)) - assert(client.port == SERIAL_PORT) - assert(client._connected) - - def handle_failure(failure): - assert(isinstance(failure.exception(), ConnectionException)) - - d = client._build_response(0x00) - d.add_done_callback(handle_failure) - - assert(client._connected) - client.close() - protocol.stop() - assert(not client._connected) + from serial import Serial + with maybe_manage(sys.platform == 'darwin', patch.object(Serial, "open")): + protocol, future = AsyncModbusSerialClient(schedulers.IO_LOOP, method=method, port=SERIAL_PORT) + client = future.result() + assert(isinstance(client, AsyncTornadoModbusSerialClient)) + assert(0 == len(list(client.transaction))) + assert(isinstance(client.framer, framer)) + assert(client.port == SERIAL_PORT) + assert(client._connected) + + def handle_failure(failure): + assert(isinstance(failure.exception(), ConnectionException)) + + d = client._build_response(0x00) + d.add_done_callback(handle_failure) + + assert(client._connected) + client.close() + protocol.stop() + assert(not client._connected) @pytest.mark.skipif(IS_PYTHON3 , reason="requires python2.7") def testSerialAsyncioClientPython2(self): From 187ce00f3910aaaaf01b753bdf5f1bbf8c94f768 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 20 Jan 2021 15:16:24 -0500 Subject: [PATCH 43/60] a bit more --- test/test_server_asyncio.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_server_asyncio.py b/test/test_server_asyncio.py index 42cb67ad4..7a6d9924c 100755 --- a/test/test_server_asyncio.py +++ b/test/test_server_asyncio.py @@ -246,6 +246,9 @@ def connection_made(self, transport): transport, protocol = yield from self.loop.create_connection(BasicClient, host='127.0.0.1',port=random_port) yield from step1 + # On Windows we seem to need to give this an extra chance to finish, + # otherwise there ends up being an active connection at the assert. + yield from asyncio.sleep(0.0) server.server_close() # close isn't synchronous and there's no notification that it's done From 72532f2fa522d80f8b1305db79fe99b68bba4523 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 20 Jan 2021 15:44:35 -0500 Subject: [PATCH 44/60] always run coverage job --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df8e3506a..c154861b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -195,6 +195,7 @@ jobs: # Should match JOB_NAME below name: ${{ matrix.task.name }} - ${{ matrix.os.name }} ${{ matrix.python.name }} ${{ matrix.arch.name }} runs-on: ${{ matrix.os.runs-on }} + if: always() needs: - test container: ${{ matrix.os.container[matrix.python.docker] }} From 371dccb426bc5f7ca535522c3189375935ef6686 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 20 Jan 2021 15:51:09 -0500 Subject: [PATCH 45/60] remove pypy for now --- .github/workflows/ci.yml | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c154861b3..280a8004f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,8 +38,6 @@ jobs: 3.7: docker://python:3.7-buster 3.8: docker://python:3.8-buster 3.9: docker://python:3.9-buster - pypy2: docker://pypy:2-jessie - pypy3: docker://pypy:3-stretch # - name: Windows # runs-on: windows-latest # python_platform: win32 @@ -54,11 +52,6 @@ jobs: action: 2.7 docker: 2.7 implementation: cpython - - name: PyPy 2.7 - tox: pypy27 - action: pypy-2.7 - docker: pypy2.7 - implementation: pypy - name: CPython 3.6 tox: py36 action: 3.6 @@ -79,16 +72,6 @@ jobs: action: 3.9 docker: 3.9 implementation: cpython - - name: PyPy 3.6 - tox: pypy36 - action: pypy-3.6 - docker: pypy3.6 - implementation: pypy - - name: PyPy 3.7 - tox: pypy37 - action: pypy-3.7 - docker: pypy3.7 - implementation: pypy arch: - name: x86 action: x86 @@ -112,18 +95,12 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Set up ${{ matrix.python.name }} (if CPython) - if: ${{ job.container == '' && matrix.python.implementation == 'cpython'}} + - name: Set up ${{ matrix.python.name }} + if: ${{ job.container == ''}} uses: actions/setup-python@v2 with: python-version: '${{ matrix.python.action }}.0-alpha - ${{ matrix.python.action }}.X' architecture: '${{ matrix.arch.action }}' - - name: Set up ${{ matrix.python.name }} (if PyPy) - if: ${{ job.container == '' && matrix.python.implementation == 'pypy'}} - uses: actions/setup-python@v2 - with: - python-version: '${{ matrix.python.action }}' - architecture: '${{ matrix.arch.action }}' - name: Install run: | pip install --upgrade pip setuptools wheel From 964ae69f688c796f1a6863b203f47e62945b8a88 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 16 Feb 2021 16:34:40 -0500 Subject: [PATCH 46/60] Remove unused import pytest --- test/test_server_async.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_server_async.py b/test/test_server_async.py index f5a3b9cfd..4fe04add3 100644 --- a/test/test_server_async.py +++ b/test/test_server_async.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from pymodbus.compat import IS_PYTHON3 import unittest -import pytest if IS_PYTHON3: # Python 3 from unittest.mock import patch, Mock, MagicMock else: # Python 2 From 01d864d856cf0bcfb0ff7f3d492a60a61c1973c7 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 16 Feb 2021 16:44:37 -0500 Subject: [PATCH 47/60] No need to change tox.ini --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index a7176825c..d84c48458 100644 --- a/tox.ini +++ b/tox.ini @@ -10,7 +10,8 @@ envlist = py{27,py27,36,37,38,39,py36,py37} deps = -r requirements-tests.txt commands = pytest {posargs:--cov=pymodbus/ --cov-report=term-missing --cov-report=xml} -setenv = with_gmp=no +setenv = + with_gmp=no [testenv:flake8] deps = -r requirements-checks.txt From 3315340104a18c4adacc62825a6ae18b41e5049e Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 09:19:10 -0500 Subject: [PATCH 48/60] another @inet_pton_skipif --- test/test_client_sync.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_client_sync.py b/test/test_client_sync.py index 28b10c61e..d7c7f7be2 100755 --- a/test/test_client_sync.py +++ b/test/test_client_sync.py @@ -165,6 +165,7 @@ def settimeout(self, *a, **kwa): client = ModbusUdpClient() self.assertFalse(client.connect()) + @inet_pton_skipif def testUdpClientIsSocketOpen(self): ''' Test the udp client is_socket_open method''' client = ModbusUdpClient() From 76f69cdd9a62d0fca12cf0c27c4709a1fd0f4771 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 09:23:48 -0500 Subject: [PATCH 49/60] stop removing pypy --- .github/workflows/ci.yml | 32 +++++++++++++++++++++++++------- requirements-tests.txt | 2 +- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b721fab5..13d53e598 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,8 @@ jobs: 3.7: docker://python:3.7-buster 3.8: docker://python:3.8-buster 3.9: docker://python:3.9-buster + pypy2: docker://pypy:2-jessie + pypy3: docker://pypy:3-stretch - name: Windows runs-on: windows-latest python_platform: win32 @@ -58,6 +60,11 @@ jobs: docker: 2.7 matrix: 2.7 implementation: cpython + - name: PyPy 2.7 + tox: pypy27 + action: pypy-2.7 + docker: pypy2.7 + implementation: pypy - name: CPython 3.6 tox: py36 action: 3.6 @@ -82,6 +89,16 @@ jobs: docker: 3.9 matrix: 3.9 implementation: cpython + - name: PyPy 3.6 + tox: pypy36 + action: pypy-3.6 + docker: pypy3.6 + implementation: pypy + - name: PyPy 3.7 + tox: pypy37 + action: pypy-3.7 + docker: pypy3.7 + implementation: pypy arch: - name: x86 action: x86 @@ -98,11 +115,6 @@ jobs: matrix: macos arch: matrix: x86 - # Twisted doesn't support Python 3.9 on Windows as of 20.3.0 - - os: - matrix: windows - python: - matrix: 3.9 env: # Should match name above JOB_NAME: ${{ matrix.task.name }} - ${{ matrix.os.name }} ${{ matrix.python.name }} ${{ matrix.arch.name }} @@ -110,12 +122,18 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Set up ${{ matrix.python.name }} - if: ${{ job.container == ''}} + - name: Set up ${{ matrix.python.name }} (if CPython) + if: ${{ job.container == '' && matrix.python.implementation == 'cpython'}} uses: actions/setup-python@v2 with: python-version: '${{ matrix.python.action }}.0-alpha - ${{ matrix.python.action }}.X' architecture: '${{ matrix.arch.action }}' + - name: Set up ${{ matrix.python.name }} (if PyPy) + if: ${{ job.container == '' && matrix.python.implementation == 'pypy'}} + uses: actions/setup-python@v2 + with: + python-version: '${{ matrix.python.action }}' + architecture: '${{ matrix.arch.action }}' - name: Install run: | pip install --upgrade pip setuptools wheel diff --git a/requirements-tests.txt b/requirements-tests.txt index 8e42f5680..5cd4769e7 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -14,6 +14,6 @@ sqlalchemy>=1.1.15 #wsgiref>=0.1.2 verboselogs >= 1.5 tornado==4.5.3 -Twisted[conch,serial]>=20.3.0 +Twisted[conch,serial]>=21.2.0 zope.interface>=4.4.0 asynctest>=0.10.0 From 0020ebe4c266769514fedd7115aa40707bd95ad0 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 09:31:41 -0500 Subject: [PATCH 50/60] bring in the pypy fixes --- .github/workflows/ci.yml | 26 ++++++++++++++++++++++++++ requirements-tests.txt | 7 ++++++- setup.py | 7 ++++++- test/test_client_async.py | 4 ++++ test/test_server_async.py | 8 ++++++++ tox.ini | 3 +++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13d53e598..8399bfc34 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,9 @@ jobs: tox: pypy27 action: pypy-2.7 docker: pypy2.7 + matrix: 2.7 implementation: pypy + openssl_msvc_version: 2019 - name: CPython 3.6 tox: py36 action: 3.6 @@ -93,12 +95,16 @@ jobs: tox: pypy36 action: pypy-3.6 docker: pypy3.6 + matrix: 3.6 implementation: pypy + openssl_msvc_version: 2019 - name: PyPy 3.7 tox: pypy37 action: pypy-3.7 docker: pypy3.7 + matrix: 3.7 implementation: pypy + openssl_msvc_version: 2019 arch: - name: x86 action: x86 @@ -115,6 +121,12 @@ jobs: matrix: macos arch: matrix: x86 + - os: + matrix: windows + python: + implementation: pypy + arch: + matrix: x64 env: # Should match name above JOB_NAME: ${{ matrix.task.name }} - ${{ matrix.os.name }} ${{ matrix.python.name }} ${{ matrix.arch.name }} @@ -139,6 +151,20 @@ jobs: pip install --upgrade pip setuptools wheel pip install --upgrade tox requests urllib3 - uses: twisted/python-info-action@v1.0.1 + - name: Add PyPy Externals + if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} + env: + PYPY_EXTERNALS_PATH: ${{ github.workspace }}/pypy_externals + shell: bash + run: | + echo $PYPY_EXTERNALS_PATH + mkdir --parents $(dirname $PYPY_EXTERNALS_PATH) + hg clone https://foss.heptapod.net/pypy/externals/ $PYPY_EXTERNALS_PATH + dir $PYPY_EXTERNALS_PATH + cd $PYPY_EXTERNALS_PATH && hg update win32_14x + echo "INCLUDE=$PYPY_EXTERNALS_PATH/include;$INCLUDE" >> $GITHUB_ENV + echo "LIB=$PYPY_EXTERNALS_PATH/lib;$LIB" >> $GITHUB_ENV +# echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - name: Test run: | tox -vv -e ${{ matrix.python.tox }} diff --git a/requirements-tests.txt b/requirements-tests.txt index 5cd4769e7..1b700aea2 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -14,6 +14,11 @@ sqlalchemy>=1.1.15 #wsgiref>=0.1.2 verboselogs >= 1.5 tornado==4.5.3 -Twisted[conch,serial]>=21.2.0 +# using platform_python_implementation rather than +# implementation_name for Python 2 support +Twisted[conch,serial]>=21.2.0; platform_python_implementation == "CPython" or sys_platform != "win32" +# pywin32 isn't supported on pypy +# https://github.com/mhammond/pywin32/issues/1289 +Twisted[conch]>=21.2.0; platform_python_implementation == "PyPy" and sys_platform == "win32" zope.interface>=4.4.0 asynctest>=0.10.0 diff --git a/setup.py b/setup.py index 8d875f8b1..2019174e8 100644 --- a/setup.py +++ b/setup.py @@ -97,7 +97,12 @@ 'sphinx_rtd_theme', 'humanfriendly'], 'twisted': [ - 'Twisted[conch,serial] >= 20.3.0', + # using platform_python_implementation rather than + # implementation_name for Python 2 support + 'Twisted[conch,serial]>=21.2.0; platform_python_implementation == "CPython" or sys_platform != "win32"', + # pywin32 isn't supported on pypy + # https://github.com/mhammond/pywin32/issues/1289 + 'Twisted[conch]>=21.2.0; platform_python_implementation == "PyPy" and sys_platform == "win32"', ], 'tornado': [ 'tornado == 4.5.3' diff --git a/test/test_client_async.py b/test/test_client_async.py index 6664af977..95f36824c 100644 --- a/test/test_client_async.py +++ b/test/test_client_async.py @@ -191,6 +191,10 @@ def testUdpAsycioClient(self, mock_gather, mock_event_loop): # Test Serial client # -----------------------------------------------------------------------# + @pytest.mark.skipif( + sys.platform == 'win32' and platform.python_implementation() == 'PyPy', + reason='Twisted serial requires pywin32 which is not compatible with PyPy', + ) @pytest.mark.parametrize("method, framer", [("rtu", ModbusRtuFramer), ("socket", ModbusSocketFramer), ("binary", ModbusBinaryFramer), diff --git a/test/test_server_async.py b/test/test_server_async.py index 4fe04add3..d5a0ac113 100644 --- a/test/test_server_async.py +++ b/test/test_server_async.py @@ -32,6 +32,11 @@ IS_HIGH_SIERRA_OR_ABOVE = False SERIAL_PORT = "/dev/ptmx" +no_twisted_serial_on_windows_with_pypy = pytest.mark.skipif( + sys.platform == 'win32' and platform.python_implementation() == 'PyPy', + reason='Twisted serial requires pywin32 which is not compatible with PyPy', +) + class AsynchronousServerTest(unittest.TestCase): ''' @@ -188,6 +193,7 @@ def testUdpServerStartup(self): self.assertEqual(mock_reactor.listenUDP.call_count, 1) self.assertEqual(mock_reactor.run.call_count, 1) + @no_twisted_serial_on_windows_with_pypy @patch("twisted.internet.serialport.SerialPort") def testSerialServerStartup(self, mock_sp): ''' Test that the modbus serial asynchronous server starts correctly ''' @@ -195,6 +201,7 @@ def testSerialServerStartup(self, mock_sp): StartSerialServer(context=None, port=SERIAL_PORT) self.assertEqual(mock_reactor.run.call_count, 1) + @no_twisted_serial_on_windows_with_pypy @patch("twisted.internet.serialport.SerialPort") def testStopServerFromMainThread(self, mock_sp): """ @@ -207,6 +214,7 @@ def testStopServerFromMainThread(self, mock_sp): StopServer() self.assertEqual(mock_reactor.stop.call_count, 1) + @no_twisted_serial_on_windows_with_pypy @patch("twisted.internet.serialport.SerialPort") def testStopServerFromThread(self, mock_sp): """ diff --git a/tox.ini b/tox.ini index d84c48458..6aa51b229 100644 --- a/tox.ini +++ b/tox.ini @@ -10,6 +10,9 @@ envlist = py{27,py27,36,37,38,39,py36,py37} deps = -r requirements-tests.txt commands = pytest {posargs:--cov=pymodbus/ --cov-report=term-missing --cov-report=xml} +passenv = + INCLUDE + LIB setenv = with_gmp=no From 413e6d3932e1195d4f102eff97ae6f9d64213fc8 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 09:33:47 -0500 Subject: [PATCH 51/60] import pytest --- test/test_server_async.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_server_async.py b/test/test_server_async.py index d5a0ac113..c88f6e4db 100644 --- a/test/test_server_async.py +++ b/test/test_server_async.py @@ -1,6 +1,7 @@ #!/usr/bin/env python from pymodbus.compat import IS_PYTHON3 import unittest +import pytest if IS_PYTHON3: # Python 3 from unittest.mock import patch, Mock, MagicMock else: # Python 2 From 863ae82025c5f45df8e25bd2937adc55a68a0c3e Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 09:36:54 -0500 Subject: [PATCH 52/60] allow Twisted 20.3.0 for py2 support --- requirements-tests.txt | 4 ++-- setup.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements-tests.txt b/requirements-tests.txt index 1b700aea2..5e2a00825 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -16,9 +16,9 @@ verboselogs >= 1.5 tornado==4.5.3 # using platform_python_implementation rather than # implementation_name for Python 2 support -Twisted[conch,serial]>=21.2.0; platform_python_implementation == "CPython" or sys_platform != "win32" +Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" or sys_platform != "win32" # pywin32 isn't supported on pypy # https://github.com/mhammond/pywin32/issues/1289 -Twisted[conch]>=21.2.0; platform_python_implementation == "PyPy" and sys_platform == "win32" +Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" and sys_platform == "win32" zope.interface>=4.4.0 asynctest>=0.10.0 diff --git a/setup.py b/setup.py index 2019174e8..5fd2dd3fa 100644 --- a/setup.py +++ b/setup.py @@ -99,10 +99,10 @@ 'twisted': [ # using platform_python_implementation rather than # implementation_name for Python 2 support - 'Twisted[conch,serial]>=21.2.0; platform_python_implementation == "CPython" or sys_platform != "win32"', + 'Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" or sys_platform != "win32"', # pywin32 isn't supported on pypy # https://github.com/mhammond/pywin32/issues/1289 - 'Twisted[conch]>=21.2.0; platform_python_implementation == "PyPy" and sys_platform == "win32"', + 'Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" and sys_platform == "win32"', ], 'tornado': [ 'tornado == 4.5.3' From b8e43c5a6c6fb8f09473941a294542ce7f6bf6b2 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 09:51:11 -0500 Subject: [PATCH 53/60] rustup --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8399bfc34..1530df34d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,6 +165,11 @@ jobs: echo "INCLUDE=$PYPY_EXTERNALS_PATH/include;$INCLUDE" >> $GITHUB_ENV echo "LIB=$PYPY_EXTERNALS_PATH/lib;$LIB" >> $GITHUB_ENV # echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV + - name: rustup + if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} + shell: bash + run: | + rustup target add i686-pc-windows-msvc - name: Test run: | tox -vv -e ${{ matrix.python.tox }} From e28deac2e8fc1f83b3481a152f96b6fc31196bb9 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 10:15:40 -0500 Subject: [PATCH 54/60] PIP_NO_CLEAN 1 --- .github/workflows/ci.yml | 4 ++++ tox.ini | 1 + 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1530df34d..e80e6fb03 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -171,6 +171,10 @@ jobs: run: | rustup target add i686-pc-windows-msvc - name: Test + env: + # When compiling Cryptography for PyPy on Windows there is a cleanup + # failure. This is CI, it doesn't matter. + PIP_NO_CLEAN: 1 run: | tox -vv -e ${{ matrix.python.tox }} - name: Coverage Processing diff --git a/tox.ini b/tox.ini index 6aa51b229..ccd8544ce 100644 --- a/tox.ini +++ b/tox.ini @@ -13,6 +13,7 @@ commands = passenv = INCLUDE LIB + PIP_* setenv = with_gmp=no From f2ce1398b63f5861cf672f8e1fae30c1a6796531 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 10:36:27 -0500 Subject: [PATCH 55/60] tidy --- .github/workflows/ci.yml | 2 +- requirements-tests.txt | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e80e6fb03..2fec02f80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -149,7 +149,7 @@ jobs: - name: Install run: | pip install --upgrade pip setuptools wheel - pip install --upgrade tox requests urllib3 + pip install --upgrade tox - uses: twisted/python-info-action@v1.0.1 - name: Add PyPy Externals if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} diff --git a/requirements-tests.txt b/requirements-tests.txt index 5e2a00825..ad0d59022 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -16,7 +16,7 @@ verboselogs >= 1.5 tornado==4.5.3 # using platform_python_implementation rather than # implementation_name for Python 2 support -Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" or sys_platform != "win32" +Twisted[conch,serial]>=20.3.0; platform_python_implementation != "PyPy" or sys_platform != "win32" # pywin32 isn't supported on pypy # https://github.com/mhammond/pywin32/issues/1289 Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" and sys_platform == "win32" diff --git a/setup.py b/setup.py index 5fd2dd3fa..89c16326a 100644 --- a/setup.py +++ b/setup.py @@ -99,7 +99,7 @@ 'twisted': [ # using platform_python_implementation rather than # implementation_name for Python 2 support - 'Twisted[conch,serial]>=20.3.0; platform_python_implementation == "CPython" or sys_platform != "win32"', + 'Twisted[conch,serial]>=20.3.0; platform_python_implementation != "PyPy" or sys_platform != "win32"', # pywin32 isn't supported on pypy # https://github.com/mhammond/pywin32/issues/1289 'Twisted[conch]>=20.3.0; platform_python_implementation == "PyPy" and sys_platform == "win32"', From 2440e7845cabe7c4646dc4b13751abfe3943b4ad Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 13:24:54 -0500 Subject: [PATCH 56/60] more catchup --- .github/workflows/ci.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d818a2d0..ba546ab77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,12 +134,18 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Set up ${{ matrix.python.name }} - if: ${{ job.container == ''}} + - name: Set up ${{ matrix.python.name }} (if CPython) + if: ${{ job.container == '' && matrix.python.implementation == 'cpython'}} uses: actions/setup-python@v2 with: python-version: '${{ matrix.python.action }}.0-alpha - ${{ matrix.python.action }}.X' architecture: '${{ matrix.arch.action }}' + - name: Set up ${{ matrix.python.name }} (if PyPy) + if: ${{ job.container == '' && matrix.python.implementation == 'pypy'}} + uses: actions/setup-python@v2 + with: + python-version: '${{ matrix.python.action }}' + architecture: '${{ matrix.arch.action }}' - name: Install run: | pip install --upgrade pip setuptools wheel From 4eabfac358a29e1e173a2bd607ca4935224a6fa4 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 13:57:30 -0500 Subject: [PATCH 57/60] use brew to get openssl and rust for cryptography build --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba546ab77..c193a2051 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -165,6 +165,13 @@ jobs: echo "INCLUDE=$PYPY_EXTERNALS_PATH/include;$INCLUDE" >> $GITHUB_ENV echo "LIB=$PYPY_EXTERNALS_PATH/lib;$LIB" >> $GITHUB_ENV # echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV + - name: Add Brew + if: ${{ matrix.os.matrix == 'darwin' && matrix.python.implementation == 'pypy'}} + shell: bash + run: | + brew install openssl@1.1 rust + echo "LDFLAGS=-L$(brew --prefix openssl@1.1)/lib" >> $GITHUB_ENV + echo "CFLAGS=-I$(brew --prefix openssl@1.1)/include" >> $GITHUB_ENV - name: rustup if: ${{ matrix.os.matrix == 'windows' && matrix.python.implementation == 'pypy'}} shell: bash From 50591b854f33204138d9e2129b0c0463db04ae8e Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 14:04:03 -0500 Subject: [PATCH 58/60] it is macos --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c193a2051..dec7570b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,7 +166,7 @@ jobs: echo "LIB=$PYPY_EXTERNALS_PATH/lib;$LIB" >> $GITHUB_ENV # echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV - name: Add Brew - if: ${{ matrix.os.matrix == 'darwin' && matrix.python.implementation == 'pypy'}} + if: ${{ matrix.os.matrix == 'macos' && matrix.python.implementation == 'pypy'}} shell: bash run: | brew install openssl@1.1 rust From 136e381a053ddc3bba41d475dbb408edd472078a Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 14:07:08 -0500 Subject: [PATCH 59/60] alphabetical os order --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dec7570b3..71c50e900 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,10 @@ jobs: 3.9: docker://python:3.9-buster pypy2: docker://pypy:2-jessie pypy3: docker://pypy:3-stretch + - name: macOS + runs-on: macos-latest + python_platform: darwin + matrix: macos - name: Windows runs-on: windows-latest python_platform: win32 @@ -49,10 +53,6 @@ jobs: openssl: x86: win32 x64: win64 - - name: macOS - runs-on: macos-latest - python_platform: darwin - matrix: macos python: - name: CPython 2.7 tox: py27 From acaffa830fe8703c9eeea1be2a83f3f92cb98893 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 3 Mar 2021 14:08:04 -0500 Subject: [PATCH 60/60] remove python_platform from matrix variables --- .github/workflows/ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71c50e900..3b35144d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,6 @@ jobs: os: - name: Linux runs-on: ubuntu-latest - python_platform: linux matrix: linux container: 2.7: docker://python:2.7-buster @@ -44,11 +43,9 @@ jobs: pypy3: docker://pypy:3-stretch - name: macOS runs-on: macos-latest - python_platform: darwin matrix: macos - name: Windows runs-on: windows-latest - python_platform: win32 matrix: windows openssl: x86: win32 @@ -213,7 +210,6 @@ jobs: os: - name: Linux runs-on: ubuntu-latest - python_platform: linux matrix: linux container: 3.8: docker://python:3.8-buster @@ -261,7 +257,6 @@ jobs: os: - name: Linux runs-on: ubuntu-latest - python_platform: linux matrix: linux container: 3.8: docker://python:3.8-buster