Skip to content

Commit 2d6e9eb

Browse files
authored
Add typing to examples. (#2435)
1 parent ea1b219 commit 2d6e9eb

22 files changed

+68
-34
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ jobs:
105105
- name: mypy
106106
if: matrix.run_lint == true
107107
run: |
108-
mypy pymodbus
108+
mypy pymodbus examples
109109
110110
- name: ruff
111111
if: matrix.run_lint == true

check_ci.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
88
codespell
99
ruff check --fix --exit-non-zero-on-fix .
1010
pylint --recursive=y examples pymodbus test
11-
mypy pymodbus
11+
mypy pymodbus examples
1212
pytest -x --cov --numprocesses auto
1313
echo "Ready to push"

examples/client_async.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@
2626
The corresponding server must be started before e.g. as:
2727
python3 server_sync.py
2828
"""
29+
from __future__ import annotations
30+
2931
import asyncio
3032
import logging
3133
import sys
3234

3335

3436
try:
35-
import helper
37+
from examples import helper
3638
except ImportError:
3739
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
3840
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\
@@ -52,7 +54,7 @@ def setup_async_client(description=None, cmdline=None):
5254
server=False, description=description, cmdline=cmdline
5355
)
5456
_logger.info("### Create client object")
55-
client = None
57+
client: modbusClient.ModbusBaseClient | None = None
5658
if args.comm == "tcp":
5759
client = modbusClient.AsyncModbusTcpClient(
5860
args.host,

examples/client_async_calls.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939

4040
try:
41-
import client_async
41+
from examples import client_async
4242
except ImportError:
4343
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
4444
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\
@@ -157,6 +157,20 @@ async def async_handle_holding_registers(client):
157157
assert not rr.isError() # test that call was OK
158158
assert rr.registers == arguments["values"]
159159

160+
async def async_write_registers_mypy(client):
161+
"""Read/write holding registers."""
162+
regs1: list[int] = [10] * 8
163+
await client.write_registers(1, regs1, slave=SLAVE)
164+
rr = await client.read_holding_registers(1, len(regs1), slave=SLAVE)
165+
assert not rr.isError() # test that call was OK
166+
assert rr.registers == regs1
167+
168+
regs2: list[bytes] = [b'\x01\x02', b'\x03\x04']
169+
await client.write_registers(1, regs2, slave=SLAVE)
170+
rr = await client.read_holding_registers(1, len(regs2), slave=SLAVE)
171+
assert not rr.isError() # test that call was OK
172+
assert rr.registers == regs2
173+
160174

161175
async def async_handle_input_registers(client):
162176
"""Read input registers."""
@@ -258,6 +272,7 @@ async def run_async_calls(client):
258272
await async_handle_coils(client)
259273
await async_handle_discrete_input(client)
260274
await async_handle_holding_registers(client)
275+
await async_write_registers_mypy(client)
261276
await async_handle_input_registers(client)
262277
await async_handle_file_records(client)
263278
await async_execute_information_requests(client)

examples/client_calls.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737

3838
try:
39-
import client_sync
39+
from examples import client_sync
4040
except ImportError:
4141
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
4242
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\

examples/client_custom_msg.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,13 @@ async def main(host="localhost", port=5020):
127127
# new modbus function code.
128128
client.register(CustomModbusPDU)
129129
slave=1
130-
request = CustomRequest(32, slave=slave)
131-
result = await client.execute(False, request)
130+
request1 = CustomRequest(32, slave=slave)
131+
result = await client.execute(False, request1)
132132
print(result)
133133

134134
# inherited request
135-
request = Read16CoilsRequest(32, slave)
136-
result = await client.execute(False, request)
135+
request2 = Read16CoilsRequest(32, slave)
136+
result = await client.execute(False, request2)
137137
print(result)
138138

139139

examples/client_payload.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414
try:
15-
import client_async
15+
from examples import client_async
1616
except ImportError:
1717
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
1818
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\
@@ -64,7 +64,7 @@ async def run_payload_calls(client):
6464
# Normally just do: builder = BinaryPayloadBuilder()
6565
my_string = "abcdefgh"
6666
builder.add_string(my_string)
67-
builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0])
67+
builder.add_bits([False, True, False, True, True, False, True, False])
6868
builder.add_8bit_int(-0x12)
6969
builder.add_8bit_uint(0x12)
7070
builder.add_16bit_int(-0x5678)

examples/client_sync.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@
3030
python3 server_sync.py
3131
3232
"""
33+
from __future__ import annotations
34+
3335
import logging
3436
import sys
3537

3638

3739
try:
38-
import helper
40+
from examples import helper
3941
except ImportError:
4042
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
4143
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\
@@ -58,7 +60,7 @@ def setup_sync_client(description=None, cmdline=None):
5860
cmdline=cmdline,
5961
)
6062
_logger.info("### Create client object")
61-
client = None
63+
client: modbusClient.ModbusBaseSyncClient | None = None
6264
if args.comm == "tcp":
6365
client = modbusClient.ModbusTcpClient(
6466
args.host,

examples/helper.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
code that are not relevant for the code as such, like e.g.
55
get_command_line
66
"""
7+
from __future__ import annotations
8+
79
import argparse
810
import logging
911
import os
@@ -95,7 +97,7 @@ def get_commandline(server=False, description=None, extras=None, cmdline=None):
9597
args = parser.parse_args(cmdline)
9698

9799
# set defaults
98-
comm_defaults = {
100+
comm_defaults: dict[str, list[int | str]] = {
99101
"tcp": ["socket", 5020],
100102
"udp": ["socket", 5020],
101103
"serial": ["rtu", "/dev/ptyp0"],

examples/message_parser.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def decode(self, message):
7070
"""Attempt to decode the supplied message."""
7171
value = message if self.encode else c.encode(message, "hex_codec")
7272
print("=" * 80)
73-
print(f"Decoding Message {value}")
73+
print(f"Decoding Message {value!r}")
7474
print("=" * 80)
7575
decoders = [
7676
self.framer(DecodePDU(True)),

examples/modbus_forwarder.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
1717
**WARNING** This example is a simple solution, that do only forward read requests.
1818
"""
19+
from __future__ import annotations
20+
1921
import asyncio
2022
import logging
2123
import sys
2224

2325

2426
try:
25-
import helper
27+
from examples import helper
2628
except ImportError:
2729
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
2830
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\
@@ -58,6 +60,7 @@ async def run_forwarder(args):
5860
# in RemoteSlaveContext
5961
# For e.g to forward the requests to slave with slave address 1 use
6062
# store = RemoteSlaveContext(client, slave=1)
63+
store: dict | RemoteSlaveContext
6164
if args.slaves:
6265
store = {}
6366
for i in args.slaves:

examples/package_test_tool.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def __init__(
6767
self,
6868
params: CommParams,
6969
is_server: bool,
70-
handler: Callable[[bytes], bytes],
70+
handler: Callable[[ModbusProtocol, bool, bytes], None],
7171
) -> None:
7272
"""Initialize a stub instance."""
7373
self.stub_handle_data = handler
@@ -109,7 +109,7 @@ def __init__(self, comm: CommType):
109109
global test_port # pylint: disable=global-statement
110110
self.comm = comm
111111
host = NULLMODEM_HOST
112-
112+
self.client: modbusClient.AsyncModbusTcpClient | modbusClient.AsyncModbusSerialClient
113113
if comm == CommType.TCP:
114114
self.client = modbusClient.AsyncModbusTcpClient(
115115
host,
@@ -157,6 +157,7 @@ def __init__(self, comm: CommType):
157157
self.identity = ModbusDeviceIdentification(
158158
info_name={"VendorName": "VendorName"}
159159
)
160+
self.server: modbusServer.ModbusTcpServer | modbusServer.ModbusSerialServer
160161
if comm == CommType.TCP:
161162
self.server = modbusServer.ModbusTcpServer(
162163
self.context,
@@ -174,8 +175,9 @@ def __init__(self, comm: CommType):
174175
else:
175176
raise RuntimeError("ERROR: CommType not implemented")
176177
client_params = self.server.comm_params.copy()
177-
client_params.host = client_params.source_address[0]
178-
client_params.port = client_params.source_address[1]
178+
if client_params.source_address:
179+
client_params.host = client_params.source_address[0]
180+
client_params.port = client_params.source_address[1]
179181
client_params.timeout_connect = 1.0
180182
self.stub = TransportStub(client_params, False, simulate_client)
181183
test_port += 1
@@ -194,6 +196,7 @@ async def run(self):
194196

195197
async def main(comm: CommType, use_server: bool):
196198
"""Combine setup and run."""
199+
test: ServerTester | ClientTester
197200
if use_server:
198201
test = ServerTester(comm)
199202
else:

examples/server_async.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@
3535
import asyncio
3636
import logging
3737
import sys
38+
from collections.abc import Callable
39+
from typing import Any
3840

3941

4042
try:
41-
import helper
43+
from examples import helper
4244
except ImportError:
4345
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
4446
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\
@@ -70,7 +72,7 @@ def setup_server(description=None, context=None, cmdline=None):
7072
args = helper.get_commandline(server=True, description=description, cmdline=cmdline)
7173
if context:
7274
args.context = context
73-
datablock = None
75+
datablock: Callable[[], Any]
7476
if not args.context:
7577
_logger.info("### Create datastore")
7678
# The datastores only respond to the addresses that are initialized

examples/server_callback.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
try:
13-
import server_async
13+
from examples import server_async
1414
except ImportError:
1515
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
1616
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\
@@ -62,7 +62,7 @@ def validate(self, address, count=1):
6262

6363
async def run_callback_server(cmdline=None):
6464
"""Define datastore callback for server and do setup."""
65-
queue = asyncio.Queue()
65+
queue: asyncio.Queue = asyncio.Queue()
6666
block = CallbackDataBlock(queue, 0x00, [17] * 100)
6767
block.setValues(1, 15)
6868
store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)

examples/server_hook.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
This is an example of using the builtin request/response tracer to
55
manipulate the messages to/from the modbus server
66
"""
7+
from __future__ import annotations
8+
79
import asyncio
810
import logging
911

@@ -20,7 +22,7 @@ class Manipulator:
2022
"""A Class to run the server."""
2123

2224
message_count: int = 1
23-
server: ModbusTcpServer = None
25+
server: ModbusTcpServer
2426

2527
def server_request_tracer(self, request, *_addr):
2628
"""Trace requests.

examples/server_payload.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
try:
13-
import server_async
13+
from examples import server_async
1414
except ImportError:
1515
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
1616
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\
@@ -37,7 +37,7 @@ def setup_payload_server(cmdline=None):
3737
# ----------------------------------------------------------------------- #
3838
builder = BinaryPayloadBuilder(byteorder=Endian.LITTLE, wordorder=Endian.LITTLE)
3939
builder.add_string("abcdefgh")
40-
builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0])
40+
builder.add_bits([False, True, False, True, True, False, True, False])
4141
builder.add_8bit_int(-0x12)
4242
builder.add_8bit_uint(0x12)
4343
builder.add_16bit_int(-0x5678)

examples/server_sync.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@
3939

4040

4141
try:
42-
import helper
43-
import server_async
42+
from examples import helper, server_async
4443
except ImportError:
4544
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
4645
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\

examples/server_updating.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838

3939
try:
40-
import server_async
40+
from examples import server_async
4141
except ImportError:
4242
print("*** ERROR --> THIS EXAMPLE needs the example directory, please see \n\
4343
https://pymodbus.readthedocs.io/en/latest/source/examples.html\n\
@@ -101,8 +101,8 @@ def setup_updating_server(cmdline=None):
101101

102102
# Continuing, use a sequential block without gaps.
103103
datablock = ModbusSequentialDataBlock(0x00, [17] * 100)
104-
context = ModbusSlaveContext(di=datablock, co=datablock, hr=datablock, ir=datablock)
105-
context = ModbusServerContext(slaves=context, single=True)
104+
slavecontext = ModbusSlaveContext(di=datablock, co=datablock, hr=datablock, ir=datablock)
105+
context = ModbusServerContext(slaves=slavecontext, single=True)
106106
return server_async.setup_server(
107107
description="Run asynchronous server.", context=context, cmdline=cmdline
108108
)

examples/simple_async_client.py

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ async def run_async_simple_client(comm, host, port, framer=FramerType.SOCKET):
2626
pymodbus_apply_logging_config("DEBUG")
2727

2828
print("get client")
29+
client: ModbusClient.ModbusBaseClient
2930
if comm == "tcp":
3031
client = ModbusClient.AsyncModbusTcpClient(
3132
host,

examples/simple_sync_client.py

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def run_sync_simple_client(comm, host, port, framer=FramerType.SOCKET):
2828
pymodbus_apply_logging_config("DEBUG")
2929

3030
print("get client")
31+
client: ModbusClient.ModbusBaseSyncClient
3132
if comm == "tcp":
3233
client = ModbusClient.ModbusTcpClient(
3334
host,

pymodbus/client/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
"AsyncModbusTlsClient",
77
"AsyncModbusUdpClient",
88
"ModbusBaseClient",
9+
"ModbusBaseSyncClient",
910
"ModbusSerialClient",
1011
"ModbusTcpClient",
1112
"ModbusTlsClient",
1213
"ModbusUdpClient",
1314
]
1415

15-
from pymodbus.client.base import ModbusBaseClient
16+
from pymodbus.client.base import ModbusBaseClient, ModbusBaseSyncClient
1617
from pymodbus.client.serial import AsyncModbusSerialClient, ModbusSerialClient
1718
from pymodbus.client.tcp import AsyncModbusTcpClient, ModbusTcpClient
1819
from pymodbus.client.tls import AsyncModbusTlsClient, ModbusTlsClient

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ overgeneral-exceptions = "builtins.Exception"
186186
bad-functions = "map,input"
187187

188188
[tool.mypy]
189+
exclude = '/contrib/'
189190
strict_optional = true
190191
show_error_codes = true
191192
local_partial_types = true

0 commit comments

Comments
 (0)