Releases: IvanAnishchuk/cuere
Release list
cuere 0.2.0
Added
-
A documentation site built with zensical (the new
zensical.tomlformat) and Material for MkDocs: a landing page, a Quickstart,
a "Rendering & scanning" guide, an auto-generated CLI reference
(mkdocs-typer2) and API reference (mkdocstrings), and the existing
cookbook/standards pages, wired into adocsextra
(uv sync --extra docs). Every public symbol's docstring now carries a
usage example. Closes #10, #11, #12, #13. -
A
DocsCI workflow (.github/workflows/docs.yml) that builds the
documentation site withzensical build --strictas a gate on every pull
request tomain, and deploys it to GitHub Pages on push tomain. The
README gains a documentation badge and a link to the published site at
https://ivananishchuk.github.io/cuere/. Closes #15. -
An animated terminal demo in the README, recorded with
vhs from a checked-in
examples/demo.tapeshowing a basic render,--invert, a wallet URI with
--optimize-uri, and--mode ansi. Ascripts/render_demo.pyhelper
re-records it locally (uv run python scripts/render_demo.py). Closes #16. -
Terminal color customization for
ansimode.render/show(and
cuere.rich.QRCode, plus the CLI--dark/--lightflags) now takedark
andlightcolors for the dark modules and the light ground. AColoris a
name (one of the 16 standard ANSI colors), a 256-palette index (anintor its
string form), or a truecolor value (#rrggbb/#rgbhex, an(r, g, b)
tuple, or its"r,g,b"string); the defaults stay the theme-proof
black-on-white (palette16on231). Colors areansi-only — passing one to
half/blockraises the newColorError(aCuereError) — andshow
drops them along with itsNO_COLOR/ non-tty fallback. Adds the exported
Colortype alias. Documented in a newdocs/colors.md, including the
scanner-contrast caveats. Closes #26. -
A pytest-benchmark performance suite (
benchmarks/) and an informational
BenchmarkCI job that records encode and render timings as a JSON artifact.
It coversQRMatrix.encodeacross payload sizes, each render mode
(half/block/ansi),render_svg,render_bytes(PNG), and the
high-levelrender()/render_bytes()paths. The suite is kept out of the
test run (not intestpaths, so coverage is unaffected) and runs only via the
benchmark job oruv run pytest benchmarks/ --benchmark-only. There is no
regression threshold yet — it is the foundation for one later. Closes #22. -
File and bytes export beyond the terminal.
render_bytes()returns the
encodedbytesfor a namedOutputFormat, andsave()writes them to a path
or binary stream — inferring the format from a.txt/.svg/.pngsuffix
when one is not given. Three formats ship:text(the terminal glyph
rendering, honoringmode/invert),svg(a standalone vector document,
also exposed directly asrender_svg()), andpng(a raster image that needs
the optionalcuere[image]extra — Pillow, imported lazily soimport cuere
never pulls it in).scalesets pixels-per-module forsvg/png. Unknown
formats raiseUnknownFormatError; a missing optional dependency raises
MissingDependencyError(bothCuereErrors). The CLI gains
--output FORMAT[:PATH](PATH-or omitted means stdout; the default stays
terminal output) and--scale. Also adds theSupportsWriteBytessink
protocol. Documented in a newdocs/output-formats.mdand the cookbook.
Closes #23, #24, #25. -
lightning_uri()— a typedlightning:URI builder for bech32 Lightning
payloads (BOLT11 invoiceslnbc…, LNURLlnurl1…, BOLT12 offerslno1…).
The payload is validated structurally (a single-case run of ASCII
alphanumerics beginningln) without a checksum verify, mirroring
bitcoin_uri; invalid input raisesWalletURIError. A lowercase result
composes withoptimize_urifor a smaller QR. Documented in
docs/cookbook/wallet-uris.mdand a newdocs/lightning-uri.md. -
SchemeCaseandscheme_case()— a public, typed classifier for how
optimize_uritreats a URI's scheme:INSENSITIVE(bech32 —bitcoin:/
lightning:— may be uppercased),SIGNIFICANT(case carries meaning —
ethereum:EIP-55,wc:WalletConnect — never folded), orUNKNOWN
(unrecognized scheme, also never folded).optimize_urinow gates on this, so
wc:is recognized explicitly as case-significant rather than incidentally
passed through. -
ethereum_uri()anderc20_transfer_uri()— typed
EIP-681ethereum:request builders.
ethereum_uri(address, *, value=None, chain_id=None, gas_limit=None, gas_price=None)builds a native payment (valuein wei, matching the
spec);erc20_transfer_uri(token, *, to, amount, ...)builds the ERC-20
transfer(address,uint256)form (amountin the token's base units).
Addresses are validated structurally as0x+ 40 hex digits with their
EIP-55 checksum case preserved (so these URIs must never go through
optimize_uri); numeric arguments are positiveuint256integers. Invalid
input raisesWalletURIError. Documented indocs/cookbook/wallet-uris.md. -
docs/bip-21.mdanddocs/eip-681.md— condensed summaries of the wallet-URI
standards cuere implements (BIP-21/BIP-173 forbitcoin_uri; EIP-681/EIP-55/
EIP-155 and ERC-20transferfor the ethereum builders). -
bitcoin_uri()— a typed BIP-21bitcoin:payment-request builder
(bitcoin_uri(address, *, amount=None, label=None, message=None)). It
validates the address alphabet, rendersamountas a plain BTC decimal
(Decimal/int/str; positive, finite, satoshi precision — neverfloat),
and percent-encodeslabel/message. Returns a plainstrthat composes
withoptimize_uriandrender/show. Invalid input raises the new
WalletURIError(aCuereError). Documented in a newdocs/cookbook/wallet-uris.md. -
Mutation testing with
mutmut(dev dependency, run locally — not in CI),
configured inpyproject.tomland documented indocs/mutation-testing.md,
with the set of accepted equivalent mutants recorded there. Includes a mypy
type-check pass (mutmut-mypy.ini) that catches type-error mutants without a
runtime test, and a no-shrink hypothesis profile for deterministic runs. -
Behavioral regression tests closing the gaps mutation testing surfaced:
exact error/warning messages (WidthError, invalid render mode), encode-option
pass-through inrender/fits/rich.QRCode, block-mode width/height in
fits/show/QRCode.__rich_measure__, theshowexact-fit boundary,
per-row Rich segments, and first-colon URI scheme parsing inoptimize_uri. -
tests/test_types.py:assert_typeregression tests pinning the inferred
types of the public API. -
zizmorGitHub Actions security audit: dev dependency, a local pre-commit
hook (offline), and a CI workflow running online audits with SARIF upload to
code scanning. -
.github/settings.yml(repository-settings app):security_and_analysis
(secret scanning + push protection + Dependabot security updates), branch
protection onmain, and the PyPI/TestPyPI environments — as code. -
.github/CODEOWNERS. -
gitleaks now uploads its SARIF to code scanning.
-
.coderabbit.yaml— the CodeRabbit review configuration, pinned in-repo
rather than left to dashboard defaults: assertive profile, auto-review on pull
requests targetingmain, path filters that skip generated files (uv.lock,
build output, golden fixtures), and house-style review instructions.
CodeRabbit's bundledruffandgitleaksare disabled there since CI already
enforces both. CodeRabbit remains a best-effort second opinion;/code-review
and CI are the gate. -
.well-known/security.txt(RFC 9116) — machine-readable security contact. -
Contributor governance:
CONTRIBUTING.md,CODE_OF_CONDUCT.md, issue
templates (bug / feature / question) and a pull-request template. -
SupportsWrite— a narrow text-sink protocol (any object withwrite(str)),
exported fromcuere. It is whatshow(out=...)now accepts. -
Test-hardening pass: edge-case and property coverage for empty/whitespace
payloads, near-maximal payloads, all four EC levels (encoding + monotonic
version growth), the reachable Micro QR variants (M2–M4, plus the M1-skip and
the rejectedH/oversized cases), extreme borders, that purerender()
keeps ANSI color regardless ofNO_COLOR, and round-trip strategies that
exercise the renderers against real encoder output (not only synthetic bit
patterns).
Changed
- The cookbook moved into a
docs/cookbook/directory: the payment-request
recipes now live indocs/cookbook/wallet-uris.mdand the file/bytes export
recipes indocs/cookbook/exporting.md(the flatdocs/cookbook.mdis gone).
The wallet page now embeds the rendered terminal QR for every recipe, adds a
standalone WalletConnect (wc:) rendering recipe, and explains why cuere
encodes at error-correction level L. Ascripts/render_docs_qr.pyscript
regenerates that embedded art (run with--checkin CI to catch drift). optimize_uri()is refactored onto the newscheme_case(); its behavior is
unchanged (case-insensitive, lowercase, no-query URIs are uppercased;
everything else is returned verbatim), butethereum:andwc:are now
deliberately classified as case-significant rather than relying on the
unknown-scheme default.- Dropped
from __future__ import annotationsand theif TYPE_CHECKING:
gating of cheap stdlib/intra-package imports — those are now plain runtime
imports. Removed theflake8-type-checking(TCH) ruff ruleset, which had
been mechanically forcing both patterns plus quotedtyping.casttypes. The
lazy import ofrich/typeris un...
cuere 0.1.0
Added
QRMatrixencoding layer over segno (error levelLby default, no
error-boost, quiet zone baked in); its.modulesgrid is the public
raw-matrix accessor.- Renderers:
half(Claude-Code-style Unicode half-blocks),block
(double-width full blocks),ansi(forced black-on-white colors). - High-level
render()/show()/fits()with optional Micro QR and
error-boost, terminal width/height fit checks, andNO_COLOR/tty-aware
ANSI fallback. - Rich renderable
cuere.rich.QRCodewith exact measurement. optimize_uri()— lossless uppercase optimization for fully-lowercase
bitcoin:/lightning:(bech32) wallet URIs to reach QR alphanumeric mode.- typer CLI:
cuere [DATA | --input FILE]with--mode,--invert,
--border,--error,--micro,--boost-error,--optimize-uri,
--check-width/--no-check-width,--force. AGENTS.mdand.github/copilot-instructions.mdwith project conventions
and review guidelines for AI review agents (Codex, GitHub Copilot).
Changed
NO_COLORdisables ANSI output whenever the variable is present, regardless
of its value (including empty), per the no-color.org spec.- The CLI strips only trailing newlines from stdin (
rstrip("\r\n")),
preserving intentional payload whitespace. - The release SBOM excludes dev dependencies (
uv export --no-dev).
Fixed
- An invalid
borderor rendermoderaisesCuereErrorrather than leaking
a bareValueError, keeping the public exception contract consistent.
Security
- OSV-Scanner findings fail CI; the coverage-comment
workflow_runjob is
restricted to same-repository pull-request runs; the gitleaks allowlist is
scoped to a single test file;scripts/audit.pysubprocesses have a timeout. - Release publish routing uses anchored version matching (not substring) to
choose PyPI vs TestPyPI, so it cannot misroute on incidental tag/branch text. - Release builds publish via PyPI trusted publishing (OIDC) with sigstore
signatures, SLSA provenance, PEP 740 attestations, and a CycloneDX SBOM.
What's Changed
- feat: cuere v0.1.0 — terminal QR code library by @IvanAnishchuk in #1
- ci: robust release routing + coverage-comment PR gating by @IvanAnishchuk in #4
New Contributors
- @IvanAnishchuk made their first contribution in #1
Full Changelog: https://github.com/IvanAnishchuk/cuere/commits/v0.1.0