Skip to content

Commit 66536c2

Browse files
committed
feat(wokwi): Add support for specifying diagram path
This PR adds a support of specifying diagram file for pytest-embedded-wokwi. To specify diagram.json add --wokwi-diagram to the pytest command s
1 parent 30082f7 commit 66536c2

File tree

5 files changed

+55
-20
lines changed

5 files changed

+55
-20
lines changed

pytest-embedded-wokwi/pytest_embedded_wokwi/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""Make pytest-embedded plugin work with the Wokwi CLI."""
22

3-
from .dut import WokwiDut
4-
from .wokwi_cli import WokwiCLI
3+
WOKWI_CLI_MINIMUM_VERSION = '0.10.1'
4+
5+
from .dut import WokwiDut # noqa
6+
from .wokwi_cli import WokwiCLI # noqa
57

68
__all__ = [
9+
'WOKWI_CLI_MINIMUM_VERSION',
710
'WokwiCLI',
811
'WokwiDut',
912
]

pytest-embedded-wokwi/pytest_embedded_wokwi/wokwi_cli.py

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
import typing as t
66
from pathlib import Path
77

8+
import pexpect
89
import toml
10+
from packaging.version import Version
911
from pytest_embedded import __version__
1012
from pytest_embedded.log import DuplicateStdoutPopen
1113

14+
from pytest_embedded_wokwi import WOKWI_CLI_MINIMUM_VERSION
15+
1216
from .idf import IDFFirmwareResolver
1317

1418
if t.TYPE_CHECKING:
@@ -32,7 +36,6 @@ class WokwiCLI(DuplicateStdoutPopen):
3236
"""
3337

3438
SOURCE = 'Wokwi'
35-
3639
WOKWI_CLI_PATH = 'wokwi-cli'
3740

3841
def __init__(
@@ -41,6 +44,7 @@ def __init__(
4144
wokwi_cli_path: t.Optional[str] = None,
4245
wokwi_timeout: t.Optional[int] = None,
4346
wokwi_scenario: t.Optional[str] = None,
47+
wokwi_diagram: t.Optional[str] = None,
4448
app: t.Optional['IdfApp'] = None,
4549
**kwargs,
4650
):
@@ -51,15 +55,38 @@ def __init__(
5155
self.app = app
5256
self.firmware_resolver = firmware_resolver
5357

58+
# first need to check if wokwi-cli exists in PATH
59+
if shutil.which('wokwi-cli') is None:
60+
print('Please install wokwi-cli, by running: curl -L https://wokwi.com/ci/install.sh | sh')
61+
# self.install_wokwi() not implemented yet
62+
63+
child = pexpect.spawn('wokwi-cli --help')
64+
try:
65+
child.expect(r'Wokwi CLI v(\d+\.\d+\.\d+)', timeout=1)
66+
wokwi_cli_version = child.match.group(1).decode('utf-8')
67+
except pexpect.TIMEOUT:
68+
raise RuntimeError('Failed to run wokwi-cli')
69+
70+
if Version(wokwi_cli_version) < Version(WOKWI_CLI_MINIMUM_VERSION):
71+
raise ValueError(
72+
f'Wokwi CLI version {wokwi_cli_version} is not supported. '
73+
f'Minimum version required: {WOKWI_CLI_MINIMUM_VERSION}. '
74+
f'To update Wokwi CLI run: curl -L https://wokwi.com/ci/install.sh | sh'
75+
)
76+
5477
self.create_wokwi_toml()
55-
self.create_diagram_json()
78+
79+
if wokwi_diagram is None:
80+
self.create_diagram_json()
5681

5782
wokwi_cli = wokwi_cli_path or self.wokwi_cli_executable
5883
cmd = [wokwi_cli, '--interactive', app.app_path]
5984
if (wokwi_timeout is not None) and (wokwi_timeout > 0):
6085
cmd.extend(['--timeout', str(wokwi_timeout)])
6186
if (wokwi_scenario is not None) and os.path.exists(wokwi_scenario):
6287
cmd.extend(['--scenario', wokwi_scenario])
88+
if (wokwi_diagram is not None) and os.path.exists(wokwi_diagram):
89+
cmd.extend(['--diagram-file', wokwi_diagram])
6390

6491
super().__init__(
6592
cmd=cmd,
@@ -70,6 +97,9 @@ def __init__(
7097
def wokwi_cli_executable(self):
7198
return self.WOKWI_CLI_PATH
7299

100+
def install_wokwi():
101+
pass
102+
73103
def create_wokwi_toml(self):
74104
app = self.app
75105
flasher_args = self.firmware_resolver.resolve_firmware(app)
@@ -107,22 +137,6 @@ def create_diagram_json(self):
107137
app = self.app
108138
target_board = target_to_board[app.target]
109139

110-
# Check for specific target.diagram.json file first
111-
diagram_json_path = os.path.join(app.app_path, (app.target + '.diagram.json'))
112-
if os.path.exists(diagram_json_path):
113-
# If there is also common diagram.json file, backup it first to diagram.json.old
114-
if os.path.exists(os.path.join(app.app_path, 'diagram.json')):
115-
logging.warning(
116-
'using %s instead. backup the original diagram.json to diagram.json.old', diagram_json_path
117-
)
118-
shutil.copyfile(
119-
os.path.join(app.app_path, 'diagram.json'),
120-
os.path.join(app.app_path, 'diagram.json.old'),
121-
)
122-
# Copy target.diagram.json to diagram.json
123-
shutil.copyfile(diagram_json_path, os.path.join(app.app_path, 'diagram.json'))
124-
return
125-
126140
# Check for common diagram.json file
127141
diagram_json_path = os.path.join(app.app_path, 'diagram.json')
128142
if os.path.exists(diagram_json_path):

pytest-embedded-wokwi/tests/test_wokwi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def test_pexpect_by_wokwi(dut):
5454
'-s',
5555
'--embedded-services', 'arduino,wokwi',
5656
'--app-path', os.path.join(testdir.tmpdir, 'hello_world_arduino'),
57+
'--wokwi-diagram', os.path.join(testdir.tmpdir, 'hello_world_arduino/esp32.diagram.json'),
5758
)
5859

5960
result.assert_outcomes(passed=1)

pytest-embedded/pytest_embedded/dut_factory.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ def _fixture_classes_and_options_fn(
149149
wokwi_cli_path,
150150
wokwi_timeout,
151151
wokwi_scenario,
152+
wokwi_diagram,
152153
skip_regenerate_image,
153154
encrypt,
154155
keyfile,
@@ -302,6 +303,7 @@ def _fixture_classes_and_options_fn(
302303
'wokwi_cli_path': wokwi_cli_path,
303304
'wokwi_timeout': wokwi_timeout,
304305
'wokwi_scenario': wokwi_scenario,
306+
'wokwi_diagram': wokwi_diagram,
305307
'msg_queue': msg_queue,
306308
'app': None,
307309
'meta': _meta,
@@ -608,6 +610,7 @@ def create(
608610
wokwi_cli_path: t.Optional[str] = None,
609611
wokwi_timeout: t.Optional[int] = 0,
610612
wokwi_scenario: t.Optional[str] = None,
613+
wokwi_diagram: t.Optional[str] = None,
611614
skip_regenerate_image: t.Optional[bool] = None,
612615
encrypt: t.Optional[bool] = None,
613616
keyfile: t.Optional[str] = None,
@@ -655,6 +658,7 @@ def create(
655658
wokwi_cli_path: Wokwi CLI path.
656659
wokwi_timeout: Wokwi timeout.
657660
wokwi_scenario: Wokwi scenario path.
661+
wokwi_diagram: Wokwi diagram path.
658662
skip_regenerate_image: Skip image regeneration flag.
659663
encrypt: Encryption flag.
660664
keyfile: Keyfile for encryption.
@@ -718,6 +722,7 @@ def create(
718722
'wokwi_cli_path': wokwi_cli_path,
719723
'wokwi_timeout': wokwi_timeout,
720724
'wokwi_scenario': wokwi_scenario,
725+
'wokwi_diagram': wokwi_diagram,
721726
'skip_regenerate_image': skip_regenerate_image,
722727
'encrypt': encrypt,
723728
'keyfile': keyfile,

pytest-embedded/pytest_embedded/plugin.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ def pytest_addoption(parser):
283283
'--wokwi-scenario',
284284
help='Path to the wokwi scenario file (Default: None)',
285285
)
286+
wokwi_group.addoption(
287+
'--wokwi-diagram',
288+
help='Path to the wokwi diagram file (Default: None)',
289+
)
286290

287291

288292
###########
@@ -973,6 +977,13 @@ def wokwi_scenario(request: FixtureRequest) -> t.Optional[str]:
973977
return _request_param_or_config_option_or_default(request, 'wokwi_scenario', None)
974978

975979

980+
@pytest.fixture
981+
@multi_dut_argument
982+
def wokwi_diagram(request: FixtureRequest) -> t.Optional[str]:
983+
"""Enable parametrization for the same cli option"""
984+
return _request_param_or_config_option_or_default(request, 'wokwi_diagram', None)
985+
986+
976987
####################
977988
# Private Fixtures #
978989
####################
@@ -1031,6 +1042,7 @@ def parametrize_fixtures(
10311042
wokwi_cli_path,
10321043
wokwi_timeout,
10331044
wokwi_scenario,
1045+
wokwi_diagram,
10341046
skip_regenerate_image,
10351047
encrypt,
10361048
keyfile,

0 commit comments

Comments
 (0)