qrpipe 0.1.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.
- qrpipe-0.1.0/.github/workflows/ci.yml +33 -0
- qrpipe-0.1.0/.github/workflows/publish-testpypi.yml +34 -0
- qrpipe-0.1.0/.github/workflows/publish.yml +34 -0
- qrpipe-0.1.0/.gitignore +10 -0
- qrpipe-0.1.0/.pre-commit-config.yaml +27 -0
- qrpipe-0.1.0/.python-version +1 -0
- qrpipe-0.1.0/CHANGELOG.md +12 -0
- qrpipe-0.1.0/LICENSE +21 -0
- qrpipe-0.1.0/PKG-INFO +133 -0
- qrpipe-0.1.0/README.md +101 -0
- qrpipe-0.1.0/pyproject.toml +118 -0
- qrpipe-0.1.0/scripts/__init__.py +1 -0
- qrpipe-0.1.0/scripts/ci.py +64 -0
- qrpipe-0.1.0/setup.cfg +4 -0
- qrpipe-0.1.0/src/qrpipe/__init__.py +12 -0
- qrpipe-0.1.0/src/qrpipe/__main__.py +8 -0
- qrpipe-0.1.0/src/qrpipe/cli.py +385 -0
- qrpipe-0.1.0/src/qrpipe/py.typed +0 -0
- qrpipe-0.1.0/src/qrpipe.egg-info/PKG-INFO +133 -0
- qrpipe-0.1.0/src/qrpipe.egg-info/SOURCES.txt +26 -0
- qrpipe-0.1.0/src/qrpipe.egg-info/dependency_links.txt +1 -0
- qrpipe-0.1.0/src/qrpipe.egg-info/entry_points.txt +2 -0
- qrpipe-0.1.0/src/qrpipe.egg-info/requires.txt +11 -0
- qrpipe-0.1.0/src/qrpipe.egg-info/scm_file_list.json +22 -0
- qrpipe-0.1.0/src/qrpipe.egg-info/scm_version.json +8 -0
- qrpipe-0.1.0/src/qrpipe.egg-info/top_level.txt +1 -0
- qrpipe-0.1.0/tests/test_cli.py +475 -0
- qrpipe-0.1.0/tests/test_integration.py +45 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
checks:
|
|
9
|
+
name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
|
|
10
|
+
runs-on: ${{ matrix.os }}
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
15
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Check out source
|
|
19
|
+
uses: actions/checkout@v5
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v6
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
cache: pip
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: python -m pip install --upgrade pip && python -m pip install -e ".[dev]"
|
|
31
|
+
|
|
32
|
+
- name: Run quality gates
|
|
33
|
+
run: python -m scripts.ci
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Publish to TestPyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
permissions: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment:
|
|
12
|
+
name: testpypi
|
|
13
|
+
url: https://test.pypi.org/p/qrpipe
|
|
14
|
+
permissions:
|
|
15
|
+
id-token: write
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Check out source
|
|
19
|
+
uses: actions/checkout@v5
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v6
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
|
|
28
|
+
- name: Build distributions
|
|
29
|
+
run: python -m pip install --upgrade build twine && python -m build && python -m twine check dist/*
|
|
30
|
+
|
|
31
|
+
- name: Publish to TestPyPI
|
|
32
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
33
|
+
with:
|
|
34
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions: {}
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
publish:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment:
|
|
13
|
+
name: pypi
|
|
14
|
+
url: https://pypi.org/p/qrpipe
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- name: Check out release tag
|
|
20
|
+
uses: actions/checkout@v5
|
|
21
|
+
with:
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
ref: ${{ github.event.release.tag_name }}
|
|
24
|
+
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
uses: actions/setup-python@v6
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.12"
|
|
29
|
+
|
|
30
|
+
- name: Build distributions
|
|
31
|
+
run: python -m pip install --upgrade build twine && python -m build && python -m twine check dist/*
|
|
32
|
+
|
|
33
|
+
- name: Publish to PyPI
|
|
34
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
qrpipe-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: local
|
|
3
|
+
hooks:
|
|
4
|
+
- id: ruff-pep8-blank-lines
|
|
5
|
+
name: Ruff PEP 8 blank lines
|
|
6
|
+
entry: ruff check --preview --select E302,E305
|
|
7
|
+
language: python
|
|
8
|
+
additional_dependencies: ["ruff>=0.11"]
|
|
9
|
+
types_or: [python, pyi]
|
|
10
|
+
- id: ruff-check
|
|
11
|
+
name: Ruff lint
|
|
12
|
+
entry: ruff check
|
|
13
|
+
language: python
|
|
14
|
+
additional_dependencies: ["ruff>=0.11"]
|
|
15
|
+
types_or: [python, pyi]
|
|
16
|
+
- id: ruff-format
|
|
17
|
+
name: Ruff format
|
|
18
|
+
entry: ruff format --check
|
|
19
|
+
language: python
|
|
20
|
+
additional_dependencies: ["ruff>=0.11"]
|
|
21
|
+
types_or: [python, pyi]
|
|
22
|
+
- id: rumdl
|
|
23
|
+
name: Markdown lint
|
|
24
|
+
entry: rumdl check
|
|
25
|
+
language: python
|
|
26
|
+
additional_dependencies: ["rumdl>=0.1"]
|
|
27
|
+
files: \.(md|mdx)$
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 - 2026-09-10
|
|
4
|
+
|
|
5
|
+
- Read QR payloads from standard input or one positional argument.
|
|
6
|
+
- Strip exactly one shell-added trailing line ending by default.
|
|
7
|
+
- Render compact terminal QR codes.
|
|
8
|
+
- Save QR codes through Segno using an output filename extension.
|
|
9
|
+
- Provide typed CLI boundaries, tests, Ruff, Pyright, and pytest configuration.
|
|
10
|
+
- Add exact QR redundancy, module size, atomic file writes, and TTY-safe input handling.
|
|
11
|
+
- Add `phone` and `vcard` payload types for scanner-friendly structured QR content.
|
|
12
|
+
- Add opt-in `--open` support for launching saved images in the system viewer.
|
qrpipe-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rick
|
|
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.
|
qrpipe-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qrpipe
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn piped input into a terminal or file-based QR code.
|
|
5
|
+
Author: Rick
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/sheepfling/qrpipe
|
|
8
|
+
Project-URL: Source, https://github.com/sheepfling/qrpipe
|
|
9
|
+
Project-URL: Issues, https://github.com/sheepfling/qrpipe/issues
|
|
10
|
+
Keywords: cli,qr,qrcode,terminal,unix
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Utilities
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: segno<2,>=1.6.6
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
24
|
+
Requires-Dist: pre-commit>=4; extra == "dev"
|
|
25
|
+
Requires-Dist: pyright>=1.1.400; extra == "dev"
|
|
26
|
+
Requires-Dist: pytest>=8.3; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-cov>=6; extra == "dev"
|
|
28
|
+
Requires-Dist: ruff>=0.11; extra == "dev"
|
|
29
|
+
Requires-Dist: rumdl>=0.1; extra == "dev"
|
|
30
|
+
Requires-Dist: twine>=6; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# qrpipe
|
|
34
|
+
|
|
35
|
+
`qrpipe` turns piped input into a QR code or QR image.
|
|
36
|
+
|
|
37
|
+
The smallest useful interaction is:
|
|
38
|
+
|
|
39
|
+
```shell
|
|
40
|
+
printf '%s' 'https://example.com' | qrpipe
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
By default, `qrpipe` renders a compact QR code in the terminal. With `--output`, it writes a
|
|
44
|
+
file whose format is inferred from the extension by Segno.
|
|
45
|
+
|
|
46
|
+
## Install for development
|
|
47
|
+
|
|
48
|
+
```console
|
|
49
|
+
python3.12 -m venv .venv
|
|
50
|
+
.venv/bin/python -m pip install -e '.[dev]'
|
|
51
|
+
.venv/bin/qrpipe --help
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Examples
|
|
55
|
+
|
|
56
|
+
```console
|
|
57
|
+
printf '%s' 'https://example.com' | qrpipe
|
|
58
|
+
echo 'https://example.com' | qrpipe
|
|
59
|
+
cat payload.txt | qrpipe
|
|
60
|
+
qrpipe 'https://example.com'
|
|
61
|
+
printf '%s' 'https://example.com' | qrpipe --output example.png --size 8
|
|
62
|
+
printf '%s' 'https://example.com' | qrpipe -o example.svg --size 4
|
|
63
|
+
printf '%s' 'https://example.com' | qrpipe -o example.png --open
|
|
64
|
+
printf '%s' 'important payload' | qrpipe --redundancy H
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`--size` controls the output module scale; `--scale` is an alias. `--redundancy` (also
|
|
68
|
+
`--error`) selects the exact QR error-correction level: `L`, `M`, `Q`, or `H`. `--open` is an
|
|
69
|
+
explicit opt-in that opens an image file with the operating system's default viewer; it requires
|
|
70
|
+
`--output`.
|
|
71
|
+
|
|
72
|
+
## Structured payloads
|
|
73
|
+
|
|
74
|
+
The default `--type text` leaves the payload unchanged. `--type phone` converts a human-readable
|
|
75
|
+
number into a `tel:` URI:
|
|
76
|
+
|
|
77
|
+
```console
|
|
78
|
+
printf '%s\n' '+1 (555) 010-1234' | qrpipe --type phone -o phone.png
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`--type vcard` accepts a complete vCard, common property lines (`FN:`, `TEL:`, `EMAIL:`, `ORG:`),
|
|
82
|
+
or a plain name, which becomes a minimal vCard:
|
|
83
|
+
|
|
84
|
+
```console
|
|
85
|
+
printf '%s' 'Ada Lovelace' | qrpipe --type vcard -o ada.svg
|
|
86
|
+
printf '%s\n' 'FN:Ada Lovelace' 'EMAIL:ada@example.test' | qrpipe --type vcard -o ada.svg
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Structured payloads must be UTF-8. Ordinary text input is read as bytes and passed to Segno
|
|
90
|
+
without a decode/re-encode round trip.
|
|
91
|
+
|
|
92
|
+
## Input and output semantics
|
|
93
|
+
|
|
94
|
+
- A positional `DATA` value takes precedence over standard input and is treated literally.
|
|
95
|
+
- When reading standard input, exactly one final `\n` or `\r\n` is removed by default. Use
|
|
96
|
+
`--preserve-newline` when that line ending is meaningful payload data.
|
|
97
|
+
- Empty input exits with status `2`; whitespace is valid data.
|
|
98
|
+
- Running `qrpipe` with no argument on an interactive terminal exits immediately with guidance
|
|
99
|
+
instead of waiting forever for EOF.
|
|
100
|
+
- File output is written beside the destination and atomically replaces an existing destination.
|
|
101
|
+
- PNG and SVG are the normal file formats; Segno also supports other formats selected by extension.
|
|
102
|
+
|
|
103
|
+
Successful terminal output contains only the QR rendering. Diagnostics never include the original
|
|
104
|
+
payload, which matters for URLs with tokens, Wi-Fi credentials, OTP setup URIs, and other secrets.
|
|
105
|
+
|
|
106
|
+
## Deliberate boundaries
|
|
107
|
+
|
|
108
|
+
qrpipe always creates ordinary QR codes. Micro QR, structured-append sequences, explicit Segno
|
|
109
|
+
encoding modes, and additional helper formats such as Wi-Fi, email, geo, MeCard, and EPC payment
|
|
110
|
+
QR are intentionally outside this small initial interface.
|
|
111
|
+
|
|
112
|
+
## Development
|
|
113
|
+
|
|
114
|
+
```console
|
|
115
|
+
.venv/bin/python -m scripts.ci
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This runs compilation, Ruff, branch coverage, build/metadata checks, Pyright, Markdown linting,
|
|
119
|
+
and pre-commit. GitHub Actions runs the same gates on Ubuntu, macOS, and Windows with Python 3.12,
|
|
120
|
+
3.13, and 3.14.
|
|
121
|
+
|
|
122
|
+
## Releasing
|
|
123
|
+
|
|
124
|
+
1. Push the release commit and wait for CI to pass.
|
|
125
|
+
2. Configure PyPI and TestPyPI trusted publishers for this repository's corresponding workflows.
|
|
126
|
+
3. Tag that commit as `v0.1.0` and push the tag.
|
|
127
|
+
4. Run **Publish to TestPyPI** from GitHub Actions against the tag and install the result in a
|
|
128
|
+
fresh environment.
|
|
129
|
+
5. Create a GitHub release from the same tag to publish to PyPI.
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT. See `LICENSE`.
|
qrpipe-0.1.0/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# qrpipe
|
|
2
|
+
|
|
3
|
+
`qrpipe` turns piped input into a QR code or QR image.
|
|
4
|
+
|
|
5
|
+
The smallest useful interaction is:
|
|
6
|
+
|
|
7
|
+
```shell
|
|
8
|
+
printf '%s' 'https://example.com' | qrpipe
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
By default, `qrpipe` renders a compact QR code in the terminal. With `--output`, it writes a
|
|
12
|
+
file whose format is inferred from the extension by Segno.
|
|
13
|
+
|
|
14
|
+
## Install for development
|
|
15
|
+
|
|
16
|
+
```console
|
|
17
|
+
python3.12 -m venv .venv
|
|
18
|
+
.venv/bin/python -m pip install -e '.[dev]'
|
|
19
|
+
.venv/bin/qrpipe --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
```console
|
|
25
|
+
printf '%s' 'https://example.com' | qrpipe
|
|
26
|
+
echo 'https://example.com' | qrpipe
|
|
27
|
+
cat payload.txt | qrpipe
|
|
28
|
+
qrpipe 'https://example.com'
|
|
29
|
+
printf '%s' 'https://example.com' | qrpipe --output example.png --size 8
|
|
30
|
+
printf '%s' 'https://example.com' | qrpipe -o example.svg --size 4
|
|
31
|
+
printf '%s' 'https://example.com' | qrpipe -o example.png --open
|
|
32
|
+
printf '%s' 'important payload' | qrpipe --redundancy H
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`--size` controls the output module scale; `--scale` is an alias. `--redundancy` (also
|
|
36
|
+
`--error`) selects the exact QR error-correction level: `L`, `M`, `Q`, or `H`. `--open` is an
|
|
37
|
+
explicit opt-in that opens an image file with the operating system's default viewer; it requires
|
|
38
|
+
`--output`.
|
|
39
|
+
|
|
40
|
+
## Structured payloads
|
|
41
|
+
|
|
42
|
+
The default `--type text` leaves the payload unchanged. `--type phone` converts a human-readable
|
|
43
|
+
number into a `tel:` URI:
|
|
44
|
+
|
|
45
|
+
```console
|
|
46
|
+
printf '%s\n' '+1 (555) 010-1234' | qrpipe --type phone -o phone.png
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`--type vcard` accepts a complete vCard, common property lines (`FN:`, `TEL:`, `EMAIL:`, `ORG:`),
|
|
50
|
+
or a plain name, which becomes a minimal vCard:
|
|
51
|
+
|
|
52
|
+
```console
|
|
53
|
+
printf '%s' 'Ada Lovelace' | qrpipe --type vcard -o ada.svg
|
|
54
|
+
printf '%s\n' 'FN:Ada Lovelace' 'EMAIL:ada@example.test' | qrpipe --type vcard -o ada.svg
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Structured payloads must be UTF-8. Ordinary text input is read as bytes and passed to Segno
|
|
58
|
+
without a decode/re-encode round trip.
|
|
59
|
+
|
|
60
|
+
## Input and output semantics
|
|
61
|
+
|
|
62
|
+
- A positional `DATA` value takes precedence over standard input and is treated literally.
|
|
63
|
+
- When reading standard input, exactly one final `\n` or `\r\n` is removed by default. Use
|
|
64
|
+
`--preserve-newline` when that line ending is meaningful payload data.
|
|
65
|
+
- Empty input exits with status `2`; whitespace is valid data.
|
|
66
|
+
- Running `qrpipe` with no argument on an interactive terminal exits immediately with guidance
|
|
67
|
+
instead of waiting forever for EOF.
|
|
68
|
+
- File output is written beside the destination and atomically replaces an existing destination.
|
|
69
|
+
- PNG and SVG are the normal file formats; Segno also supports other formats selected by extension.
|
|
70
|
+
|
|
71
|
+
Successful terminal output contains only the QR rendering. Diagnostics never include the original
|
|
72
|
+
payload, which matters for URLs with tokens, Wi-Fi credentials, OTP setup URIs, and other secrets.
|
|
73
|
+
|
|
74
|
+
## Deliberate boundaries
|
|
75
|
+
|
|
76
|
+
qrpipe always creates ordinary QR codes. Micro QR, structured-append sequences, explicit Segno
|
|
77
|
+
encoding modes, and additional helper formats such as Wi-Fi, email, geo, MeCard, and EPC payment
|
|
78
|
+
QR are intentionally outside this small initial interface.
|
|
79
|
+
|
|
80
|
+
## Development
|
|
81
|
+
|
|
82
|
+
```console
|
|
83
|
+
.venv/bin/python -m scripts.ci
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
This runs compilation, Ruff, branch coverage, build/metadata checks, Pyright, Markdown linting,
|
|
87
|
+
and pre-commit. GitHub Actions runs the same gates on Ubuntu, macOS, and Windows with Python 3.12,
|
|
88
|
+
3.13, and 3.14.
|
|
89
|
+
|
|
90
|
+
## Releasing
|
|
91
|
+
|
|
92
|
+
1. Push the release commit and wait for CI to pass.
|
|
93
|
+
2. Configure PyPI and TestPyPI trusted publishers for this repository's corresponding workflows.
|
|
94
|
+
3. Tag that commit as `v0.1.0` and push the tag.
|
|
95
|
+
4. Run **Publish to TestPyPI** from GitHub Actions against the tag and install the result in a
|
|
96
|
+
fresh environment.
|
|
97
|
+
5. Create a GitHub release from the same tag to publish to PyPI.
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT. See `LICENSE`.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "setuptools-scm>=8"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "qrpipe"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Turn piped input into a terminal or file-based QR code."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.12"
|
|
13
|
+
authors = [{ name = "Rick" }]
|
|
14
|
+
keywords = ["cli", "qr", "qrcode", "terminal", "unix"]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"segno>=1.6.6,<2",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Environment :: Console",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Topic :: Utilities",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/sheepfling/qrpipe"
|
|
30
|
+
Source = "https://github.com/sheepfling/qrpipe"
|
|
31
|
+
Issues = "https://github.com/sheepfling/qrpipe/issues"
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
dev = [
|
|
35
|
+
"build>=1.2",
|
|
36
|
+
"pre-commit>=4",
|
|
37
|
+
"pyright>=1.1.400",
|
|
38
|
+
"pytest>=8.3",
|
|
39
|
+
"pytest-cov>=6",
|
|
40
|
+
"ruff>=0.11",
|
|
41
|
+
"rumdl>=0.1",
|
|
42
|
+
"twine>=6",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project.scripts]
|
|
46
|
+
qrpipe = "qrpipe.cli:main"
|
|
47
|
+
|
|
48
|
+
[tool.setuptools.packages.find]
|
|
49
|
+
where = ["src"]
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.package-data]
|
|
52
|
+
qrpipe = ["py.typed"]
|
|
53
|
+
|
|
54
|
+
[tool.setuptools_scm]
|
|
55
|
+
version_scheme = "no-guess-dev"
|
|
56
|
+
fallback_version = "0.1.0"
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
addopts = "-ra --strict-config --strict-markers"
|
|
60
|
+
testpaths = ["tests"]
|
|
61
|
+
|
|
62
|
+
[tool.pyright]
|
|
63
|
+
include = ["src", "scripts", "tests"]
|
|
64
|
+
exclude = [".venv"]
|
|
65
|
+
pythonVersion = "3.12"
|
|
66
|
+
pythonPlatform = "All"
|
|
67
|
+
typeCheckingMode = "strict"
|
|
68
|
+
venvPath = "."
|
|
69
|
+
venv = ".venv"
|
|
70
|
+
reportUnnecessaryTypeIgnoreComment = "error"
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 100
|
|
74
|
+
target-version = "py312"
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint]
|
|
77
|
+
select = [
|
|
78
|
+
"A",
|
|
79
|
+
"ANN",
|
|
80
|
+
"ARG",
|
|
81
|
+
"B",
|
|
82
|
+
"C4",
|
|
83
|
+
"E",
|
|
84
|
+
"F",
|
|
85
|
+
"I",
|
|
86
|
+
"N",
|
|
87
|
+
"PERF",
|
|
88
|
+
"PIE",
|
|
89
|
+
"PL",
|
|
90
|
+
"PTH",
|
|
91
|
+
"RET",
|
|
92
|
+
"RUF",
|
|
93
|
+
"SIM",
|
|
94
|
+
"TRY",
|
|
95
|
+
"UP",
|
|
96
|
+
"W",
|
|
97
|
+
]
|
|
98
|
+
ignore = [
|
|
99
|
+
"ANN401",
|
|
100
|
+
"TRY003",
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
[tool.ruff.lint.per-file-ignores]
|
|
104
|
+
"tests/**/*.py" = ["PLR2004", "S101"]
|
|
105
|
+
|
|
106
|
+
[tool.coverage.run]
|
|
107
|
+
branch = true
|
|
108
|
+
source = ["qrpipe"]
|
|
109
|
+
|
|
110
|
+
[tool.coverage.report]
|
|
111
|
+
fail_under = 95
|
|
112
|
+
show_missing = true
|
|
113
|
+
skip_covered = true
|
|
114
|
+
|
|
115
|
+
[tool.rumdl]
|
|
116
|
+
line-length = 100
|
|
117
|
+
exclude = [".git", ".github", "build", "dist", "node_modules", "vendor"]
|
|
118
|
+
respect-gitignore = true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Local development and continuous-integration helpers."""
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Run the repository quality gates in the hosted-CI order."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
import sysconfig
|
|
9
|
+
from collections.abc import Sequence
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from tempfile import TemporaryDirectory
|
|
12
|
+
|
|
13
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _run(command: Sequence[str], *, cwd: Path = ROOT) -> None:
|
|
17
|
+
"""Run one quality gate and stop immediately if it fails."""
|
|
18
|
+
print("+", " ".join(command), flush=True)
|
|
19
|
+
scripts_directory = Path(sysconfig.get_path("scripts"))
|
|
20
|
+
environment = os.environ | {
|
|
21
|
+
"PATH": os.pathsep.join(
|
|
22
|
+
(str(scripts_directory), str(Path(sys.executable).parent), os.environ.get("PATH", ""))
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
subprocess.run(command, check=True, cwd=cwd, env=environment)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _check_distributions(python: str) -> None:
|
|
29
|
+
"""Build isolated distributions and validate their core metadata."""
|
|
30
|
+
with TemporaryDirectory(prefix="qrpipe-build-") as temporary_directory:
|
|
31
|
+
artifacts = Path(temporary_directory)
|
|
32
|
+
_run([python, "-m", "build", "--outdir", str(artifacts)])
|
|
33
|
+
distributions = sorted(artifacts.iterdir())
|
|
34
|
+
_run([python, "-m", "twine", "check", *(str(path) for path in distributions)])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _environment_tool(python: str, name: str) -> str:
|
|
38
|
+
"""Return a tool installed beside the selected interpreter."""
|
|
39
|
+
scripts_directory = Path(sysconfig.get_path("scripts"))
|
|
40
|
+
return str(scripts_directory / f"{name}{Path(python).suffix}")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def main() -> int:
|
|
44
|
+
"""Run all local quality gates."""
|
|
45
|
+
python = sys.executable
|
|
46
|
+
commands = (
|
|
47
|
+
[python, "-m", "compileall", "-q", "src", "scripts", "tests"],
|
|
48
|
+
[python, "-m", "ruff", "check", "--preview", "--select", "E302,E305", "."],
|
|
49
|
+
[python, "-m", "ruff", "check", "."],
|
|
50
|
+
[python, "-m", "ruff", "format", "--check", "."],
|
|
51
|
+
[python, "-m", "pytest", "--cov=qrpipe", "--cov-branch"],
|
|
52
|
+
)
|
|
53
|
+
for command in commands:
|
|
54
|
+
_run(command)
|
|
55
|
+
|
|
56
|
+
_check_distributions(python)
|
|
57
|
+
_run([python, "-m", "pyright"])
|
|
58
|
+
_run([_environment_tool(python, "rumdl"), "check", "README.md", "CHANGELOG.md"])
|
|
59
|
+
_run([python, "-m", "pre_commit", "run", "--all-files"])
|
|
60
|
+
return 0
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
raise SystemExit(main())
|
qrpipe-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Pipe text into a QR code."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
__version__ = version("qrpipe")
|
|
9
|
+
except PackageNotFoundError:
|
|
10
|
+
__version__ = "0.0.0+unknown"
|
|
11
|
+
|
|
12
|
+
__all__ = ["__version__"]
|