Skip to content

Commit 02dbad2

Browse files
committed
DictTransactionManager -> ModbusTransactionManager
1 parent c0a782d commit 02dbad2

File tree

2 files changed

+47
-95
lines changed

2 files changed

+47
-95
lines changed

pymodbus/transaction.py

Lines changed: 22 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from pymodbus.exceptions import (
2020
InvalidMessageReceivedException,
2121
ModbusIOException,
22-
NotImplementedException,
2322
)
2423
from pymodbus.framer.ascii_framer import ModbusAsciiFramer
2524
from pymodbus.framer.binary_framer import ModbusBinaryFramer
@@ -47,6 +46,8 @@ class ModbusTransactionManager:
4746
while (count < 3)
4847
4948
This module helps to abstract this away from the framer and protocol.
49+
50+
Results are keyed based on the supplied transaction id.
5051
"""
5152

5253
def __init__(self, client, **kwargs):
@@ -62,11 +63,19 @@ def __init__(self, client, **kwargs):
6263
self.retry_on_empty = kwargs.get("retry_on_empty", False)
6364
self.retry_on_invalid = kwargs.get("retry_on_invalid", False)
6465
self.retries = kwargs.get("retries", 3)
66+
self.transactions = {}
6567
self._transaction_lock = RLock()
6668
self._no_response_devices = []
6769
if client:
6870
self._set_adu_size()
6971

72+
def __iter__(self):
73+
"""Iterate over the current managed transactions.
74+
75+
:returns: An iterator of the managed transactions
76+
"""
77+
return iter(self.transactions.keys())
78+
7079
def _set_adu_size(self):
7180
"""Set adu size."""
7281
# base ADU size of modbus frame in bytes
@@ -422,27 +431,33 @@ def addTransaction(self, request, tid=None):
422431
423432
:param request: The request to hold on to
424433
:param tid: The overloaded transaction id to use
425-
:raises NotImplementedException:
426434
"""
427-
raise NotImplementedException("addTransaction")
435+
tid = tid if tid is not None else request.transaction_id
436+
Log.debug("Adding transaction {}", tid)
437+
self.transactions[tid] = request
428438

429439
def getTransaction(self, tid):
430440
"""Return a transaction matching the referenced tid.
431441
432442
If the transaction does not exist, None is returned
433443
434444
:param tid: The transaction to retrieve
435-
:raises NotImplementedException:
445+
436446
"""
437-
raise NotImplementedException("getTransaction")
447+
Log.debug("Getting transaction {}", tid)
448+
if not tid:
449+
if self.transactions:
450+
return self.transactions.popitem()[1]
451+
return None
452+
return self.transactions.pop(tid, None)
438453

439454
def delTransaction(self, tid):
440455
"""Remove a transaction matching the referenced tid.
441456
442457
:param tid: The transaction to remove
443-
:raises NotImplementedException:
444458
"""
445-
raise NotImplementedException("delTransaction")
459+
Log.debug("deleting transaction {}", tid)
460+
self.transactions.pop(tid, None)
446461

447462
def getNextTID(self):
448463
"""Retrieve the next unique transaction identifier.
@@ -461,61 +476,3 @@ def reset(self):
461476
self.transactions = type( # pylint: disable=attribute-defined-outside-init
462477
self.transactions
463478
)()
464-
465-
466-
class DictTransactionManager(ModbusTransactionManager):
467-
"""Implements a transaction for a manager.
468-
469-
Where the results are keyed based on the supplied transaction id.
470-
"""
471-
472-
def __init__(self, client, **kwargs):
473-
"""Initialize an instance of the ModbusTransactionManager.
474-
475-
:param client: The client socket wrapper
476-
"""
477-
self.transactions = {}
478-
super().__init__(client, **kwargs)
479-
480-
def __iter__(self):
481-
"""Iterate over the current managed transactions.
482-
483-
:returns: An iterator of the managed transactions
484-
"""
485-
return iter(self.transactions.keys())
486-
487-
def addTransaction(self, request, tid=None):
488-
"""Add a transaction to the handler.
489-
490-
This holds the requests in case it needs to be resent.
491-
After being sent, the request is removed.
492-
493-
:param request: The request to hold on to
494-
:param tid: The overloaded transaction id to use
495-
"""
496-
tid = tid if tid is not None else request.transaction_id
497-
Log.debug("Adding transaction {}", tid)
498-
self.transactions[tid] = request
499-
500-
def getTransaction(self, tid):
501-
"""Return a transaction matching the referenced tid.
502-
503-
If the transaction does not exist, None is returned
504-
505-
:param tid: The transaction to retrieve
506-
507-
"""
508-
Log.debug("Getting transaction {}", tid)
509-
if not tid:
510-
if self.transactions:
511-
return self.transactions.popitem()[1]
512-
return None
513-
return self.transactions.pop(tid, None)
514-
515-
def delTransaction(self, tid):
516-
"""Remove a transaction matching the referenced tid.
517-
518-
:param tid: The transaction to remove
519-
"""
520-
Log.debug("deleting transaction {}", tid)
521-
self.transactions.pop(tid, None)

test/test_transaction.py

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,23 @@ def setup_method(self):
5050
self._rtu = ModbusRtuFramer(decoder=self.decoder, client=None)
5151
self._ascii = ModbusAsciiFramer(decoder=self.decoder, client=None)
5252
self._binary = ModbusBinaryFramer(decoder=self.decoder, client=None)
53-
self._manager = DictTransactionManager(self.client)
54-
self._tm = ModbusTransactionManager(self.client)
53+
self._manager = ModbusTransactionManager(self.client)
5554

5655
# ----------------------------------------------------------------------- #
57-
# Base transaction manager
56+
# Modbus transaction manager
5857
# ----------------------------------------------------------------------- #
5958

6059
def test_calculate_expected_response_length(self):
6160
"""Test calculate expected response length."""
62-
self._tm.client = mock.MagicMock()
63-
self._tm.client.framer = mock.MagicMock()
64-
self._tm._set_adu_size() # pylint: disable=protected-access
65-
assert not self._tm._calculate_response_length( # pylint: disable=protected-access
61+
self._manager.client = mock.MagicMock()
62+
self._manager.client.framer = mock.MagicMock()
63+
self._manager._set_adu_size() # pylint: disable=protected-access
64+
assert not self._manager._calculate_response_length( # pylint: disable=protected-access
6665
0
6766
)
68-
self._tm.base_adu_size = 10
67+
self._manager.base_adu_size = 10
6968
assert (
70-
self._tm._calculate_response_length(5) # pylint: disable=protected-access
69+
self._manager._calculate_response_length(5) # pylint: disable=protected-access
7170
== 15
7271
)
7372

@@ -81,23 +80,23 @@ def test_calculate_exception_length(self):
8180
("tls", 2),
8281
("dummy", None),
8382
):
84-
self._tm.client = mock.MagicMock()
83+
self._manager.client = mock.MagicMock()
8584
if framer == "ascii":
86-
self._tm.client.framer = self._ascii
85+
self._manager.client.framer = self._ascii
8786
elif framer == "binary":
88-
self._tm.client.framer = self._binary
87+
self._manager.client.framer = self._binary
8988
elif framer == "rtu":
90-
self._tm.client.framer = self._rtu
89+
self._manager.client.framer = self._rtu
9190
elif framer == "tcp":
92-
self._tm.client.framer = self._tcp
91+
self._manager.client.framer = self._tcp
9392
elif framer == "tls":
94-
self._tm.client.framer = self._tls
93+
self._manager.client.framer = self._tls
9594
else:
96-
self._tm.client.framer = mock.MagicMock()
95+
self._manager.client.framer = mock.MagicMock()
9796

98-
self._tm._set_adu_size() # pylint: disable=protected-access
97+
self._manager._set_adu_size() # pylint: disable=protected-access
9998
assert (
100-
self._tm._calculate_exception_length() # pylint: disable=protected-access
99+
self._manager._calculate_exception_length() # pylint: disable=protected-access
101100
== exception_length
102101
)
103102

@@ -125,7 +124,7 @@ def test_execute(self, mock_time):
125124
request.get_response_pdu_size.return_value = 10
126125
request.slave_id = 1
127126
request.function_code = 222
128-
trans = ModbusTransactionManager(client)
127+
trans = DictTransactionManager(client)
129128
trans._recv = mock.MagicMock( # pylint: disable=protected-access
130129
return_value=b"abcdef"
131130
)
@@ -140,7 +139,7 @@ def test_execute(self, mock_time):
140139
trans._recv = mock.MagicMock( # pylint: disable=protected-access
141140
return_value=b"abcdef"
142141
)
143-
trans.transactions = []
142+
trans.transactions = {}
144143
trans.getTransaction = mock.MagicMock()
145144
trans.getTransaction.return_value = None
146145
response = trans.execute(request)
@@ -198,19 +197,15 @@ def test_execute(self, mock_time):
198197
recv.assert_called_once_with(8, False)
199198
client.comm_params.handle_local_echo = False
200199

201-
# ----------------------------------------------------------------------- #
202-
# Dictionary based transaction manager
203-
# ----------------------------------------------------------------------- #
204-
205-
def test_dict_transaction_manager_tid(self):
206-
"""Test the dict transaction manager TID."""
200+
def test_transaction_manager_tid(self):
201+
"""Test the transaction manager TID."""
207202
for tid in range(1, self._manager.getNextTID() + 10):
208203
assert tid + 1 == self._manager.getNextTID()
209204
self._manager.reset()
210205
assert self._manager.getNextTID() == 1
211206

212-
def test_get_dict_fifo_transaction_manager_transaction(self):
213-
"""Test the dict transaction manager."""
207+
def test_get_transaction_manager_transaction(self):
208+
"""Test the getting a transaction from the transaction manager."""
214209

215210
class Request: # pylint: disable=too-few-public-methods
216211
"""Request."""
@@ -225,8 +220,8 @@ class Request: # pylint: disable=too-few-public-methods
225220
result = self._manager.getTransaction(handle.transaction_id)
226221
assert handle.message == result.message
227222

228-
def test_delete_dict_fifo_transaction_manager_transaction(self):
229-
"""Test the dict transaction manager."""
223+
def test_delete_transaction_manager_transaction(self):
224+
"""Test deleting a transaction from the dict transaction manager."""
230225

231226
class Request: # pylint: disable=too-few-public-methods
232227
"""Request."""

0 commit comments

Comments
 (0)