pgntui 0.2.1__tar.gz → 0.2.2__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 (98) hide show
  1. {pgntui-0.2.1 → pgntui-0.2.2}/PKG-INFO +1 -1
  2. {pgntui-0.2.1 → pgntui-0.2.2}/packaging/homebrew/pgntui.rb +1 -1
  3. {pgntui-0.2.1 → pgntui-0.2.2}/packaging/winget/phobic.pgntui.yaml +2 -2
  4. {pgntui-0.2.1 → pgntui-0.2.2}/pyproject.toml +4 -1
  5. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/__init__.py +1 -1
  6. pgntui-0.2.2/src/pgntui/examples/containers/main.json +14 -0
  7. pgntui-0.2.2/src/pgntui/examples/signals/anchor_light.json +12 -0
  8. pgntui-0.2.2/src/pgntui/examples/signals/bilge_alarm.json +10 -0
  9. pgntui-0.2.2/src/pgntui/examples/signals/target_heading.json +14 -0
  10. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_example_workspace.py +25 -3
  11. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_signals_loader.py +21 -11
  12. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_smoke.py +1 -1
  13. pgntui-0.2.1/src/pgntui/examples/containers/main.json +0 -11
  14. {pgntui-0.2.1 → pgntui-0.2.2}/.github/workflows/ci.yml +0 -0
  15. {pgntui-0.2.1 → pgntui-0.2.2}/.github/workflows/release.yml +0 -0
  16. {pgntui-0.2.1 → pgntui-0.2.2}/.gitignore +0 -0
  17. {pgntui-0.2.1 → pgntui-0.2.2}/LICENSE +0 -0
  18. {pgntui-0.2.1 → pgntui-0.2.2}/README.md +0 -0
  19. {pgntui-0.2.1 → pgntui-0.2.2}/docs/superpowers/plans/2026-06-04-pgntui-implementation.md +0 -0
  20. {pgntui-0.2.1 → pgntui-0.2.2}/docs/superpowers/specs/2026-06-04-pgntui-design.md +0 -0
  21. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/__main__.py +0 -0
  22. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/app.py +0 -0
  23. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/config.py +0 -0
  24. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/containers/__init__.py +0 -0
  25. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/containers/loader.py +0 -0
  26. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/containers/screen.py +0 -0
  27. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/debug/__init__.py +0 -0
  28. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/debug/tab.py +0 -0
  29. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/decode/__init__.py +0 -0
  30. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/decode/canboat.py +0 -0
  31. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/decode/pgns.json +0 -0
  32. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/decode/router.py +0 -0
  33. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/drivers/__init__.py +0 -0
  34. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/drivers/actisense.py +0 -0
  35. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/drivers/base.py +0 -0
  36. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/drivers/replay.py +0 -0
  37. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/examples/__init__.py +0 -0
  38. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/examples/config.toml +0 -0
  39. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/examples/signals/depth.json +0 -0
  40. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/examples/signals/engine_rpm.json +0 -0
  41. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/examples/signals/speed.json +0 -0
  42. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/examples/signals/water_temp.json +0 -0
  43. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/logging/__init__.py +0 -0
  44. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/logging/csv.py +0 -0
  45. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/recording/__init__.py +0 -0
  46. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/recording/reader.py +0 -0
  47. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/recording/writer.py +0 -0
  48. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/replay_mode.py +0 -0
  49. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/signals/__init__.py +0 -0
  50. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/signals/base.py +0 -0
  51. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/signals/widgets.py +0 -0
  52. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/themes/__init__.py +0 -0
  53. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/themes/builtin/__init__.py +0 -0
  54. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/themes/builtin/amber-crt.json +0 -0
  55. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/themes/builtin/dark.json +0 -0
  56. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/themes/builtin/green-phosphor.json +0 -0
  57. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/themes/builtin/light.json +0 -0
  58. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/themes/builtin/mono-ascii.json +0 -0
  59. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/themes/builtin/rainbow-disco.json +0 -0
  60. {pgntui-0.2.1 → pgntui-0.2.2}/src/pgntui/themes/loader.py +0 -0
  61. {pgntui-0.2.1 → pgntui-0.2.2}/tests/__init__.py +0 -0
  62. {pgntui-0.2.1 → pgntui-0.2.2}/tests/fixtures/__init__.py +0 -0
  63. {pgntui-0.2.1 → pgntui-0.2.2}/tests/fixtures/e2e_containers/engine.json +0 -0
  64. {pgntui-0.2.1 → pgntui-0.2.2}/tests/fixtures/e2e_containers/nav.json +0 -0
  65. {pgntui-0.2.1 → pgntui-0.2.2}/tests/fixtures/e2e_session.pgnlog +0 -0
  66. {pgntui-0.2.1 → pgntui-0.2.2}/tests/fixtures/e2e_signals/engine_rpm.json +0 -0
  67. {pgntui-0.2.1 → pgntui-0.2.2}/tests/fixtures/e2e_signals/wind_speed.json +0 -0
  68. {pgntui-0.2.1 → pgntui-0.2.2}/tests/fixtures/frames.py +0 -0
  69. {pgntui-0.2.1 → pgntui-0.2.2}/tests/fixtures/sample.pgnlog +0 -0
  70. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_actisense_driver.py +0 -0
  71. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_app_empty_welcome.py +0 -0
  72. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_app_frame_loop.py +0 -0
  73. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_app_on_write.py +0 -0
  74. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_app_quit_binding.py +0 -0
  75. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_app_record_toggle.py +0 -0
  76. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_app_shell.py +0 -0
  77. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_builtin_themes.py +0 -0
  78. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_canboat.py +0 -0
  79. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_cli.py +0 -0
  80. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_config.py +0 -0
  81. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_container_screen.py +0 -0
  82. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_containers_loader.py +0 -0
  83. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_csv_logger.py +0 -0
  84. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_debug_tab.py +0 -0
  85. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_drivers_base.py +0 -0
  86. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_e2e_replay.py +0 -0
  87. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_main_replay.py +0 -0
  88. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_packaging.py +0 -0
  89. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_recording_writer.py +0 -0
  90. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_replay_driver.py +0 -0
  91. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_replay_mode.py +0 -0
  92. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_router.py +0 -0
  93. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_signals_base.py +0 -0
  94. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_themes_loader.py +0 -0
  95. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_widgets_analog_in.py +0 -0
  96. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_widgets_analog_out.py +0 -0
  97. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_widgets_digital_in.py +0 -0
  98. {pgntui-0.2.1 → pgntui-0.2.2}/tests/test_widgets_digital_out.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pgntui
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Cross-platform TUI for NMEA 2000 with canboat decoding and pluggable drivers
5
5
  Author: phobicdotno
6
6
  License: MIT License
@@ -3,7 +3,7 @@
3
3
  class Pgntui < Formula
4
4
  desc "Cross-platform TUI for NMEA 2000 with canboat decoding"
5
5
  homepage "https://github.com/phobicdotno/pgntui"
6
- url "https://files.pythonhosted.org/packages/source/p/pgntui/pgntui-0.2.1.tar.gz"
6
+ url "https://files.pythonhosted.org/packages/source/p/pgntui/pgntui-0.2.2.tar.gz"
7
7
  sha256 "REPLACE_ON_RELEASE"
8
8
  license "MIT"
9
9
 
@@ -1,6 +1,6 @@
1
1
  # Stub manifest for microsoft/winget-pkgs PR
2
2
  PackageIdentifier: phobic.pgntui
3
- PackageVersion: 0.2.1
3
+ PackageVersion: 0.2.2
4
4
  PackageLocale: en-US
5
5
  Publisher: phobic
6
6
  PackageName: pgntui
@@ -15,7 +15,7 @@ Tags: [nmea, marine, tui, terminal]
15
15
  Installers:
16
16
  - Architecture: x64
17
17
  InstallerType: portable
18
- InstallerUrl: https://github.com/phobicdotno/pgntui/releases/download/v0.2.1/pgntui-windows-x86_64.exe
18
+ InstallerUrl: https://github.com/phobicdotno/pgntui/releases/download/v0.2.2/pgntui-windows-x86_64.exe
19
19
  InstallerSha256: REPLACE_ON_RELEASE
20
20
  ManifestType: singleton
21
21
  ManifestVersion: 1.6.0
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pgntui"
7
- version = "0.2.1"
7
+ version = "0.2.2"
8
8
  description = "Cross-platform TUI for NMEA 2000 with canboat decoding and pluggable drivers"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -64,6 +64,9 @@ packages = ["src/pgntui"]
64
64
  "src/pgntui/examples/signals/speed.json" = "pgntui/examples/signals/speed.json"
65
65
  "src/pgntui/examples/signals/depth.json" = "pgntui/examples/signals/depth.json"
66
66
  "src/pgntui/examples/signals/water_temp.json" = "pgntui/examples/signals/water_temp.json"
67
+ "src/pgntui/examples/signals/target_heading.json" = "pgntui/examples/signals/target_heading.json"
68
+ "src/pgntui/examples/signals/bilge_alarm.json" = "pgntui/examples/signals/bilge_alarm.json"
69
+ "src/pgntui/examples/signals/anchor_light.json" = "pgntui/examples/signals/anchor_light.json"
67
70
 
68
71
  [tool.ruff]
69
72
  line-length = 100
@@ -1,3 +1,3 @@
1
1
  """pgntui — NMEA 2000 TUI."""
2
2
 
3
- __version__ = "0.2.1"
3
+ __version__ = "0.2.2"
@@ -0,0 +1,14 @@
1
+ {
2
+ "id": "main",
3
+ "title": "Main",
4
+ "cols": 12,
5
+ "signals": [
6
+ {"ref": "engine_rpm", "row": 0, "col": 0, "w": 3},
7
+ {"ref": "speed", "row": 0, "col": 3, "w": 3},
8
+ {"ref": "depth", "row": 0, "col": 6, "w": 3},
9
+ {"ref": "water_temp", "row": 0, "col": 9, "w": 3},
10
+ {"ref": "target_heading", "row": 1, "col": 0, "w": 12},
11
+ {"ref": "bilge_alarm", "row": 2, "col": 0, "w": 6},
12
+ {"ref": "anchor_light", "row": 2, "col": 6, "w": 6}
13
+ ]
14
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "id": "anchor_light",
3
+ "type": "digital_out",
4
+ "title": "Anchor Light",
5
+ "pgn": 127502,
6
+ "field": "Switch1",
7
+ "on_label": "ON",
8
+ "off_label": "OFF",
9
+ "write_pgn": 127502,
10
+ "write_field": "Switch1",
11
+ "log": false
12
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "id": "bilge_alarm",
3
+ "type": "digital_in",
4
+ "title": "Bilge Alarm",
5
+ "pgn": 127501,
6
+ "field": "Indicator1",
7
+ "on_label": "WET",
8
+ "off_label": "DRY",
9
+ "log": true
10
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "id": "target_heading",
3
+ "type": "analog_out",
4
+ "title": "Target Heading",
5
+ "unit": "rad",
6
+ "pgn": 65360,
7
+ "field": "Target Heading Magnetic",
8
+ "min": 0,
9
+ "max": 6.2832,
10
+ "decimals": 2,
11
+ "write_pgn": 65360,
12
+ "write_field": "Target Heading Magnetic",
13
+ "log": false
14
+ }
@@ -6,7 +6,7 @@ from pathlib import Path
6
6
 
7
7
  from pgntui.__main__ import main
8
8
  from pgntui.containers.loader import load_container
9
- from pgntui.signals.base import load_signals_dir
9
+ from pgntui.signals.base import AnalogIn, AnalogOut, DigitalIn, DigitalOut, load_signals_dir
10
10
 
11
11
 
12
12
  def test_example_creates_expected_files(tmp_path: Path) -> None:
@@ -18,8 +18,17 @@ def test_example_creates_expected_files(tmp_path: Path) -> None:
18
18
  assert (ws / "containers").is_dir()
19
19
  signals = load_signals_dir(ws / "signals")
20
20
  ids = {s.id for s in signals}
21
- # We ship four sensible defaults.
22
- assert ids == {"engine_rpm", "speed", "depth", "water_temp"}
21
+ # Seven shipped defaults: four analog readouts plus one of each remaining
22
+ # widget kind so the scaffold exercises the full UI surface.
23
+ assert ids == {
24
+ "engine_rpm",
25
+ "speed",
26
+ "depth",
27
+ "water_temp",
28
+ "target_heading",
29
+ "bilge_alarm",
30
+ "anchor_light",
31
+ }
23
32
  # Containers reference signal ids that exist.
24
33
  main_container = load_container(ws / "containers" / "main.json", ids)
25
34
  refs = {p.ref for p in main_container.signals}
@@ -27,6 +36,19 @@ def test_example_creates_expected_files(tmp_path: Path) -> None:
27
36
  assert main_container.cols == 12
28
37
 
29
38
 
39
+ def test_example_includes_all_four_widget_types(tmp_path: Path) -> None:
40
+ """Scaffolded workspace must contain at least one signal of each kind."""
41
+ ws = tmp_path / "ws"
42
+ rc = main(["--workspace", str(ws), "--example"])
43
+ assert rc == 0
44
+ signals = load_signals_dir(ws / "signals")
45
+ kinds = {type(s) for s in signals}
46
+ assert AnalogIn in kinds
47
+ assert AnalogOut in kinds
48
+ assert DigitalIn in kinds
49
+ assert DigitalOut in kinds
50
+
51
+
30
52
  def test_example_refuses_when_workspace_non_empty(tmp_path: Path, capsys) -> None: # type: ignore[no-untyped-def]
31
53
  ws = tmp_path / "ws"
32
54
  ws.mkdir()
@@ -6,28 +6,38 @@ from importlib import resources
6
6
 
7
7
  import pytest
8
8
 
9
- from pgntui.signals.base import AnalogIn, AnalogOut, DigitalIn, DigitalOut, load_signal
9
+ from pgntui.signals.base import AnalogIn, AnalogOut, DigitalIn, DigitalOut, Signal, load_signal
10
10
 
11
+ _EXAMPLE_EXPECTED: dict[str, type[Signal]] = {
12
+ "engine_rpm": AnalogIn,
13
+ "speed": AnalogIn,
14
+ "depth": AnalogIn,
15
+ "water_temp": AnalogIn,
16
+ "target_heading": AnalogOut,
17
+ "bilge_alarm": DigitalIn,
18
+ "anchor_light": DigitalOut,
19
+ }
11
20
 
12
- @pytest.mark.parametrize(
13
- "name",
14
- ["engine_rpm", "speed", "depth", "water_temp"],
15
- )
21
+
22
+ @pytest.mark.parametrize("name", sorted(_EXAMPLE_EXPECTED))
16
23
  def test_each_example_signal_loads(name: str, tmp_path) -> None: # type: ignore[no-untyped-def]
17
- """Every bundled signal JSON parses into a real Signal subclass."""
24
+ """Every bundled signal JSON parses into the expected Signal subclass."""
18
25
  src = resources.files("pgntui.examples.signals").joinpath(f"{name}.json")
19
26
  target = tmp_path / f"{name}.json"
20
27
  with src.open("rb") as fh:
21
28
  target.write_bytes(fh.read())
22
29
  sig = load_signal(target)
23
- # The 4 bundled signals are all analog_in dashboards. If we ever ship a
24
- # digital example, extend this assertion.
25
- assert isinstance(sig, AnalogIn)
30
+ assert isinstance(sig, _EXAMPLE_EXPECTED[name])
26
31
  assert sig.id == name
27
32
  assert sig.pgn > 0
28
33
  assert sig.field
29
- assert sig.min < sig.max
30
- assert sig.smoothing >= 0
34
+ if isinstance(sig, AnalogIn | AnalogOut):
35
+ assert sig.min < sig.max
36
+ if isinstance(sig, AnalogIn):
37
+ assert sig.smoothing >= 0
38
+ if isinstance(sig, AnalogOut | DigitalOut):
39
+ assert sig.write_pgn > 0
40
+ assert sig.write_field
31
41
 
32
42
 
33
43
  def test_signal_load_round_trip_all_types(tmp_path) -> None: # type: ignore[no-untyped-def]
@@ -2,7 +2,7 @@ from pgntui import __version__
2
2
 
3
3
 
4
4
  def test_version() -> None:
5
- assert __version__ == "0.2.1"
5
+ assert __version__ == "0.2.2"
6
6
 
7
7
 
8
8
  def test_main_returns_zero() -> None:
@@ -1,11 +0,0 @@
1
- {
2
- "id": "main",
3
- "title": "Main",
4
- "cols": 12,
5
- "signals": [
6
- {"ref": "engine_rpm", "row": 0, "col": 0, "w": 6},
7
- {"ref": "speed", "row": 0, "col": 6, "w": 6},
8
- {"ref": "depth", "row": 1, "col": 0, "w": 6},
9
- {"ref": "water_temp", "row": 1, "col": 6, "w": 6}
10
- ]
11
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes