Skip to content

Commit b3bd579

Browse files
committed
Add more typing to transaction and base client
1 parent 978ad88 commit b3bd579

File tree

3 files changed

+30
-29
lines changed

3 files changed

+30
-29
lines changed

pymodbus/client/base.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
import asyncio
55
import socket
66
from abc import abstractmethod
7-
from collections.abc import Awaitable, Callable
7+
from collections.abc import Callable, Coroutine
88
from dataclasses import dataclass
9-
from typing import Any, cast
9+
from typing import Any, Union, cast
1010

1111
from pymodbus.client.mixin import ModbusClientMixin
1212
from pymodbus.client.modbusclientprotocol import ModbusClientProtocol
@@ -20,7 +20,7 @@
2020
from pymodbus.utilities import ModbusTransactionState
2121

2222

23-
class ModbusBaseClient(ModbusClientMixin[Awaitable[ModbusResponse]]):
23+
class ModbusBaseClient(ModbusClientMixin[Coroutine[Any, Any, Union[ModbusResponse, None]]]):
2424
"""**ModbusBaseClient**.
2525
2626
Fixed parameters:
@@ -144,7 +144,7 @@ def idle_time(self) -> float:
144144
return 0
145145
return self.last_frame_end + self.silent_interval
146146

147-
def execute(self, request: ModbusRequest):
147+
def execute(self, request: ModbusRequest) -> Coroutine[Any, Any, ModbusResponse | None]:
148148
"""Execute request and get response (call **sync/async**).
149149
150150
:param request: The request to process
@@ -158,7 +158,7 @@ def execute(self, request: ModbusRequest):
158158
# ----------------------------------------------------------------------- #
159159
# Merged client methods
160160
# ----------------------------------------------------------------------- #
161-
async def async_execute(self, request) -> ModbusResponse:
161+
async def async_execute(self, request) -> ModbusResponse | None:
162162
"""Execute requests asynchronously."""
163163
request.transaction_id = self.ctx.transaction.getNextTID()
164164
packet = self.ctx.framer.buildPacket(request)
@@ -186,9 +186,9 @@ async def async_execute(self, request) -> ModbusResponse:
186186
f"ERROR: No response received after {self.retries} retries"
187187
)
188188

189-
return resp # type: ignore[return-value]
189+
return resp
190190

191-
def build_response(self, request: ModbusRequest):
191+
def build_response(self, request: ModbusRequest) -> asyncio.Future[ModbusResponse]:
192192
"""Return a deferred response for the current request."""
193193
my_future: asyncio.Future = asyncio.Future()
194194
request.fut = my_future
@@ -225,7 +225,7 @@ def __str__(self):
225225
)
226226

227227

228-
class ModbusBaseSyncClient(ModbusClientMixin[ModbusResponse]):
228+
class ModbusBaseSyncClient(ModbusClientMixin[Union[ModbusResponse, bytes, ModbusIOException]]):
229229
"""**ModbusBaseClient**.
230230
231231
Fixed parameters:
@@ -279,7 +279,7 @@ def __init__( # pylint: disable=too-many-arguments
279279
**kwargs: Any,
280280
) -> None:
281281
"""Initialize a client instance."""
282-
ModbusClientMixin.__init__(self) # type: ignore[arg-type]
282+
ModbusClientMixin.__init__(self) # type: ignore[arg-type] # pylint: disable=non-parent-init-called
283283
self.comm_params = CommParams(
284284
comm_type=comm_type,
285285
comm_name="comm",
@@ -346,7 +346,7 @@ def idle_time(self) -> float:
346346
return 0
347347
return self.last_frame_end + self.silent_interval
348348

349-
def execute(self, request: ModbusRequest) -> ModbusResponse:
349+
def execute(self, request: ModbusRequest) -> ModbusResponse | bytes | ModbusIOException:
350350
"""Execute request and get response (call **sync/async**).
351351
352352
:param request: The request to process

pymodbus/framer/old_framer_base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def sendPacket(self, message: bytes):
8080
"""
8181
return self.client.send(message)
8282

83-
def recvPacket(self, size: int) -> bytes:
83+
def recvPacket(self, size: int | None) -> bytes:
8484
"""Receive packet from the bus.
8585
8686
With specified len

pymodbus/transaction.py

+19-18
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
ModbusTlsFramer,
3030
)
3131
from pymodbus.logging import Log
32-
from pymodbus.pdu import ModbusRequest
32+
from pymodbus.pdu import ModbusRequest, ModbusResponse
3333
from pymodbus.transport import CommType
3434
from pymodbus.utilities import ModbusTransactionState, hexlify_packets
3535

@@ -167,13 +167,13 @@ def _set_adu_size(self):
167167
else:
168168
self.base_adu_size = -1
169169

170-
def _calculate_response_length(self, expected_pdu_size):
170+
def _calculate_response_length(self, expected_pdu_size: int) -> int | None:
171171
"""Calculate response length."""
172172
if self.base_adu_size == -1:
173173
return None
174174
return self.base_adu_size + expected_pdu_size
175175

176-
def _calculate_exception_length(self):
176+
def _calculate_exception_length(self) -> int | None:
177177
"""Return the length of the Modbus Exception Response according to the type of Framer."""
178178
if isinstance(self.client.framer, (ModbusSocketFramer, ModbusTlsFramer)):
179179
return self.base_adu_size + 2 # Fcode(1), ExceptionCode(1)
@@ -183,7 +183,9 @@ def _calculate_exception_length(self):
183183
return self.base_adu_size + 2 # Fcode(1), ExceptionCode(1)
184184
return None
185185

186-
def _validate_response(self, request: ModbusRequest, response, exp_resp_len, is_udp=False):
186+
def _validate_response(
187+
self, request: ModbusRequest, response: bytes | int, exp_resp_len: int | None, is_udp=False
188+
) -> bool:
187189
"""Validate Incoming response against request.
188190
189191
:param request: Request sent
@@ -208,7 +210,7 @@ def _validate_response(self, request: ModbusRequest, response, exp_resp_len, is_
208210
return mbap.get("length") == exp_resp_len
209211
return True
210212

211-
def execute(self, request: ModbusRequest): # noqa: C901
213+
def execute(self, request: ModbusRequest) -> ModbusResponse | bytes | ModbusIOException: # noqa: C901
212214
"""Start the producer to send the next request to consumer.write(Frame(request))."""
213215
with self._transaction_lock:
214216
try:
@@ -333,7 +335,9 @@ def execute(self, request: ModbusRequest): # noqa: C901
333335
self.client.close()
334336
return exc
335337

336-
def _retry_transaction(self, retries, reason, packet, response_length, full=False):
338+
def _retry_transaction(
339+
self, retries: int, reason: str, request: ModbusRequest, response_length: int | None, full=False
340+
) -> tuple[bytes, str | Exception | None]:
337341
"""Retry transaction."""
338342
Log.debug("Retry on {} response - {}", reason, retries)
339343
Log.debug('Changing transaction state from "WAITING_FOR_REPLY" to "RETRYING"')
@@ -350,9 +354,11 @@ def _retry_transaction(self, retries, reason, packet, response_length, full=Fals
350354
if response_length == in_waiting:
351355
result = self._recv(response_length, full)
352356
return result, None
353-
return self._transact(packet, response_length, full=full)
357+
return self._transact(request, response_length, full=full)
354358

355-
def _transact(self, request: ModbusRequest, response_length, full=False, broadcast=False):
359+
def _transact(
360+
self, request: ModbusRequest, response_length: int | None, full=False, broadcast=False
361+
) -> tuple[bytes, str | Exception | None]:
356362
"""Do a Write and Read transaction.
357363
358364
:param packet: packet to be sent
@@ -368,16 +374,12 @@ def _transact(self, request: ModbusRequest, response_length, full=False, broadca
368374
packet = self.client.framer.buildPacket(request)
369375
Log.debug("SEND: {}", packet, ":hex")
370376
size = self._send(packet)
371-
if (
372-
isinstance(size, bytes)
373-
and self.client.state == ModbusTransactionState.RETRYING
374-
):
377+
if size and self.client.state == ModbusTransactionState.RETRYING:
375378
Log.debug(
376379
"Changing transaction state from "
377380
'"RETRYING" to "PROCESSING REPLY"'
378381
)
379382
self.client.state = ModbusTransactionState.PROCESSING_REPLY
380-
return size, None
381383
if self.client.comm_params.handle_local_echo is True:
382384
if self._recv(size, full) != packet:
383385
return b"", "Wrong local echo"
@@ -405,23 +407,22 @@ def _transact(self, request: ModbusRequest, response_length, full=False, broadca
405407
result = b""
406408
return result, last_exception
407409

408-
def _send(self, packet: bytes, _retrying=False):
410+
def _send(self, packet: bytes, _retrying=False) -> int:
409411
"""Send."""
410412
return self.client.framer.sendPacket(packet)
411413

412-
def _recv(self, expected_response_length, full) -> bytes: # noqa: C901
414+
def _recv(self, expected_response_length: int | None, full: bool) -> bytes: # noqa: C901
413415
"""Receive."""
414416
total = None
415417
if not full:
416418
exception_length = self._calculate_exception_length()
419+
min_size = expected_response_length
417420
if isinstance(self.client.framer, ModbusSocketFramer):
418421
min_size = 8
419422
elif isinstance(self.client.framer, ModbusRtuFramer):
420423
min_size = 4
421424
elif isinstance(self.client.framer, ModbusAsciiFramer):
422425
min_size = 5
423-
else:
424-
min_size = expected_response_length
425426

426427
read_min = self.client.framer.recvPacket(min_size)
427428
if len(read_min) != min_size:
@@ -462,7 +463,7 @@ def _recv(self, expected_response_length, full) -> bytes: # noqa: C901
462463
if expected_response_length is not None:
463464
expected_response_length -= min_size
464465
total = expected_response_length + min_size
465-
else:
466+
if func_code >= 0x80 and exception_length:
466467
expected_response_length = exception_length - min_size
467468
total = expected_response_length + min_size
468469
else:

0 commit comments

Comments
 (0)