lr-lumenlabel-cli 3.0.0__tar.gz → 3.0.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 (62) hide show
  1. {lr_lumenlabel_cli-3.0.0/src/lr_lumenlabel_cli.egg-info → lr_lumenlabel_cli-3.0.2}/PKG-INFO +1 -1
  2. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/lumenlabel.spec +2 -0
  3. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2/src/lr_lumenlabel_cli.egg-info}/PKG-INFO +1 -1
  4. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/_version.py +2 -2
  5. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/build_words.py +14 -3
  6. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/commands/label.py +1 -1
  7. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/config_rules.py +1 -1
  8. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_build_words.py +10 -5
  9. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/LICENSE +0 -0
  10. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/Makefile +0 -0
  11. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/README.md +0 -0
  12. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/pyproject.toml +0 -0
  13. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/setup.cfg +0 -0
  14. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lr_lumenlabel_cli.egg-info/SOURCES.txt +0 -0
  15. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lr_lumenlabel_cli.egg-info/dependency_links.txt +0 -0
  16. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lr_lumenlabel_cli.egg-info/entry_points.txt +0 -0
  17. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lr_lumenlabel_cli.egg-info/requires.txt +0 -0
  18. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lr_lumenlabel_cli.egg-info/scm_file_list.json +0 -0
  19. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lr_lumenlabel_cli.egg-info/top_level.txt +0 -0
  20. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/__init__.py +0 -0
  21. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/__main__.py +0 -0
  22. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/cli.py +0 -0
  23. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/client.py +0 -0
  24. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/commands/__init__.py +0 -0
  25. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/commands/api.py +0 -0
  26. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/commands/auth.py +0 -0
  27. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/commands/station.py +0 -0
  28. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/config.py +0 -0
  29. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/importer.py +0 -0
  30. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/manifest_gen.py +0 -0
  31. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/media_check.py +0 -0
  32. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/package.py +0 -0
  33. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/shared.py +0 -0
  34. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/src/lumenlabel/wordlist/bip39-english.txt +0 -0
  35. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/conftest.py +0 -0
  36. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1114-arena/.arena.json +0 -0
  37. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1114-arena/109-1114 109-1115 v5.pdf +0 -0
  38. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1135/.arena.json +0 -0
  39. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1135/109-1135.txt +0 -0
  40. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1135/111-1002/.arena.json +0 -0
  41. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1135/Galileo MAX box label.pdf +0 -0
  42. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1135/Galileo MAX.nlbl +0 -0
  43. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1135/configuration.json +0 -0
  44. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1182/.arena.json +0 -0
  45. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1182/109-1182.txt +0 -0
  46. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1182/Reel label_TiMo_2021_.pdf +0 -0
  47. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1182/configuration.json +0 -0
  48. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1183/.arena.json +0 -0
  49. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1183/109-1183.txt +0 -0
  50. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1183/800-8203_MWA-N2.nlbl +0 -0
  51. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1183/800-8203_MWA-N2_Landscape.nlbl +0 -0
  52. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1183/Reel label_TimoTwo .pdf +0 -0
  53. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/fixtures/109-1183/configuration.json +0 -0
  54. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_client.py +0 -0
  55. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_config_rules.py +0 -0
  56. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_label_commands.py +0 -0
  57. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_manifest_gen.py +0 -0
  58. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_media_check.py +0 -0
  59. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_other_commands.py +0 -0
  60. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_package.py +0 -0
  61. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_real_sidecar.py +0 -0
  62. {lr_lumenlabel_cli-3.0.0 → lr_lumenlabel_cli-3.0.2}/tests/test_station_data_dir.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lr-lumenlabel-cli
3
- Version: 3.0.0
3
+ Version: 3.0.2
4
4
  Summary: CLI for the LumenRadio LumenLabel label printing station: import label packages fetched from Arena with gladiator, list labels and inspect the station, locally, on the LAN or through the Fleet relay.
5
5
  Author-email: Jonas Estberger <jonas.estberger@lumenradio.com>
6
6
  License-Expression: MIT
@@ -30,6 +30,8 @@ exe = EXE(
30
30
  a.datas,
31
31
  [],
32
32
  name="lumenlabel",
33
+ # Windows Explorer icon of the .exe; the GUI's icon, so both look alike.
34
+ icon="../src/img/LR_icon.ico",
33
35
  debug=False,
34
36
  bootloader_ignore_signals=False,
35
37
  strip=False,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lr-lumenlabel-cli
3
- Version: 3.0.0
3
+ Version: 3.0.2
4
4
  Summary: CLI for the LumenRadio LumenLabel label printing station: import label packages fetched from Arena with gladiator, list labels and inspect the station, locally, on the LAN or through the Fleet relay.
5
5
  Author-email: Jonas Estberger <jonas.estberger@lumenradio.com>
6
6
  License-Expression: MIT
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '3.0.0'
22
- __version_tuple__ = version_tuple = (3, 0, 0)
21
+ __version__ = version = '3.0.2'
22
+ __version_tuple__ = version_tuple = (3, 0, 2)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -40,7 +40,7 @@ def _load_wordlist(path: Path) -> tuple[str, ...]:
40
40
 
41
41
  _WORDLIST: tuple[str, ...] = _load_wordlist(WORDLIST_PATH)
42
42
 
43
- __all__ = ["BUILD_WORDS_COUNT", "content_digest", "build_words"]
43
+ __all__ = ["BUILD_WORDS_COUNT", "content_digest", "label_digest", "build_words"]
44
44
 
45
45
 
46
46
  def _canonical_entry(entry: Any) -> dict[str, Any]:
@@ -70,6 +70,17 @@ def words_from_digest(digest: str) -> str:
70
70
  return f"{_WORDLIST[value >> _BITS_PER_WORD]} {_WORDLIST[value & 0x7FF]}"
71
71
 
72
72
 
73
+ def label_digest(files: Iterable[Any]) -> str:
74
+ """:func:`content_digest` of *files* with every ``title`` as null.
75
+
76
+ LumenLabel leaves the file title out of Build Words (§6.1): it
77
+ controls nothing on the station, and a 2.x label folder has no record
78
+ of it, so the station can fingerprint an unmanaged label from its files
79
+ alone (LUL-106).
80
+ """
81
+ return content_digest({**_canonical_entry(f), "title": None} for f in files)
82
+
83
+
73
84
  def build_words(files: Iterable[Any]) -> str:
74
- """Two BIP39 words for *files*. The manifest header is not hashed."""
75
- return words_from_digest(content_digest(files))
85
+ """Two BIP39 words for *files*. The manifest header and titles are not hashed."""
86
+ return words_from_digest(label_digest(files))
@@ -226,7 +226,7 @@ def list_labels(ctx: typer.Context, output: OutputFormat = output_option()) -> N
226
226
  table.add_row(
227
227
  label["article"],
228
228
  label.get("revision") or "-",
229
- label.get("build_words") or "local",
229
+ label.get("build_words") or "-",
230
230
  _media_text(label.get("media_article"), label.get("media_name")),
231
231
  label.get("name") or label.get("product") or "",
232
232
  _state(label),
@@ -62,7 +62,7 @@ def _box_quantity(config: dict[str, Any]) -> int | None:
62
62
  def _fields_problem(
63
63
  config: dict[str, Any], labeltype: str, quantity: int | None
64
64
  ) -> str | None:
65
- for key in ("product", "article", "serial_field"):
65
+ for key in ("product", "serial_field"):
66
66
  if not str(config.get(key, "")):
67
67
  return f"{key} is required"
68
68
  if labeltype == "pcba" and not config.get("serial_source"):
@@ -68,17 +68,21 @@ LABEL_109_1182_A2 = [
68
68
  def test_lumentest_golden_vector():
69
69
  digest = cli_words.content_digest(GOLDEN)
70
70
  assert digest == "791a3dbf367bab0d9ccfe024ba3c015b7c575a13490a418f312e9ba77f2c00b1"
71
- assert cli_words.build_words(GOLDEN) == "jungle spin"
71
+ assert cli_words.words_from_digest(digest) == "jungle spin"
72
72
 
73
73
 
74
- def test_109_1182_rev_a2_is_usual_hammer():
74
+ def test_109_1182_rev_a2_is_person_chat():
75
75
  digest = cli_words.content_digest(LABEL_109_1182_A2)
76
76
  assert digest == "f02d12a2623371989ecc41106e6d3fd5eb6b99134f13b2d20671b72ad508186a"
77
- assert cli_words.build_words(LABEL_109_1182_A2) == "usual hammer"
77
+ digest = cli_words.label_digest(LABEL_109_1182_A2)
78
+ assert digest == "a344da3d2001fa9e7e62db47edfbff9ee26721ebaec1999181f0f431dc67f1ae"
79
+ assert cli_words.build_words(LABEL_109_1182_A2) == "person chat"
78
80
 
79
81
 
80
- def test_order_and_header_do_not_matter():
81
- assert cli_words.build_words(reversed(LABEL_109_1182_A2)) == "usual hammer"
82
+ def test_order_header_and_titles_do_not_matter():
83
+ assert cli_words.build_words(reversed(LABEL_109_1182_A2)) == "person chat"
84
+ untitled = [{k: v for k, v in f.items() if k != "title"} for f in LABEL_109_1182_A2]
85
+ assert cli_words.build_words(untitled) == "person chat"
82
86
 
83
87
 
84
88
  @pytest.fixture(scope="module")
@@ -114,6 +118,7 @@ def test_cli_and_station_give_the_same_words(station_words):
114
118
  rng = random.Random(93)
115
119
  for vector in (GOLDEN, LABEL_109_1182_A2):
116
120
  assert cli_words.content_digest(vector) == station_words.content_digest(vector)
121
+ assert cli_words.label_digest(vector) == station_words.label_digest(vector)
117
122
  for _ in range(500):
118
123
  files = _random_files(rng)
119
124
  assert cli_words.build_words(files) == station_words.build_words(files)