tmodbus 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. tmodbus-0.1.0/.gitignore +26 -0
  2. tmodbus-0.1.0/PKG-INFO +152 -0
  3. tmodbus-0.1.0/README.md +139 -0
  4. tmodbus-0.1.0/examples/async_rtu_client.py +49 -0
  5. tmodbus-0.1.0/examples/async_tcp_client.py +58 -0
  6. tmodbus-0.1.0/examples/async_tcp_tls_client.py +60 -0
  7. tmodbus-0.1.0/examples/ruff.toml +7 -0
  8. tmodbus-0.1.0/pyproject.toml +125 -0
  9. tmodbus-0.1.0/src/tmodbus/__init__.py +137 -0
  10. tmodbus-0.1.0/src/tmodbus/_version.py +34 -0
  11. tmodbus-0.1.0/src/tmodbus/client/__init__.py +5 -0
  12. tmodbus-0.1.0/src/tmodbus/client/async_client.py +341 -0
  13. tmodbus-0.1.0/src/tmodbus/const.py +42 -0
  14. tmodbus-0.1.0/src/tmodbus/exceptions.py +195 -0
  15. tmodbus-0.1.0/src/tmodbus/pdu/__init__.py +127 -0
  16. tmodbus-0.1.0/src/tmodbus/pdu/base.py +206 -0
  17. tmodbus-0.1.0/src/tmodbus/pdu/coils.py +362 -0
  18. tmodbus-0.1.0/src/tmodbus/pdu/device.py +135 -0
  19. tmodbus-0.1.0/src/tmodbus/pdu/discrete_inputs.py +11 -0
  20. tmodbus-0.1.0/src/tmodbus/pdu/holding_registers.py +539 -0
  21. tmodbus-0.1.0/src/tmodbus/pdu/holding_registers_struct.py +619 -0
  22. tmodbus-0.1.0/src/tmodbus/transport/__init__.py +13 -0
  23. tmodbus-0.1.0/src/tmodbus/transport/async_base.py +88 -0
  24. tmodbus-0.1.0/src/tmodbus/transport/async_rtu.py +346 -0
  25. tmodbus-0.1.0/src/tmodbus/transport/async_smart.py +245 -0
  26. tmodbus-0.1.0/src/tmodbus/transport/async_tcp.py +266 -0
  27. tmodbus-0.1.0/src/tmodbus/utils/__init__.py +1 -0
  28. tmodbus-0.1.0/src/tmodbus/utils/crc.py +63 -0
  29. tmodbus-0.1.0/src/tmodbus/utils/raw_traffic_logger.py +29 -0
  30. tmodbus-0.1.0/src/tmodbus/utils/word_aware_struct.py +135 -0
  31. tmodbus-0.1.0/tests/__init__.py +1 -0
  32. tmodbus-0.1.0/tests/client/__init__.py +1 -0
  33. tmodbus-0.1.0/tests/client/test_async_client.py +397 -0
  34. tmodbus-0.1.0/tests/pdu/__init__.py +1 -0
  35. tmodbus-0.1.0/tests/pdu/test_base.py +355 -0
  36. tmodbus-0.1.0/tests/pdu/test_coils.py +297 -0
  37. tmodbus-0.1.0/tests/pdu/test_device.py +285 -0
  38. tmodbus-0.1.0/tests/pdu/test_holding_registers.py +533 -0
  39. tmodbus-0.1.0/tests/pdu/test_holding_registers_struct.py +846 -0
  40. tmodbus-0.1.0/tests/pdu/test_pdu.py +274 -0
  41. tmodbus-0.1.0/tests/ruff.toml +12 -0
  42. tmodbus-0.1.0/tests/test_exceptions.py +35 -0
  43. tmodbus-0.1.0/tests/test_init.py +87 -0
  44. tmodbus-0.1.0/tests/transport/__init__.py +1 -0
  45. tmodbus-0.1.0/tests/transport/test_async_base.py +55 -0
  46. tmodbus-0.1.0/tests/transport/test_async_rtu.py +469 -0
  47. tmodbus-0.1.0/tests/transport/test_async_smart.py +369 -0
  48. tmodbus-0.1.0/tests/transport/test_async_tcp.py +309 -0
  49. tmodbus-0.1.0/tests/utils/__init__.py +1 -0
  50. tmodbus-0.1.0/tests/utils/test_crc.py +17 -0
  51. tmodbus-0.1.0/tests/utils/test_raw_traffic_logger.py +47 -0
  52. tmodbus-0.1.0/tests/utils/test_word_aware_struct.py +203 -0
@@ -0,0 +1,26 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ .python-version
12
+
13
+ # coverage
14
+ .coverage
15
+
16
+ # ruff
17
+ .ruff_cache/
18
+
19
+ # pytest
20
+ .pytest_cache/
21
+
22
+ # docs
23
+ docs/_build/
24
+
25
+ # version file
26
+ src/tmodbus/_version.py
tmodbus-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.4
2
+ Name: tmodbus
3
+ Version: 0.1.0
4
+ Summary: A modern, strongly typed Modbus client library.
5
+ Author: wlcrs
6
+ Keywords: modbus,modbus-rtu,modbus-tcp
7
+ Requires-Python: >=3.12
8
+ Provides-Extra: async-rtu
9
+ Requires-Dist: pyserial-asyncio-fast>=0.16; extra == 'async-rtu'
10
+ Provides-Extra: smart
11
+ Requires-Dist: tenacity>=9.1.2; extra == 'smart'
12
+ Description-Content-Type: text/markdown
13
+
14
+ # tModbus
15
+ [![Release](https://img.shields.io/github/v/release/wlcrs/tmodbus.svg)](https://github.com/wlcrs/tmodbus/releases)
16
+ [![Python Versions](https://img.shields.io/pypi/pyversions/tmodbus)](https://pypi.org/p/tmodbus/)
17
+ [![Testing](https://github.com/wlcrs/tmodbus/actions/workflows/tests.yml/badge.svg)](https://github.com/wlcrs/tmodbus/actions/workflows/tests.yml)
18
+
19
+ ## About
20
+
21
+ A modern Python Modbus library that is fully **t**yped and well-**t**ested.
22
+
23
+ Modbus is based on the [_master/slave_](https://en.wikipedia.org/wiki/Master%E2%80%93slave_(technology)) communication pattern.
24
+ We choose to use the terminology _client_ and _server_ instead, as it is more clear.
25
+
26
+ ## Features
27
+
28
+ - Pure Python library with minimal dependencies
29
+ - Fully **t**yped
30
+ - Full **t**est coverage
31
+ - Support for both Modbus TCP and RTU clients
32
+ - Support for TCP over SSL connections
33
+ - Auto reconnect and retry functionality (which can be enabled optionally)
34
+ - Extensible with custom Modbus functions and exception codes
35
+ - Open source (BSD)
36
+
37
+ ## Supported function codes
38
+
39
+ * Read coils (`0x01`)
40
+ * Read discrete inputs (`0x02`)
41
+ * Read holding registers (`0x03`)
42
+ * Read input registers (`0x04`)
43
+ * Write single coil (`0x05`)
44
+ * Write single register (`0x06`)
45
+ * Write multiple coils (`0x0f`)
46
+ * Write multiple registers (`0x10`)
47
+ * Read device identification (`0x2B / 0x0E`)
48
+
49
+ ## Examples
50
+
51
+ A simple example of an Async TCP client:
52
+
53
+ ```python
54
+ import asyncio
55
+
56
+ from tmodbus import create_async_tcp_client
57
+
58
+
59
+ async def main() -> None:
60
+ """Show example of reading a Modbus register."""
61
+ async with create_async_tcp_client("127.0.0.1", 502, unit_id=1) as client:
62
+ response = await client.read_holding_registers(start_address=100, quantity=2)
63
+ print("Contents of holding registers 100 and 101: ", response)
64
+
65
+
66
+ if __name__ == "__main__":
67
+ asyncio.run(main())
68
+
69
+ ```
70
+
71
+ Various examples for Modbus RTU and TCP can be found in the [examples](./examples) folder.
72
+
73
+ ## Dependencies
74
+
75
+ **async-rtu**
76
+
77
+ This library uses [pyserial-asyncio-fast](https://pypi.org/project/pyserial-asyncio-fast/) to
78
+ access the serial port when using async RTU.
79
+
80
+ Use `pip install tmodbus[async-rtu]` to install.
81
+
82
+ **smart**
83
+
84
+ This library uses [tenacity](https://github.com/jd/tenacity) to implement the reconnect and retry-logic,
85
+ giving you access to a powerful API to customize the retry behavior of this library.
86
+
87
+ Use `pip install tmodbus[smart]` to install.
88
+
89
+ ## Changelog & releases
90
+
91
+ This repository keeps a change log using [GitHub's releases](https://github.com/wlcrs/tmodbus/releases)
92
+ functionality. The format of the log is based on
93
+ [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
94
+
95
+ Releases are based on [Semantic Versioning](http://semver.org/spec/v2.0.0.html), and use the format
96
+ of `MAJOR.MINOR.PATCH`. In a nutshell, the version will be incremented
97
+ based on the following:
98
+
99
+ - `MAJOR`: Incompatible or major changes.
100
+ - `MINOR`: Backwards-compatible new features and enhancements.
101
+ - `PATCH`: Backwards-compatible bugfixes and package updates.
102
+
103
+ ## Contributing
104
+
105
+ This is an active open-source project. We are always open to people who want to
106
+ use the code or contribute to it.
107
+
108
+ We've set up a separate document for our
109
+ [contribution guidelines](.github/CONTRIBUTING.md).
110
+
111
+ Thank you for being involved! :heart_eyes:
112
+
113
+ ### Setting up a development environment
114
+
115
+ This Python project is fully managed using the [uv] dependency manager.
116
+
117
+ You need at least:
118
+
119
+ - Python 3.12+
120
+ - [uv][uv-install]
121
+
122
+ To install all packages, including all development requirements:
123
+
124
+ ```bash
125
+ uv sync --all-extras --dev
126
+ ```
127
+
128
+ As this repository uses the [pre-commit][pre-commit] framework, all changes
129
+ are linted and tested with each commit. You can run all checks and tests
130
+ manually, using the following command:
131
+
132
+ ```bash
133
+ uv run pre-commit run --all-files
134
+ ```
135
+
136
+ To run just the Python tests:
137
+
138
+ ```bash
139
+ uv run pytest
140
+ ```
141
+
142
+
143
+ ## Protocol-Specification
144
+
145
+ - [Modbus Application Protocol Specification v1.1b3 (PDF)](http://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf)
146
+ - [Modbus over serial line specification and implementation guide v1.02 (PDF)](http://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf)
147
+ - [Modbus Messaging on TCP/IP Implementation Guide v1.0b (PDF)](http://modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf)
148
+
149
+
150
+ [uv-install]: https://docs.astral.sh/uv/getting-started/installation/
151
+ [uv]: https://docs.astral.sh/uv/
152
+ [pre-commit]: https://pre-commit.com/
@@ -0,0 +1,139 @@
1
+ # tModbus
2
+ [![Release](https://img.shields.io/github/v/release/wlcrs/tmodbus.svg)](https://github.com/wlcrs/tmodbus/releases)
3
+ [![Python Versions](https://img.shields.io/pypi/pyversions/tmodbus)](https://pypi.org/p/tmodbus/)
4
+ [![Testing](https://github.com/wlcrs/tmodbus/actions/workflows/tests.yml/badge.svg)](https://github.com/wlcrs/tmodbus/actions/workflows/tests.yml)
5
+
6
+ ## About
7
+
8
+ A modern Python Modbus library that is fully **t**yped and well-**t**ested.
9
+
10
+ Modbus is based on the [_master/slave_](https://en.wikipedia.org/wiki/Master%E2%80%93slave_(technology)) communication pattern.
11
+ We choose to use the terminology _client_ and _server_ instead, as it is more clear.
12
+
13
+ ## Features
14
+
15
+ - Pure Python library with minimal dependencies
16
+ - Fully **t**yped
17
+ - Full **t**est coverage
18
+ - Support for both Modbus TCP and RTU clients
19
+ - Support for TCP over SSL connections
20
+ - Auto reconnect and retry functionality (which can be enabled optionally)
21
+ - Extensible with custom Modbus functions and exception codes
22
+ - Open source (BSD)
23
+
24
+ ## Supported function codes
25
+
26
+ * Read coils (`0x01`)
27
+ * Read discrete inputs (`0x02`)
28
+ * Read holding registers (`0x03`)
29
+ * Read input registers (`0x04`)
30
+ * Write single coil (`0x05`)
31
+ * Write single register (`0x06`)
32
+ * Write multiple coils (`0x0f`)
33
+ * Write multiple registers (`0x10`)
34
+ * Read device identification (`0x2B / 0x0E`)
35
+
36
+ ## Examples
37
+
38
+ A simple example of an Async TCP client:
39
+
40
+ ```python
41
+ import asyncio
42
+
43
+ from tmodbus import create_async_tcp_client
44
+
45
+
46
+ async def main() -> None:
47
+ """Show example of reading a Modbus register."""
48
+ async with create_async_tcp_client("127.0.0.1", 502, unit_id=1) as client:
49
+ response = await client.read_holding_registers(start_address=100, quantity=2)
50
+ print("Contents of holding registers 100 and 101: ", response)
51
+
52
+
53
+ if __name__ == "__main__":
54
+ asyncio.run(main())
55
+
56
+ ```
57
+
58
+ Various examples for Modbus RTU and TCP can be found in the [examples](./examples) folder.
59
+
60
+ ## Dependencies
61
+
62
+ **async-rtu**
63
+
64
+ This library uses [pyserial-asyncio-fast](https://pypi.org/project/pyserial-asyncio-fast/) to
65
+ access the serial port when using async RTU.
66
+
67
+ Use `pip install tmodbus[async-rtu]` to install.
68
+
69
+ **smart**
70
+
71
+ This library uses [tenacity](https://github.com/jd/tenacity) to implement the reconnect and retry-logic,
72
+ giving you access to a powerful API to customize the retry behavior of this library.
73
+
74
+ Use `pip install tmodbus[smart]` to install.
75
+
76
+ ## Changelog & releases
77
+
78
+ This repository keeps a change log using [GitHub's releases](https://github.com/wlcrs/tmodbus/releases)
79
+ functionality. The format of the log is based on
80
+ [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
81
+
82
+ Releases are based on [Semantic Versioning](http://semver.org/spec/v2.0.0.html), and use the format
83
+ of `MAJOR.MINOR.PATCH`. In a nutshell, the version will be incremented
84
+ based on the following:
85
+
86
+ - `MAJOR`: Incompatible or major changes.
87
+ - `MINOR`: Backwards-compatible new features and enhancements.
88
+ - `PATCH`: Backwards-compatible bugfixes and package updates.
89
+
90
+ ## Contributing
91
+
92
+ This is an active open-source project. We are always open to people who want to
93
+ use the code or contribute to it.
94
+
95
+ We've set up a separate document for our
96
+ [contribution guidelines](.github/CONTRIBUTING.md).
97
+
98
+ Thank you for being involved! :heart_eyes:
99
+
100
+ ### Setting up a development environment
101
+
102
+ This Python project is fully managed using the [uv] dependency manager.
103
+
104
+ You need at least:
105
+
106
+ - Python 3.12+
107
+ - [uv][uv-install]
108
+
109
+ To install all packages, including all development requirements:
110
+
111
+ ```bash
112
+ uv sync --all-extras --dev
113
+ ```
114
+
115
+ As this repository uses the [pre-commit][pre-commit] framework, all changes
116
+ are linted and tested with each commit. You can run all checks and tests
117
+ manually, using the following command:
118
+
119
+ ```bash
120
+ uv run pre-commit run --all-files
121
+ ```
122
+
123
+ To run just the Python tests:
124
+
125
+ ```bash
126
+ uv run pytest
127
+ ```
128
+
129
+
130
+ ## Protocol-Specification
131
+
132
+ - [Modbus Application Protocol Specification v1.1b3 (PDF)](http://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf)
133
+ - [Modbus over serial line specification and implementation guide v1.02 (PDF)](http://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf)
134
+ - [Modbus Messaging on TCP/IP Implementation Guide v1.0b (PDF)](http://modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf)
135
+
136
+
137
+ [uv-install]: https://docs.astral.sh/uv/getting-started/installation/
138
+ [uv]: https://docs.astral.sh/uv/
139
+ [pre-commit]: https://pre-commit.com/
@@ -0,0 +1,49 @@
1
+ """Example of an asynchronous RTU Modbus client using tmodbus."""
2
+
3
+ import asyncio
4
+
5
+ from tmodbus import create_async_rtu_client
6
+ from tmodbus.exceptions import InvalidResponseError, ModbusConnectionError, ModbusResponseError
7
+
8
+
9
+ async def example_rtu_client() -> None:
10
+ """Asynchronous RTU Modbus client example."""
11
+ # Replace with your Modbus server's IP and por
12
+ port = "/dev/ttyUSB0"
13
+ baudrate = 9600 # Adjust baudrate as needed
14
+
15
+ unit_id = 1 # Modbus unit ID of the target device
16
+
17
+ # The create_async_rtu_client function returns an instance of AsyncModbusClient
18
+ client = create_async_rtu_client(port, baudrate=baudrate, unit_id=unit_id)
19
+
20
+ try:
21
+ await client.connect()
22
+ # Read 2 holding registers starting at address 100
23
+ coils_response = await client.read_holding_registers(start_address=100, quantity=2)
24
+
25
+ print("Contents of holding registers 100 and 101: ", coils_response)
26
+
27
+ # Write value 123 to holding register at address 1
28
+ await client.write_single_register(address=1, value=123)
29
+
30
+ # Write values [10, 20, 30] to holding registers starting at address 10
31
+ await client.write_multiple_registers(start_address=10, values=[10, 20, 30])
32
+
33
+ except ModbusResponseError as e:
34
+ print(f"The server responded with error code {e.error_code:#04x} for function {e.function_code:#04x}")
35
+ except InvalidResponseError as e:
36
+ print(f"Received invalid response: {e}")
37
+ except ModbusConnectionError as e:
38
+ print(f"A connection error occurred: {e}")
39
+ finally:
40
+ await client.disconnect()
41
+
42
+ # Alternatively, you can use the client as an async context manager
43
+ # which automatically handles connection and disconnection
44
+ async with create_async_rtu_client(port, baudrate=baudrate, unit_id=unit_id) as client2:
45
+ print("Status of coils 0-7: ", await client2.read_coils(start_address=0, quantity=8))
46
+
47
+
48
+ if __name__ == "__main__":
49
+ asyncio.run(example_rtu_client())
@@ -0,0 +1,58 @@
1
+ """Example of an asynchronous TCP Modbus client using tmodbus."""
2
+
3
+ import asyncio
4
+
5
+ from tmodbus import create_async_tcp_client
6
+ from tmodbus.exceptions import InvalidResponseError, ModbusConnectionError, ModbusResponseError
7
+
8
+
9
+ async def example_tcp_client() -> None:
10
+ """Asynchronous TCP Modbus client example."""
11
+ # Replace with your Modbus server's IP and port
12
+ host = "127.0.0.1"
13
+ port = 502
14
+
15
+ unit_id = 1 # Modbus unit ID of the target device
16
+
17
+ # The create_async_tcp_client function returns an instance of AsyncModbusClient
18
+ client = create_async_tcp_client(host, port, unit_id=unit_id)
19
+
20
+ try:
21
+ await client.connect()
22
+ # Read 2 holding registers starting at address 100
23
+ response = await client.read_holding_registers(start_address=100, quantity=2)
24
+
25
+ print("Contents of holding registers 100 and 101: ", response)
26
+
27
+ client_for_unit_id_2 = client.for_unit_id(2)
28
+ response2 = await client_for_unit_id_2.read_holding_registers(start_address=100, quantity=2)
29
+ print("Contents of holding registers 100 and 101 for unit ID 2: ", response2)
30
+
31
+ response6 = await client.for_unit_id(6).read_float(start_address=1)
32
+ print("Float value at address 1 for unit ID 6: ", response6)
33
+
34
+ # Write value 123 to holding register at address 1
35
+ await client.write_single_register(address=1, value=123)
36
+ print("Wrote 123 to holding register at address 1")
37
+
38
+ # Write values [10, 20, 30] to holding registers starting at address 10
39
+ await client.write_multiple_registers(start_address=10, values=[10, 20, 30])
40
+ print("Wrote [10, 20, 30] to holding registers starting at address 10")
41
+
42
+ except ModbusResponseError as e:
43
+ print(f"The server responded with error code {e.error_code:#04x} for function {e.function_code:#04x}")
44
+ except InvalidResponseError as e:
45
+ print(f"Received invalid response: {e}")
46
+ except ModbusConnectionError as e:
47
+ print(f"A connection error occurred: {e}")
48
+ finally:
49
+ await client.disconnect()
50
+
51
+ # Alternatively, you can use the client as an async context manager
52
+ # which automatically handles connection and disconnection
53
+ async with create_async_tcp_client(host, port, unit_id=unit_id) as client2:
54
+ print("Status of coils 0-7: ", await client2.read_coils(start_address=0, quantity=8))
55
+
56
+
57
+ if __name__ == "__main__":
58
+ asyncio.run(example_tcp_client())
@@ -0,0 +1,60 @@
1
+ """Example of an asynchronous TCP Modbus client over an SSL connection using tmodbus."""
2
+
3
+ import asyncio
4
+ import ssl
5
+
6
+ from tmodbus import create_async_tcp_client
7
+ from tmodbus.exceptions import InvalidResponseError, ModbusConnectionError, ModbusResponseError
8
+
9
+
10
+ async def example_tcp_client() -> None:
11
+ """Asynchronous TCP Modbus client example."""
12
+ # Replace with your Modbus server's IP and port
13
+ host = "127.0.0.1"
14
+ port = 502
15
+
16
+ unit_id = 1 # Modbus unit ID of the target device
17
+
18
+ # You can pass any additional parameters supported by `asyncio.open_connection`
19
+ # For example, to use an SSL context, you can set `ssl=True` or provide a custom SSLContext
20
+
21
+ # The create_async_tcp_client function returns an instance of AsyncModbusClient
22
+ client = create_async_tcp_client(host, port, unit_id=unit_id, ssl=True)
23
+
24
+ try:
25
+ await client.connect()
26
+ # Read 2 holding registers starting at address 100
27
+ coils_response = await client.read_holding_registers(start_address=100, quantity=2)
28
+
29
+ print("Contents of holding registers 100 and 101: ", coils_response)
30
+
31
+ # Write value 123 to holding register at address 1
32
+ await client.write_single_register(address=1, value=123)
33
+
34
+ # Write values [10, 20, 30] to holding registers starting at address 10
35
+ await client.write_multiple_registers(start_address=10, values=[10, 20, 30])
36
+
37
+ except ModbusResponseError as e:
38
+ print(f"The server responded with error code {e.error_code:#04x} for function {e.function_code:#04x}")
39
+ except InvalidResponseError as e:
40
+ print(f"Received invalid response: {e}")
41
+ except ModbusConnectionError as e:
42
+ print(f"A connection error occurred: {e}")
43
+ finally:
44
+ await client.disconnect()
45
+
46
+ # Alternatively, you can use the client as an async context manager
47
+ # which automatically handles connection and disconnection.
48
+ # We also demonstrate passing of a custom SSL context here.
49
+
50
+ ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
51
+ ssl_context.load_default_certs(purpose=ssl.Purpose.SERVER_AUTH)
52
+ ssl_context.check_hostname = True
53
+ ssl_context.verify_mode = ssl.CERT_REQUIRED
54
+
55
+ async with create_async_tcp_client(host, port, unit_id=unit_id, ssl=ssl_context) as client2:
56
+ print("Status of coils 0-7: ", await client2.read_coils(start_address=0, quantity=8))
57
+
58
+
59
+ if __name__ == "__main__":
60
+ asyncio.run(example_tcp_client())
@@ -0,0 +1,7 @@
1
+ # This extend our general Ruff rules
2
+ extend = "../pyproject.toml"
3
+
4
+ lint.extend-ignore = [
5
+ "INP001", # not a package
6
+ "T201", # use print statements in examples
7
+ ]
@@ -0,0 +1,125 @@
1
+ [project]
2
+ name = "tmodbus"
3
+ authors= [{name="wlcrs"}]
4
+ description = "A modern, strongly typed Modbus client library."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ keywords = ["modbus", "modbus-tcp", "modbus-rtu"]
8
+ dynamic = ["version"]
9
+
10
+
11
+ [project.optional-dependencies]
12
+
13
+ async-rtu = [
14
+ "pyserial-asyncio-fast>=0.16",
15
+ ]
16
+
17
+ smart = [
18
+ "tenacity>=9.1.2",
19
+ ]
20
+
21
+ [build-system]
22
+ requires = ["hatchling", "hatch-vcs"]
23
+ build-backend = "hatchling.build"
24
+
25
+ [tool.hatch.build.targets.wheel]
26
+ only-packages = true
27
+
28
+ [tool.hatch.build.targets.sdist]
29
+ only-include = ["examples", "src", "tests"]
30
+
31
+ [tool.hatch.version]
32
+ source = "vcs"
33
+
34
+ [tool.hatch.build.hooks.vcs]
35
+ version-file = "src/tmodbus/_version.py"
36
+
37
+ [tool.ruff]
38
+ line-length = 120
39
+
40
+ [tool.ruff.lint]
41
+ ignore = [
42
+ "ANN401", # Opinioated warning on disallowing dynamically typed expressions
43
+ "D203", # Conflicts with other rules
44
+ "D213", # Conflicts with other rules
45
+ "PLR2004", # Just annoying, not really useful
46
+ "S101", # allow asserts
47
+
48
+ # Conflicts with the Ruff formatter
49
+ "COM812",
50
+ "ISC001",
51
+
52
+ ]
53
+ select = ["ALL"]
54
+
55
+ [tool.mypy]
56
+ # Specify the target platform details in config, so your developers are
57
+ # free to run mypy on Windows, Linux, or macOS and get consistent
58
+ # results.
59
+ platform = "linux"
60
+ python_version = "3.12"
61
+
62
+ # show error messages from unrelated files
63
+ follow_imports = "normal"
64
+
65
+ # suppress errors about unsatisfied imports
66
+ ignore_missing_imports = true
67
+
68
+ # be strict
69
+ check_untyped_defs = true
70
+ disallow_any_generics = true
71
+ disallow_incomplete_defs = true
72
+ disallow_subclassing_any = true
73
+ disallow_untyped_calls = true
74
+ disallow_untyped_decorators = true
75
+ disallow_untyped_defs = true
76
+ no_implicit_optional = true
77
+ no_implicit_reexport = true
78
+ strict_optional = true
79
+ warn_incomplete_stub = true
80
+ warn_no_return = true
81
+ warn_redundant_casts = true
82
+ warn_return_any = true
83
+ warn_unused_configs = true
84
+ warn_unused_ignores = true
85
+
86
+
87
+ [tool.pytest.ini_options]
88
+ addopts = "--cov"
89
+ asyncio_mode = "auto"
90
+
91
+ [tool.coverage.run]
92
+ plugins = ["covdefaults"]
93
+ source = ["tmodbus"]
94
+ omit = [
95
+ "src/tmodbus/_version.py", # automatically generated by hatch-vcs
96
+ ]
97
+ [tool.coverage.report]
98
+ show_missing = true
99
+ fail_under = 100
100
+
101
+
102
+ [tool.uv]
103
+ prerelease = "allow"
104
+
105
+ [dependency-groups]
106
+ dev = [
107
+ "codespell==2.4.1",
108
+ "covdefaults==2.3.0",
109
+ "coverage[toml]==7.10.7",
110
+ "mypy==1.18.2",
111
+ "pre-commit==4.3.0",
112
+ "pre-commit-hooks==6.0.0",
113
+ "pytest==8.4.2",
114
+ "pytest-asyncio==1.2.0",
115
+ "pytest-cov==7.0.0",
116
+ "ruff==0.13.3",
117
+ "yamllint==1.37.1",
118
+ ]
119
+
120
+ docs = [
121
+ "sphinx>=8.2.3",
122
+ "sphinx-rtd-theme>=3.0.2",
123
+ "sphinx-autobuild",
124
+ "sphinxcontrib-mermaid",
125
+ ]