lr-lumenlabel-cli 3.0.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.
- lr_lumenlabel_cli-3.0.0/LICENSE +21 -0
- lr_lumenlabel_cli-3.0.0/Makefile +98 -0
- lr_lumenlabel_cli-3.0.0/PKG-INFO +121 -0
- lr_lumenlabel_cli-3.0.0/README.md +90 -0
- lr_lumenlabel_cli-3.0.0/lumenlabel.spec +45 -0
- lr_lumenlabel_cli-3.0.0/pyproject.toml +87 -0
- lr_lumenlabel_cli-3.0.0/setup.cfg +4 -0
- lr_lumenlabel_cli-3.0.0/src/lr_lumenlabel_cli.egg-info/PKG-INFO +121 -0
- lr_lumenlabel_cli-3.0.0/src/lr_lumenlabel_cli.egg-info/SOURCES.txt +60 -0
- lr_lumenlabel_cli-3.0.0/src/lr_lumenlabel_cli.egg-info/dependency_links.txt +1 -0
- lr_lumenlabel_cli-3.0.0/src/lr_lumenlabel_cli.egg-info/entry_points.txt +2 -0
- lr_lumenlabel_cli-3.0.0/src/lr_lumenlabel_cli.egg-info/requires.txt +15 -0
- lr_lumenlabel_cli-3.0.0/src/lr_lumenlabel_cli.egg-info/scm_file_list.json +56 -0
- lr_lumenlabel_cli-3.0.0/src/lr_lumenlabel_cli.egg-info/top_level.txt +1 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/__init__.py +6 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/__main__.py +3 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/_version.py +24 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/build_words.py +75 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/cli.py +60 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/client.py +362 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/commands/__init__.py +1 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/commands/api.py +64 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/commands/auth.py +59 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/commands/label.py +253 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/commands/station.py +105 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/config.py +132 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/config_rules.py +92 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/importer.py +47 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/manifest_gen.py +232 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/media_check.py +73 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/package.py +294 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/shared.py +131 -0
- lr_lumenlabel_cli-3.0.0/src/lumenlabel/wordlist/bip39-english.txt +2048 -0
- lr_lumenlabel_cli-3.0.0/tests/conftest.py +238 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1114-arena/.arena.json +35 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1114-arena/109-1114 109-1115 v5.pdf +0 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1135/.arena.json +53 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1135/109-1135.txt +4 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1135/111-1002/.arena.json +12 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1135/Galileo MAX box label.pdf +3 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1135/Galileo MAX.nlbl +1 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1135/configuration.json +12 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1182/.arena.json +43 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1182/109-1182.txt +4 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1182/Reel label_TiMo_2021_.pdf +3 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1182/configuration.json +12 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1183/.arena.json +63 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1183/109-1183.txt +4 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1183/800-8203_MWA-N2.nlbl +1 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1183/800-8203_MWA-N2_Landscape.nlbl +1 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1183/Reel label_TimoTwo .pdf +3 -0
- lr_lumenlabel_cli-3.0.0/tests/fixtures/109-1183/configuration.json +12 -0
- lr_lumenlabel_cli-3.0.0/tests/test_build_words.py +119 -0
- lr_lumenlabel_cli-3.0.0/tests/test_client.py +237 -0
- lr_lumenlabel_cli-3.0.0/tests/test_config_rules.py +79 -0
- lr_lumenlabel_cli-3.0.0/tests/test_label_commands.py +190 -0
- lr_lumenlabel_cli-3.0.0/tests/test_manifest_gen.py +192 -0
- lr_lumenlabel_cli-3.0.0/tests/test_media_check.py +98 -0
- lr_lumenlabel_cli-3.0.0/tests/test_other_commands.py +199 -0
- lr_lumenlabel_cli-3.0.0/tests/test_package.py +184 -0
- lr_lumenlabel_cli-3.0.0/tests/test_real_sidecar.py +32 -0
- lr_lumenlabel_cli-3.0.0/tests/test_station_data_dir.py +70 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LumenRadio AB
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
VENV := .venv
|
|
2
|
+
PY := $(VENV)/bin/python
|
|
3
|
+
PIP := $(VENV)/bin/pip
|
|
4
|
+
|
|
5
|
+
# setuptools_scm version, resolved on the host. Passed in through
|
|
6
|
+
# SETUPTOOLS_SCM_PRETEND_VERSION_FOR_* so the sdist build skips the VCS file
|
|
7
|
+
# finder (root=".." would pull in the whole repository) and builds without
|
|
8
|
+
# git (the containers) get it too.
|
|
9
|
+
DIST_ENV := SETUPTOOLS_SCM_PRETEND_VERSION_FOR_LR_LUMENLABEL_CLI
|
|
10
|
+
SCM_VERSION ?= $(shell $(PY) -m setuptools_scm 2>/dev/null)
|
|
11
|
+
|
|
12
|
+
# dist/ also holds the PyInstaller binary; only these are PyPI distributions.
|
|
13
|
+
DIST_FILES := dist/*.whl dist/*.tar.gz
|
|
14
|
+
|
|
15
|
+
PYPI_REPOSITORY ?= https://upload.pypi.org/legacy/
|
|
16
|
+
TEST_PYPI_REPOSITORY ?= https://test.pypi.org/legacy/
|
|
17
|
+
|
|
18
|
+
# PyPI keeps every version number forever and rejects a local (+...) segment,
|
|
19
|
+
# so an upload is refused unless the version is a clean lumenlabel-X.Y.Z tag.
|
|
20
|
+
CHECK_RELEASE_VERSION = case "$(SCM_VERSION)" in *dev*|*+*|"") echo "error: refusing to upload '$(SCM_VERSION)': build from a clean 'lumenlabel-X.Y.Z' tag"; exit 2 ;; esac
|
|
21
|
+
|
|
22
|
+
.DEFAULT_GOAL := install
|
|
23
|
+
|
|
24
|
+
.PHONY: install dev test test-only dist check publish publish-test clean package build-linux-docker build-windows-docker
|
|
25
|
+
|
|
26
|
+
$(VENV)/bin/activate:
|
|
27
|
+
python3.12 -m venv $(VENV)
|
|
28
|
+
$(PIP) install --upgrade pip
|
|
29
|
+
|
|
30
|
+
install: $(VENV)/bin/activate
|
|
31
|
+
$(PIP) install .
|
|
32
|
+
|
|
33
|
+
dev: $(VENV)/bin/activate
|
|
34
|
+
$(PIP) install -e ".[dev,package]"
|
|
35
|
+
|
|
36
|
+
test: dev test-only
|
|
37
|
+
|
|
38
|
+
test-only:
|
|
39
|
+
$(VENV)/bin/pytest \
|
|
40
|
+
--cov=lumenlabel \
|
|
41
|
+
--cov-report=term-missing \
|
|
42
|
+
--junit-xml=build/reports/junit.xml \
|
|
43
|
+
tests/
|
|
44
|
+
|
|
45
|
+
# Clearing the previous sdist and wheel keeps $(DIST_FILES) to this build.
|
|
46
|
+
dist: dev
|
|
47
|
+
rm -f dist/*.whl dist/*.tar.gz
|
|
48
|
+
$(DIST_ENV)="$(SCM_VERSION)" $(PY) -m build
|
|
49
|
+
|
|
50
|
+
check: dist
|
|
51
|
+
$(VENV)/bin/twine check $(DIST_FILES)
|
|
52
|
+
|
|
53
|
+
# twine reads TWINE_USERNAME/TWINE_PASSWORD itself, so the token never shows
|
|
54
|
+
# in the echoed recipe or in the upload's argv.
|
|
55
|
+
publish-test: check
|
|
56
|
+
@$(CHECK_RELEASE_VERSION)
|
|
57
|
+
@if [ -z "$$TEST_PYPI_TOKEN" ]; then echo "error: TEST_PYPI_TOKEN is required"; exit 2; fi
|
|
58
|
+
@TWINE_USERNAME=__token__ TWINE_PASSWORD="$$TEST_PYPI_TOKEN" $(VENV)/bin/twine upload --repository-url $(TEST_PYPI_REPOSITORY) $(DIST_FILES)
|
|
59
|
+
|
|
60
|
+
publish: check
|
|
61
|
+
@$(CHECK_RELEASE_VERSION)
|
|
62
|
+
@if [ -z "$$PYPI_TOKEN" ]; then echo "error: PYPI_TOKEN is required"; exit 2; fi
|
|
63
|
+
@TWINE_USERNAME=__token__ TWINE_PASSWORD="$$PYPI_TOKEN" $(VENV)/bin/twine upload --repository-url $(PYPI_REPOSITORY) $(DIST_FILES)
|
|
64
|
+
|
|
65
|
+
clean:
|
|
66
|
+
rm -rf $(VENV) dist/ build/ .coverage
|
|
67
|
+
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null; true
|
|
68
|
+
find . -name "*.egg-info" -type d -exec rm -rf {} + 2>/dev/null; true
|
|
69
|
+
|
|
70
|
+
# dist/lumenlabel for this host.
|
|
71
|
+
package: dev
|
|
72
|
+
$(VENV)/bin/pyinstaller -y lumenlabel.spec
|
|
73
|
+
|
|
74
|
+
# dist/lumenlabel in python:3.12-slim-bookworm, the image of the app's build-linux
|
|
75
|
+
# job. Debian 12 sets the glibc floor of the .deb (packaging/deb/README.md).
|
|
76
|
+
build-linux-docker: dev
|
|
77
|
+
docker run --rm \
|
|
78
|
+
-e $(DIST_ENV)="$(SCM_VERSION)" \
|
|
79
|
+
-v "$(CURDIR):/src" \
|
|
80
|
+
-w /src \
|
|
81
|
+
python:3.12-slim-bookworm \
|
|
82
|
+
bash -c "apt-get update -qq && apt-get install -y -qq --no-install-recommends binutils >/dev/null && \
|
|
83
|
+
python3 -m venv /build-venv && \
|
|
84
|
+
/build-venv/bin/pip install --no-cache-dir --upgrade pip setuptools wheel && \
|
|
85
|
+
/build-venv/bin/pip install --no-cache-dir -e '.[package]' && \
|
|
86
|
+
/build-venv/bin/pyinstaller -y lumenlabel.spec; \
|
|
87
|
+
rc=\$$?; chown -R $(shell id -u):$(shell id -g) build dist src 2>/dev/null; exit \$$rc"
|
|
88
|
+
|
|
89
|
+
# dist/lumenlabel.exe in the Wine image the app's Windows build uses.
|
|
90
|
+
build-windows-docker: dev
|
|
91
|
+
docker run --rm \
|
|
92
|
+
--entrypoint bash \
|
|
93
|
+
-e $(DIST_ENV)="$(SCM_VERSION)" \
|
|
94
|
+
-v "$(CURDIR):/src" \
|
|
95
|
+
-w /src \
|
|
96
|
+
batonogov/pyinstaller-windows:v5.0.0 \
|
|
97
|
+
-c "pip install --no-cache-dir --upgrade -e '.[package]' && pyinstaller -y lumenlabel.spec; \
|
|
98
|
+
rc=\$$?; chown -R $(shell id -u):$(shell id -g) build dist src 2>/dev/null; exit \$$rc"
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lr-lumenlabel-cli
|
|
3
|
+
Version: 3.0.0
|
|
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
|
+
Author-email: Jonas Estberger <jonas.estberger@lumenradio.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/lumenradio/production/lumenlabel
|
|
8
|
+
Project-URL: Changelog, https://gitlab.com/lumenradio/production/lumenlabel/-/blob/main/CHANGELOG.md
|
|
9
|
+
Keywords: LumenRadio,LumenLabel,label printing,Arena,CLI
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: typer>=0.12
|
|
18
|
+
Requires-Dist: rich>=13.7
|
|
19
|
+
Requires-Dist: httpx>=0.27
|
|
20
|
+
Requires-Dist: lr-fleet>=0.7
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: build>=1.2.1; extra == "dev"
|
|
23
|
+
Requires-Dist: twine>=6.1; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest>=8.4; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
26
|
+
Requires-Dist: black>=25.9; extra == "dev"
|
|
27
|
+
Requires-Dist: setuptools_scm>=8; extra == "dev"
|
|
28
|
+
Provides-Extra: package
|
|
29
|
+
Requires-Dist: pyinstaller==6.21.0; extra == "package"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# lr-lumenlabel-cli
|
|
33
|
+
|
|
34
|
+
The `lumenlabel` command for LumenRadio LumenLabel label printing stations.
|
|
35
|
+
It turns a label fetched from Arena with gladiator into a label package and
|
|
36
|
+
imports it into a station, locally, on the LAN or through the Fleet relay.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install lr-lumenlabel-cli
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The LumenLabel installers also put it on every station: the `.msi` as
|
|
45
|
+
`lumenlabel.exe` on the system `PATH`, the `.deb` as `/usr/bin/lumenlabel`.
|
|
46
|
+
There it imports from a USB stick without a network (airgapped mode).
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Fetch the label with its Arena metadata and BOM children
|
|
52
|
+
gladiator get-files 109-1182 --recursive --meta-data --out 109-1182
|
|
53
|
+
|
|
54
|
+
# Write the manifest and show Build Words and media warnings, offline
|
|
55
|
+
lumenlabel label import 109-1182 --dry-run
|
|
56
|
+
|
|
57
|
+
# Import into the LumenLabel running on this computer
|
|
58
|
+
lumenlabel label import 109-1182
|
|
59
|
+
|
|
60
|
+
# Or remember a station once, then import into it
|
|
61
|
+
lumenlabel login --station https://fleet.cloud.lumenradio.com/v1/s/<uid>
|
|
62
|
+
lumenlabel label import 109-1182
|
|
63
|
+
lumenlabel label list
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Commands
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
lumenlabel [--station URL] [--token TOKEN] COMMAND # global options first
|
|
70
|
+
|
|
71
|
+
lumenlabel login --station URL [--token TOKEN]
|
|
72
|
+
# Checks the station and remembers it, with its token, in
|
|
73
|
+
# ~/.config/lumenlabel/login.json (0600). Every later command then talks
|
|
74
|
+
# to that station as if it were the local one. --base-url is an alias of
|
|
75
|
+
# --station, as in lumentest.
|
|
76
|
+
lumenlabel logout
|
|
77
|
+
|
|
78
|
+
lumenlabel label import DIR [--dry-run] [--invalidate] [--output rich|json]
|
|
79
|
+
lumenlabel label list [--output rich|json]
|
|
80
|
+
lumenlabel label remove ARTICLE [--yes]
|
|
81
|
+
|
|
82
|
+
lumenlabel station [--output rich|json] # info
|
|
83
|
+
lumenlabel station history [--limit N] [--before ID]
|
|
84
|
+
lumenlabel station logs [--tail N]
|
|
85
|
+
|
|
86
|
+
lumenlabel api METHOD PATH [--data JSON|@FILE] # any /api/ endpoint
|
|
87
|
+
lumenlabel --version
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Which station
|
|
91
|
+
|
|
92
|
+
1. `--station URL` (alias `--base-url`), or `LUMENLABEL_STATION` /
|
|
93
|
+
`LUMENLABEL_URL`.
|
|
94
|
+
2. The station saved by `lumenlabel login`.
|
|
95
|
+
3. The LumenLabel on this computer, `http://127.0.0.1:<port>`. The port is
|
|
96
|
+
read from the station's `lumenlabel.json` (default 17081).
|
|
97
|
+
|
|
98
|
+
| URL | Authentication |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `https://<fleet>/v1/s/<uid>` (Fleet relay) | Your Fleet sign-in (`fleet login`; the first command opens the browser if needed) |
|
|
101
|
+
| `http://127.0.0.1:<port>` (on the station) | None |
|
|
102
|
+
| `http://<station>:<port>` (LAN, `instrumentation.host` `0.0.0.0` on the station) | The station token, shown in admin mode on the station |
|
|
103
|
+
|
|
104
|
+
## `label import`
|
|
105
|
+
|
|
106
|
+
- The manifest (`artifact-manifest.json`) is built from the `.arena.json`
|
|
107
|
+
sidecars gladiator writes with `--meta-data`. A folder with a manifest and no
|
|
108
|
+
sidecars is imported as it is.
|
|
109
|
+
- Private attachments (NiceLabel `.nlbl` sources), web links and BOM child
|
|
110
|
+
folders are left out. Only the declared files are uploaded.
|
|
111
|
+
- The media in `configuration.json` (`media_article`, `media_name`) is checked
|
|
112
|
+
against the BOM's 111 item. A mismatch is a warning; fix it with a new
|
|
113
|
+
revision in Arena. The CLI never changes `configuration.json`.
|
|
114
|
+
- A read-only folder (a write-protected USB stick) is imported through a
|
|
115
|
+
temporary copy.
|
|
116
|
+
- An interrupted import resumes: run it again and only the files that did not
|
|
117
|
+
arrive are sent. `--invalidate` discards what the station has staged.
|
|
118
|
+
- The output shows the revision, the Build Words, the media and any warnings.
|
|
119
|
+
|
|
120
|
+
Specification: `doc/label-package.md` and `doc/api-reference.md` in the
|
|
121
|
+
[LumenLabel repository](https://gitlab.com/lumenradio/production/lumenlabel).
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# lr-lumenlabel-cli
|
|
2
|
+
|
|
3
|
+
The `lumenlabel` command for LumenRadio LumenLabel label printing stations.
|
|
4
|
+
It turns a label fetched from Arena with gladiator into a label package and
|
|
5
|
+
imports it into a station, locally, on the LAN or through the Fleet relay.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install lr-lumenlabel-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The LumenLabel installers also put it on every station: the `.msi` as
|
|
14
|
+
`lumenlabel.exe` on the system `PATH`, the `.deb` as `/usr/bin/lumenlabel`.
|
|
15
|
+
There it imports from a USB stick without a network (airgapped mode).
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Fetch the label with its Arena metadata and BOM children
|
|
21
|
+
gladiator get-files 109-1182 --recursive --meta-data --out 109-1182
|
|
22
|
+
|
|
23
|
+
# Write the manifest and show Build Words and media warnings, offline
|
|
24
|
+
lumenlabel label import 109-1182 --dry-run
|
|
25
|
+
|
|
26
|
+
# Import into the LumenLabel running on this computer
|
|
27
|
+
lumenlabel label import 109-1182
|
|
28
|
+
|
|
29
|
+
# Or remember a station once, then import into it
|
|
30
|
+
lumenlabel login --station https://fleet.cloud.lumenradio.com/v1/s/<uid>
|
|
31
|
+
lumenlabel label import 109-1182
|
|
32
|
+
lumenlabel label list
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Commands
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
lumenlabel [--station URL] [--token TOKEN] COMMAND # global options first
|
|
39
|
+
|
|
40
|
+
lumenlabel login --station URL [--token TOKEN]
|
|
41
|
+
# Checks the station and remembers it, with its token, in
|
|
42
|
+
# ~/.config/lumenlabel/login.json (0600). Every later command then talks
|
|
43
|
+
# to that station as if it were the local one. --base-url is an alias of
|
|
44
|
+
# --station, as in lumentest.
|
|
45
|
+
lumenlabel logout
|
|
46
|
+
|
|
47
|
+
lumenlabel label import DIR [--dry-run] [--invalidate] [--output rich|json]
|
|
48
|
+
lumenlabel label list [--output rich|json]
|
|
49
|
+
lumenlabel label remove ARTICLE [--yes]
|
|
50
|
+
|
|
51
|
+
lumenlabel station [--output rich|json] # info
|
|
52
|
+
lumenlabel station history [--limit N] [--before ID]
|
|
53
|
+
lumenlabel station logs [--tail N]
|
|
54
|
+
|
|
55
|
+
lumenlabel api METHOD PATH [--data JSON|@FILE] # any /api/ endpoint
|
|
56
|
+
lumenlabel --version
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Which station
|
|
60
|
+
|
|
61
|
+
1. `--station URL` (alias `--base-url`), or `LUMENLABEL_STATION` /
|
|
62
|
+
`LUMENLABEL_URL`.
|
|
63
|
+
2. The station saved by `lumenlabel login`.
|
|
64
|
+
3. The LumenLabel on this computer, `http://127.0.0.1:<port>`. The port is
|
|
65
|
+
read from the station's `lumenlabel.json` (default 17081).
|
|
66
|
+
|
|
67
|
+
| URL | Authentication |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `https://<fleet>/v1/s/<uid>` (Fleet relay) | Your Fleet sign-in (`fleet login`; the first command opens the browser if needed) |
|
|
70
|
+
| `http://127.0.0.1:<port>` (on the station) | None |
|
|
71
|
+
| `http://<station>:<port>` (LAN, `instrumentation.host` `0.0.0.0` on the station) | The station token, shown in admin mode on the station |
|
|
72
|
+
|
|
73
|
+
## `label import`
|
|
74
|
+
|
|
75
|
+
- The manifest (`artifact-manifest.json`) is built from the `.arena.json`
|
|
76
|
+
sidecars gladiator writes with `--meta-data`. A folder with a manifest and no
|
|
77
|
+
sidecars is imported as it is.
|
|
78
|
+
- Private attachments (NiceLabel `.nlbl` sources), web links and BOM child
|
|
79
|
+
folders are left out. Only the declared files are uploaded.
|
|
80
|
+
- The media in `configuration.json` (`media_article`, `media_name`) is checked
|
|
81
|
+
against the BOM's 111 item. A mismatch is a warning; fix it with a new
|
|
82
|
+
revision in Arena. The CLI never changes `configuration.json`.
|
|
83
|
+
- A read-only folder (a write-protected USB stick) is imported through a
|
|
84
|
+
temporary copy.
|
|
85
|
+
- An interrupted import resumes: run it again and only the files that did not
|
|
86
|
+
arrive are sent. `--invalidate` discards what the station has staged.
|
|
87
|
+
- The output shows the revision, the Build Words, the media and any warnings.
|
|
88
|
+
|
|
89
|
+
Specification: `doc/label-package.md` and `doc/api-reference.md` in the
|
|
90
|
+
[LumenLabel repository](https://gitlab.com/lumenradio/production/lumenlabel).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# -*- mode: python ; coding: utf-8 -*-
|
|
2
|
+
# One-file build of the lumenlabel CLI: cli/dist/lumenlabel(.exe).
|
|
3
|
+
from PyInstaller.utils.hooks import collect_data_files, collect_submodules, copy_metadata
|
|
4
|
+
|
|
5
|
+
a = Analysis(
|
|
6
|
+
["src/lumenlabel/__main__.py"],
|
|
7
|
+
pathex=[],
|
|
8
|
+
binaries=[],
|
|
9
|
+
datas=[
|
|
10
|
+
*copy_metadata("lr-lumenlabel-cli"),
|
|
11
|
+
*collect_data_files("rich"),
|
|
12
|
+
("src/lumenlabel/wordlist", "lumenlabel/wordlist"),
|
|
13
|
+
],
|
|
14
|
+
# rich imports a Unicode-version submodule by a name computed at run
|
|
15
|
+
# time, which static analysis cannot see.
|
|
16
|
+
hiddenimports=[*collect_submodules("rich._unicode_data")],
|
|
17
|
+
hookspath=[],
|
|
18
|
+
hooksconfig={},
|
|
19
|
+
runtime_hooks=[],
|
|
20
|
+
excludes=[],
|
|
21
|
+
noarchive=False,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
pyz = PYZ(a.pure)
|
|
25
|
+
|
|
26
|
+
exe = EXE(
|
|
27
|
+
pyz,
|
|
28
|
+
a.scripts,
|
|
29
|
+
a.binaries,
|
|
30
|
+
a.datas,
|
|
31
|
+
[],
|
|
32
|
+
name="lumenlabel",
|
|
33
|
+
debug=False,
|
|
34
|
+
bootloader_ignore_signals=False,
|
|
35
|
+
strip=False,
|
|
36
|
+
upx=True,
|
|
37
|
+
upx_exclude=[],
|
|
38
|
+
runtime_tmpdir=None,
|
|
39
|
+
console=True,
|
|
40
|
+
disable_windowed_traceback=False,
|
|
41
|
+
argv_emulation=False,
|
|
42
|
+
target_arch=None,
|
|
43
|
+
codesign_identity=None,
|
|
44
|
+
entitlements_file=None,
|
|
45
|
+
)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "setuptools_scm>=8", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "lr-lumenlabel-cli"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "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."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Jonas Estberger", email = "jonas.estberger@lumenradio.com" }
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"typer>=0.12",
|
|
18
|
+
"rich>=13.7",
|
|
19
|
+
"httpx>=0.27",
|
|
20
|
+
"lr-fleet>=0.7",
|
|
21
|
+
]
|
|
22
|
+
keywords = ["LumenRadio", "LumenLabel", "label printing", "Arena", "CLI"]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
"Environment :: Console",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = [
|
|
32
|
+
"build>=1.2.1",
|
|
33
|
+
"twine>=6.1",
|
|
34
|
+
"pytest>=8.4",
|
|
35
|
+
"pytest-cov>=5.0",
|
|
36
|
+
"black>=25.9",
|
|
37
|
+
"setuptools_scm>=8",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
# The one place the CLI's PyInstaller version is declared. Held equal to the
|
|
41
|
+
# app's requirements-build.txt (tests/test_build_pins.py), so both executables
|
|
42
|
+
# in the .msi and the .deb come from one toolchain. The Wine build installs it
|
|
43
|
+
# over the version batonogov/pyinstaller-windows ships.
|
|
44
|
+
package = [
|
|
45
|
+
"pyinstaller==6.21.0",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
lumenlabel = "lumenlabel.cli:app"
|
|
50
|
+
|
|
51
|
+
[project.urls]
|
|
52
|
+
Homepage = "https://gitlab.com/lumenradio/production/lumenlabel"
|
|
53
|
+
Changelog = "https://gitlab.com/lumenradio/production/lumenlabel/-/blob/main/CHANGELOG.md"
|
|
54
|
+
|
|
55
|
+
[tool.setuptools]
|
|
56
|
+
package-dir = {"" = "src"}
|
|
57
|
+
include-package-data = true
|
|
58
|
+
|
|
59
|
+
[tool.setuptools.packages.find]
|
|
60
|
+
where = ["src"]
|
|
61
|
+
|
|
62
|
+
[tool.setuptools.package-data]
|
|
63
|
+
lumenlabel = ["wordlist/*.txt"]
|
|
64
|
+
|
|
65
|
+
# The version is the repository's lumenlabel-X.Y.Z tag, as for the app.
|
|
66
|
+
# `make dist` and the CI jobs set SETUPTOOLS_SCM_PRETEND_VERSION_FOR_LR_LUMENLABEL_CLI,
|
|
67
|
+
# so the sdist build does not pull the whole repository in through root="..",
|
|
68
|
+
# and builds without git (the Wine image) get the version too.
|
|
69
|
+
[tool.setuptools_scm]
|
|
70
|
+
root = ".."
|
|
71
|
+
tag_regex = "^lumenlabel-(?P<version>[0-9].+)$"
|
|
72
|
+
git_describe_command = ["git", "describe", "--dirty", "--tags", "--long", "--match", "lumenlabel-*", "--exclude", "*-rc*"]
|
|
73
|
+
version_file = "src/lumenlabel/_version.py"
|
|
74
|
+
fallback_version = "0.0.0"
|
|
75
|
+
|
|
76
|
+
[tool.pytest.ini_options]
|
|
77
|
+
addopts = "-ra"
|
|
78
|
+
testpaths = ["tests"]
|
|
79
|
+
|
|
80
|
+
[tool.coverage.run]
|
|
81
|
+
branch = true
|
|
82
|
+
source = ["lumenlabel"]
|
|
83
|
+
omit = ["*/_version.py"]
|
|
84
|
+
|
|
85
|
+
[tool.coverage.report]
|
|
86
|
+
fail_under = 80
|
|
87
|
+
show_missing = true
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lr-lumenlabel-cli
|
|
3
|
+
Version: 3.0.0
|
|
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
|
+
Author-email: Jonas Estberger <jonas.estberger@lumenradio.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/lumenradio/production/lumenlabel
|
|
8
|
+
Project-URL: Changelog, https://gitlab.com/lumenradio/production/lumenlabel/-/blob/main/CHANGELOG.md
|
|
9
|
+
Keywords: LumenRadio,LumenLabel,label printing,Arena,CLI
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: typer>=0.12
|
|
18
|
+
Requires-Dist: rich>=13.7
|
|
19
|
+
Requires-Dist: httpx>=0.27
|
|
20
|
+
Requires-Dist: lr-fleet>=0.7
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: build>=1.2.1; extra == "dev"
|
|
23
|
+
Requires-Dist: twine>=6.1; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest>=8.4; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
26
|
+
Requires-Dist: black>=25.9; extra == "dev"
|
|
27
|
+
Requires-Dist: setuptools_scm>=8; extra == "dev"
|
|
28
|
+
Provides-Extra: package
|
|
29
|
+
Requires-Dist: pyinstaller==6.21.0; extra == "package"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# lr-lumenlabel-cli
|
|
33
|
+
|
|
34
|
+
The `lumenlabel` command for LumenRadio LumenLabel label printing stations.
|
|
35
|
+
It turns a label fetched from Arena with gladiator into a label package and
|
|
36
|
+
imports it into a station, locally, on the LAN or through the Fleet relay.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install lr-lumenlabel-cli
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The LumenLabel installers also put it on every station: the `.msi` as
|
|
45
|
+
`lumenlabel.exe` on the system `PATH`, the `.deb` as `/usr/bin/lumenlabel`.
|
|
46
|
+
There it imports from a USB stick without a network (airgapped mode).
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Fetch the label with its Arena metadata and BOM children
|
|
52
|
+
gladiator get-files 109-1182 --recursive --meta-data --out 109-1182
|
|
53
|
+
|
|
54
|
+
# Write the manifest and show Build Words and media warnings, offline
|
|
55
|
+
lumenlabel label import 109-1182 --dry-run
|
|
56
|
+
|
|
57
|
+
# Import into the LumenLabel running on this computer
|
|
58
|
+
lumenlabel label import 109-1182
|
|
59
|
+
|
|
60
|
+
# Or remember a station once, then import into it
|
|
61
|
+
lumenlabel login --station https://fleet.cloud.lumenradio.com/v1/s/<uid>
|
|
62
|
+
lumenlabel label import 109-1182
|
|
63
|
+
lumenlabel label list
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Commands
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
lumenlabel [--station URL] [--token TOKEN] COMMAND # global options first
|
|
70
|
+
|
|
71
|
+
lumenlabel login --station URL [--token TOKEN]
|
|
72
|
+
# Checks the station and remembers it, with its token, in
|
|
73
|
+
# ~/.config/lumenlabel/login.json (0600). Every later command then talks
|
|
74
|
+
# to that station as if it were the local one. --base-url is an alias of
|
|
75
|
+
# --station, as in lumentest.
|
|
76
|
+
lumenlabel logout
|
|
77
|
+
|
|
78
|
+
lumenlabel label import DIR [--dry-run] [--invalidate] [--output rich|json]
|
|
79
|
+
lumenlabel label list [--output rich|json]
|
|
80
|
+
lumenlabel label remove ARTICLE [--yes]
|
|
81
|
+
|
|
82
|
+
lumenlabel station [--output rich|json] # info
|
|
83
|
+
lumenlabel station history [--limit N] [--before ID]
|
|
84
|
+
lumenlabel station logs [--tail N]
|
|
85
|
+
|
|
86
|
+
lumenlabel api METHOD PATH [--data JSON|@FILE] # any /api/ endpoint
|
|
87
|
+
lumenlabel --version
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Which station
|
|
91
|
+
|
|
92
|
+
1. `--station URL` (alias `--base-url`), or `LUMENLABEL_STATION` /
|
|
93
|
+
`LUMENLABEL_URL`.
|
|
94
|
+
2. The station saved by `lumenlabel login`.
|
|
95
|
+
3. The LumenLabel on this computer, `http://127.0.0.1:<port>`. The port is
|
|
96
|
+
read from the station's `lumenlabel.json` (default 17081).
|
|
97
|
+
|
|
98
|
+
| URL | Authentication |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `https://<fleet>/v1/s/<uid>` (Fleet relay) | Your Fleet sign-in (`fleet login`; the first command opens the browser if needed) |
|
|
101
|
+
| `http://127.0.0.1:<port>` (on the station) | None |
|
|
102
|
+
| `http://<station>:<port>` (LAN, `instrumentation.host` `0.0.0.0` on the station) | The station token, shown in admin mode on the station |
|
|
103
|
+
|
|
104
|
+
## `label import`
|
|
105
|
+
|
|
106
|
+
- The manifest (`artifact-manifest.json`) is built from the `.arena.json`
|
|
107
|
+
sidecars gladiator writes with `--meta-data`. A folder with a manifest and no
|
|
108
|
+
sidecars is imported as it is.
|
|
109
|
+
- Private attachments (NiceLabel `.nlbl` sources), web links and BOM child
|
|
110
|
+
folders are left out. Only the declared files are uploaded.
|
|
111
|
+
- The media in `configuration.json` (`media_article`, `media_name`) is checked
|
|
112
|
+
against the BOM's 111 item. A mismatch is a warning; fix it with a new
|
|
113
|
+
revision in Arena. The CLI never changes `configuration.json`.
|
|
114
|
+
- A read-only folder (a write-protected USB stick) is imported through a
|
|
115
|
+
temporary copy.
|
|
116
|
+
- An interrupted import resumes: run it again and only the files that did not
|
|
117
|
+
arrive are sent. `--invalidate` discards what the station has staged.
|
|
118
|
+
- The output shows the revision, the Build Words, the media and any warnings.
|
|
119
|
+
|
|
120
|
+
Specification: `doc/label-package.md` and `doc/api-reference.md` in the
|
|
121
|
+
[LumenLabel repository](https://gitlab.com/lumenradio/production/lumenlabel).
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
Makefile
|
|
3
|
+
README.md
|
|
4
|
+
lumenlabel.spec
|
|
5
|
+
pyproject.toml
|
|
6
|
+
src/lr_lumenlabel_cli.egg-info/PKG-INFO
|
|
7
|
+
src/lr_lumenlabel_cli.egg-info/SOURCES.txt
|
|
8
|
+
src/lr_lumenlabel_cli.egg-info/dependency_links.txt
|
|
9
|
+
src/lr_lumenlabel_cli.egg-info/entry_points.txt
|
|
10
|
+
src/lr_lumenlabel_cli.egg-info/requires.txt
|
|
11
|
+
src/lr_lumenlabel_cli.egg-info/scm_file_list.json
|
|
12
|
+
src/lr_lumenlabel_cli.egg-info/top_level.txt
|
|
13
|
+
src/lumenlabel/__init__.py
|
|
14
|
+
src/lumenlabel/__main__.py
|
|
15
|
+
src/lumenlabel/_version.py
|
|
16
|
+
src/lumenlabel/build_words.py
|
|
17
|
+
src/lumenlabel/cli.py
|
|
18
|
+
src/lumenlabel/client.py
|
|
19
|
+
src/lumenlabel/config.py
|
|
20
|
+
src/lumenlabel/config_rules.py
|
|
21
|
+
src/lumenlabel/importer.py
|
|
22
|
+
src/lumenlabel/manifest_gen.py
|
|
23
|
+
src/lumenlabel/media_check.py
|
|
24
|
+
src/lumenlabel/package.py
|
|
25
|
+
src/lumenlabel/shared.py
|
|
26
|
+
src/lumenlabel/commands/__init__.py
|
|
27
|
+
src/lumenlabel/commands/api.py
|
|
28
|
+
src/lumenlabel/commands/auth.py
|
|
29
|
+
src/lumenlabel/commands/label.py
|
|
30
|
+
src/lumenlabel/commands/station.py
|
|
31
|
+
src/lumenlabel/wordlist/bip39-english.txt
|
|
32
|
+
tests/conftest.py
|
|
33
|
+
tests/test_build_words.py
|
|
34
|
+
tests/test_client.py
|
|
35
|
+
tests/test_config_rules.py
|
|
36
|
+
tests/test_label_commands.py
|
|
37
|
+
tests/test_manifest_gen.py
|
|
38
|
+
tests/test_media_check.py
|
|
39
|
+
tests/test_other_commands.py
|
|
40
|
+
tests/test_package.py
|
|
41
|
+
tests/test_real_sidecar.py
|
|
42
|
+
tests/test_station_data_dir.py
|
|
43
|
+
tests/fixtures/109-1114-arena/.arena.json
|
|
44
|
+
tests/fixtures/109-1114-arena/109-1114 109-1115 v5.pdf
|
|
45
|
+
tests/fixtures/109-1135/.arena.json
|
|
46
|
+
tests/fixtures/109-1135/109-1135.txt
|
|
47
|
+
tests/fixtures/109-1135/Galileo MAX box label.pdf
|
|
48
|
+
tests/fixtures/109-1135/Galileo MAX.nlbl
|
|
49
|
+
tests/fixtures/109-1135/configuration.json
|
|
50
|
+
tests/fixtures/109-1135/111-1002/.arena.json
|
|
51
|
+
tests/fixtures/109-1182/.arena.json
|
|
52
|
+
tests/fixtures/109-1182/109-1182.txt
|
|
53
|
+
tests/fixtures/109-1182/Reel label_TiMo_2021_.pdf
|
|
54
|
+
tests/fixtures/109-1182/configuration.json
|
|
55
|
+
tests/fixtures/109-1183/.arena.json
|
|
56
|
+
tests/fixtures/109-1183/109-1183.txt
|
|
57
|
+
tests/fixtures/109-1183/800-8203_MWA-N2.nlbl
|
|
58
|
+
tests/fixtures/109-1183/800-8203_MWA-N2_Landscape.nlbl
|
|
59
|
+
tests/fixtures/109-1183/Reel label_TimoTwo .pdf
|
|
60
|
+
tests/fixtures/109-1183/configuration.json
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|