Skip to content

Commit 1a6a740

Browse files
authored
Merge pull request #8 from pymodbus-dev/repl-server-startup
Fix repl failing to start on python 3.8, address review comments
2 parents 7b7d2f0 + 1130fb2 commit 1a6a740

File tree

8 files changed

+105
-21
lines changed

8 files changed

+105
-21
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,4 @@ cython_debug/
157157
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158158
# and can be added to the global gitignore or merged into this file. For a more nuclear
159159
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
160-
#.idea/
160+
.idea/

README.md

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Pymodbus-REPL is a REPL (Read-Eval-Print Loop) tool for working with Modbus devi
99
- Python 3.8+
1010
- Poetry (installed globally or within a virtual environment)
1111

12-
### Installation
12+
### Dev instructions
1313

1414
1. Clone the repository:
1515

@@ -23,6 +23,80 @@ Pymodbus-REPL is a REPL (Read-Eval-Print Loop) tool for working with Modbus devi
2323

2424
`poetry install`
2525

26+
**NOTE** This repo is meant to be an helper for [pymodbus](https://github.com/pymodbus-dev/pymodbus) and the usage requires
27+
a working version of pymodbus.
28+
29+
The installed `pymodbus` library for local development can also have impact on the path resolution while working locally on this repo.
30+
To overcome that problem, please make sure to run the [client](./pymodbus/client/main.py) and [server](./pymodbus/server/main.py) files
31+
from with in the respective working directories.
32+
33+
For .e.g
34+
35+
#### Run Server
36+
```
37+
(pymodbus3.8)
38+
pymodbus/repl/server on  repl-server-startup [!?] via 🐍 v3.8.13 (pymodbus3.8)
39+
❯ python3 main.py --host 0.0.0.0 --verbose run --modbus-config default_config.json --modbus-server tcp --modbus-framer socket --modbus-port 5020 --unit-id 1 --unit-id 2 -u 4 -r 1 --timeout 2
40+
2024-02-17 13:27:17,218 INFO logging:97 Modbus server started
41+
2024-02-17 13:27:17,219 DEBUG logging:103 Awaiting connections server_listener
42+
2024-02-17 13:27:17,219 INFO logging:97 Server listening.
43+
44+
__________ .______. _________
45+
\______ \___.__. _____ ____ __| _/\_ |__ __ __ ______ / _____/ ______________ __ ___________
46+
| ___< | |/ \ / _ \ / __ | | __ \| | \/ ___/ \_____ \_/ __ \_ __ \ \/ // __ \_ __ \\
47+
| | \___ | Y Y ( <_> ) /_/ | | \_\ \ | /\___ \ / \ ___/| | \/\ /\ ___/| | \/
48+
|____| / ____|__|_| /\____/\____ | |___ /____//____ > /_______ /\___ >__| \_/ \___ >__|
49+
\/ \/ \/ \/ \/ \/ \/ \/
50+
51+
52+
SERVER >
53+
```
54+
55+
#### Run client
56+
```
57+
pymodbus/repl/client on  repl-server-startup [!?] via 🐍 v3.8.13 (pymodbus3.8)
58+
❯ python3 main.py tcp --port 5020 --framer tcp
59+
60+
----------------------------------------------------------------------------
61+
__________ _____ .___ __________ .__
62+
\______ \___.__. / \ ____ __| _/ \______ \ ____ ______ | |
63+
| ___< | |/ \ / \ / _ \ / __ | | _// __ \\\____ \| |
64+
| | \___ / Y ( <_> ) /_/ | | | \ ___/| |_> > |__
65+
|____| / ____\____|__ /\____/\____ | /\ |____|_ /\___ > __/|____/
66+
\/ \/ \/ \/ \/ \/|__|
67+
v1.3.1 - 3.6.4
68+
----------------------------------------------------------------------------
69+
70+
> client.read_input_registers address 1 count 1 slave 4
71+
{
72+
"registers": [
73+
34518
74+
]
75+
}
76+
77+
> client.read_input_registers address 1 count 1 slave 1
78+
{
79+
"registers": [
80+
32198
81+
]
82+
}
83+
84+
> client.read_input_registers address 1 count 1 slave 2
85+
{
86+
"registers": [
87+
51557
88+
]
89+
}
90+
91+
> client.read_input_registers address 1 count 1 slave 3
92+
{
93+
"original_function_code": "4 (0x4)",
94+
"error": "[Input/Output] Modbus Error: [Invalid Message] No response received, expected at least 8 bytes (0 received)"
95+
}
96+
97+
```
98+
99+
26100
### Running Tests
27101
To run tests, use the following command:
28102

poetry.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pymodbus_repl/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
"""REPL (Read-Eval-Print Loop) tool for working with Modbus devices using the Pymodbus library."""
2+
__VERSION__ = "2.0.0"
3+

pymodbus_repl/client/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from prompt_toolkit.styles import Style
1313
from pygments.lexers.python import PythonLexer
1414
from pymodbus import __version__ as pymodbus_version
15+
from pymodbus_repl import __VERSION__ as repl_version
1516
from pymodbus.exceptions import ParameterException
1617
from pymodbus.transaction import (
1718
ModbusAsciiFramer,
@@ -38,7 +39,7 @@
3839
| | \___ / Y ( <_> ) /_/ | | | \ ___/| |_> > |__
3940
|____| / ____\____|__ /\____/\____ | /\ |____|_ /\___ > __/|____/
4041
\/ \/ \/ \/ \/ \/|__|
41-
v1.3.1 - {pymodbus_version}
42+
v{repl_version} - Pymodbus-{pymodbus_version}
4243
----------------------------------------------------------------------------
4344
"""
4445

pymodbus_repl/server/cli.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from prompt_toolkit.shortcuts import clear
99
from prompt_toolkit.shortcuts.progress_bar import formatters
1010
from prompt_toolkit.styles import Style
11+
from pymodbus import __version__ as pymodbus_version
12+
from pymodbus_repl import __VERSION__ as repl_version
1113

1214

1315
TITLE = r"""
@@ -17,6 +19,7 @@
1719
| | \___ | Y Y ( <_> ) /_/ | | \_\ \ | /\___ \ / \ ___/| | \/\ /\ ___/| | \/
1820
|____| / ____|__|_| /\____/\____ | |___ /____//____ > /_______ /\___ >__| \_/ \___ >__|
1921
\/ \/ \/ \/ \/ \/ \/ \/
22+
v{}-Pymodbus{}
2023
"""
2124

2225

@@ -111,8 +114,9 @@ def print_title():
111114
max_len = max( # pylint: disable=consider-using-generator
112115
[len(t) for t in TITLE.split("\n")]
113116
)
117+
title = TITLE.format(repl_version, pymodbus_version)
114118
if col > max_len:
115-
info(TITLE)
119+
info(title)
116120
else:
117121
print_formatted_text(
118122
HTML(f'<u><b><style color="green">{SMALL_TITLE}</style></b></u>')

pymodbus_repl/server/main.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
"""Repl server main."""
2-
from __future__ import annotations
2+
# from __future__ import annotations
33

44
import asyncio
55
import contextlib
66
import json
77
import logging
88
import sys
99
from enum import Enum
10-
from pathlib import Path
1110

11+
from typing import List, Optional
12+
from pathlib import Path
1213
import typer
14+
from typing_extensions import Annotated
1315
from pymodbus import pymodbus_apply_logging_config
1416
from pymodbus.framer.socket_framer import ModbusSocketFramer
1517
from pymodbus.logging import Log
@@ -50,7 +52,7 @@ class ModbusFramerTypes(str, Enum):
5052
binary = "binary" # pylint: disable=invalid-name
5153

5254

53-
def _completer(incomplete: str, valid_values: list[str]) -> list[str]:
55+
def _completer(incomplete: str, valid_values: List[str]) -> List[str]:
5456
"""Complete value."""
5557
completion = []
5658
for name in valid_values:
@@ -59,19 +61,19 @@ def _completer(incomplete: str, valid_values: list[str]) -> list[str]:
5961
return completion
6062

6163

62-
def framers(incomplete: str) -> list[str]:
64+
def framers(incomplete: str) -> List[str]:
6365
"""Return an autocompleted list of supported clouds."""
6466
_framers = ["socket", "rtu", "tls", "ascii", "binary"]
6567
return _completer(incomplete, _framers)
6668

6769

68-
def servers(incomplete: str) -> list[str]:
70+
def servers(incomplete: str) -> List[str]:
6971
"""Return an autocompleted list of supported clouds."""
7072
_servers = ["tcp", "serial", "tls", "udp"]
7173
return _completer(incomplete, _servers)
7274

7375

74-
def process_extra_args(extra_args: list[str], modbus_config: dict) -> dict:
76+
def process_extra_args(extra_args: List[str], modbus_config: dict) -> dict:
7577
"""Process extra args passed to server."""
7678
options_stripped = [x.strip().replace("--", "") for x in extra_args[::2]]
7779
extra_args_dict = dict(list(zip(options_stripped, extra_args[1::2])))
@@ -139,12 +141,12 @@ def run(
139141
help="Modbus framer to use",
140142
),
141143
modbus_port: str = typer.Option("5020", "--modbus-port", "-p", help="Modbus port"),
142-
modbus_slave_id: list[int] = typer.Option(
143-
[1], "--slave-id", "-u", help="Supported Modbus slave id's"
144-
),
145-
modbus_config_path: Path = typer.Option(
146-
None, help="Path to additional modbus server config"
147-
),
144+
modbus_slave_id: Annotated[Optional[List[int]], typer.Option(
145+
"--unit-id", "-u", help="Supported Modbus slave id's"
146+
)] = [1],
147+
modbus_config_path: Annotated[Path, typer.Option(
148+
help="Path to additional modbus server config"
149+
)] = None,
148150
randomize: int = typer.Option(
149151
0,
150152
"--random",

pyproject.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "pymodbus_repl"
3-
version = "0.1.0"
3+
version = "2.0.0"
44
description = "REPL (Read-Eval-Print Loop) tool for working with Modbus devices using the Pymodbus library."
55
authors = ["dhoomakethu <[email protected]>"]
66
readme = "README.md"
@@ -11,7 +11,6 @@ python = "^3.8"
1111
typer = {extras = ["all"], version = "^0.9.0"}
1212
prompt-toolkit = "^3.0.43"
1313
pygments = "^2.17.2"
14-
pytest-xdist = "^3.5.0"
1514

1615
[[tool.poetry.dependencies.aiohttp]]
1716
python="3.12"
@@ -30,6 +29,7 @@ include = ["pymodbus_repl"]
3029
pymodbus = "^3.6.4"
3130
ruff = "^0.2.1"
3231
coverage = "^7.4.1"
32+
pytest-xdist = "^3.5.0"
3333
pytest-cov = "^4.1.0"
3434

3535
[build-system]
@@ -43,7 +43,7 @@ addopts = "--cov-report html"
4343

4444
[tool.coverage.run]
4545
source = [
46-
"pymodbus/"
46+
"pymodbus_repl/"
4747
]
4848
omit = ["examples/contrib/"]
4949
branch = true
@@ -56,6 +56,7 @@ exclude_also = [
5656
]
5757
skip_covered = true
5858
fail_under = 70.0
59+
show_missing = true
5960

6061
[tool.coverage.html]
6162
directory = "build/cov"

0 commit comments

Comments
 (0)