Metadata-Version: 2.4
Name: qrpen
Version: 1.0.0
Summary: Dependency-free QR generation for Python, prompts, terminals, and custom URIs.
Author: Joao Lopes
License-Expression: MIT
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: test
Requires-Dist: coverage>=7.6; extra == "test"
Requires-Dist: pytest>=8; extra == "test"
Dynamic: license-file

# QRpen

**QRpen** is a dependency-free Python 3.13+ QR encoder and renderer designed for embedding in applications, agent prompts, terminals, custom-URI workflows, and file-export pipelines. The Python API is the primary interface; the `qrpen` command is a thin adapter over it.

## Highlights

- Dependency-free runtime; no external QR library.
- Automatic QR version selection from payload size (versions 1–10).
- Low, medium, quartile, and high error correction.
- Exact UTF-8 payload preservation: custom URI schemes are not parsed, normalized, decoded, or rebuilt.
- Optional companion instruction that is returned with the artifact but never encoded into the QR.
- Plain text, Markdown, agent-hook/prompt, terminal, PNG, and SVG output.
- Responsive SVG: the root uses `viewBox` only; no fixed `width` or `height` attributes.
- Configurable text character-cell ratio and PNG pixels-per-module scale.
- Structured size metadata in characters, pixels, viewport units, or QR modules.
- ANSI truecolor terminal rendering with CSS color names and `#RRGGBB`.
- Side-effect-free embedding API; filesystem/stdout behavior is confined to adapters.

## Installation

```bash
python -m pip install .
```

For development:

```bash
python -m pip install -e '.[test]'
```

## CLI quick start

```bash
qrpen 'https://example.com'
qrpen 'arrow://auth?id=abc' --frame --no-color
qrpen 'arrow://auth?id=abc' --output-format hook
qrpen 'https://example.com' --output-format svg --output-file qr.svg
qrpen 'https://example.com' --output-format png --scale 12 --output-file qr.png
```

`txt` with no output file preserves the interactive terminal renderer. `md`, `hook`, and other textual portable formats go to stdout unless `--output-file` is supplied. Binary PNG requires `--output-file`.

## Size inspection

Use `--size` to calculate the produced dimensions without emitting the artifact:

```bash
qrpen 'https://example.com' --output-format txt --size
qrpen 'https://example.com' --output-format hook --size
qrpen 'https://example.com' --output-format svg --size
qrpen 'https://example.com' --output-format png --scale 4 --size
```

Units are format-specific:

| Format | Size unit | Meaning |
|---|---|---|
| `txt` | characters | proportional QR matrix width × rows |
| `md` | characters | QR matrix geometry (fence excluded from measurement) |
| `hook` | characters | complete generated prompt payload geometry |
| `svg` | viewport | SVG `viewBox` dimensions |
| `png` | pixels | actual raster dimensions |

The encoded QR matrix itself is always square and available through `QrCode.size` / artifact `module_count`.

## Python API

```python
from qrpen import ExportOptions, OutputFormat, QrApi, QrRequest

request = QrRequest(
    content="arrow://auth?id=a%2Fb&next=x%3Fy%3D1",
    instruction="Authenticate and open the URI exactly as supplied.",
)
artifact = QrApi.render_artifact(
    request=request,
    output_format=OutputFormat.hook,
    options=ExportOptions(ratio=2.6),
)

assert artifact.encoded_content == request.content
print(artifact.size)
print(artifact.content)
```

The `instruction` is metadata/presentation content. It does **not** change QR capacity and is not encoded into the QR matrix.

### PNG

```python
artifact = QrApi.render_artifact(
    request=QrRequest(content="https://example.com"),
    output_format=OutputFormat.png,
    options=ExportOptions(border=4, scale=10),
)
assert artifact.size.unit.value == "pixels"
```

### Responsive SVG

```python
artifact = QrApi.render_artifact(
    request=QrRequest(content="https://example.com"),
    output_format=OutputFormat.svg,
)
```

The SVG root resembles:

```xml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29 29">
```

There are intentionally no root `width` or `height` attributes. Size it with CSS or the embedding viewport.

### Terminal

```python
from qrpen import QrApi, QrRequest, TerminalOptions

text = QrApi.render_terminal(
    request=QrRequest(content="arrow://auth?id=abc"),
    options=TerminalOptions(
        frame=True,
        frame_color="dodgerblue",
        qr_foreground="black",
        qr_background="white",
    ),
)
```

The API returns the string. It does not print it.

## Prompt / hook mode

Hook output is designed for session-start context systems. It contains a strict instruction asking the receiving agent to reproduce the framed QR exactly once before its first normal response. This is instruction-driven behavior: the receiving model/UI ultimately controls whether and how it is displayed.

Agent/surface calibrations keep that presentation renderer-specific. Codex and Claude Code CLI sessions use explicit text ratios so monospaced shell cells remain scannable. Their desktop chat surfaces use a generated PNG instead, because proportional chat typography cannot preserve QR module geometry.

```bash
qrpen 'arrow://auth?id=abc' \
  --instruction 'Authenticate using this URI.' \
  --output-format hook > session-start.txt
```

This is equivalent to `--output-file session-start.txt` for textual output.

## Custom URI safety

QRpen treats content as opaque Unicode text and encodes `content.encode("utf-8")`. It deliberately does not call a URL parser. Consequently percent escapes, query separators, custom schemes, and Unicode are preserved exactly at the byte-encoding boundary.

If URI canonicalization, signing, authentication, expiry, privilege escalation, or replay protection is required, implement those semantics in the URI-producing/consuming layer. QRpen is the transport/representation layer, not an authorization system.

## Validation and errors

Public configuration errors derive from `QrpenError`. Important subclasses are:

- `QrConfigurationError` — invalid ratio, border, scale, or empty content.
- `QrEncodingError` — encoding failure.
- `QrCapacityError` — payload exceeds the supported QR capacity.
- `QrRenderError` — reserved for rendering failures.

## Output sizing

QR version determines the logical module matrix: `17 + 4 × version`. Text `ratio` changes only horizontal character representation; it never changes encoded data. PNG `scale` is pixels per QR module. SVG uses logical cells directly in its `viewBox`.

## Architecture

```text
QrRequest / ExportOptions / TerminalOptions
                 │
                 ▼
               QrApi
      ┌──────────┼──────────┐
      ▼          ▼          ▼
   encoder    renderers   measure
      │          │          │
      └──────────┴──────────┘
                 │
                 ▼
             QrArtifact

CLI = argument parsing + stdout/file adapter only
```

Application code should depend on `qrpen` public exports, not `_legacy` or other private implementation modules.

## Testing

```bash
coverage run -m pytest
coverage report
```

The project config enforces a 90% coverage gate for the supported public package surface. Tests cover all output modes, exact custom-URI preservation, size metadata, responsive SVG invariants, PNG dimensions, terminal framing, CLI stdout/files, validation, error correction levels, and QR version growth.

## Examples

- `examples/python_api.py` — custom URI + companion instruction + hook artifact.
- `examples/responsive_svg.py` — responsive viewBox-only SVG.

## Compatibility

- Python 3.13+
- No runtime dependencies
- UTF-8 text payloads
- QR versions 1–10

## License

MIT.

<!-- exactus:inventory:start -->
## Directory contents

### Files

- [`LICENSE`](LICENSE) — Provide LICENSE project content.
- [`__init__.py`](__init__.py) — QRpen public API.
- [`__main__.py`](__main__.py) — Execute QRpen as ``python -m qrpen``.
- [`api.py`](api.py) — Side-effect-free QRpen embedding API.
- [`cli.py`](cli.py) — Thin QRpen command-line adapter.
- [`config.py`](config.py) — Load ``\[tool.qrpen\]`` settings from the nearest ``pyproject.toml``.
- [`engine.py`](engine.py) — QRpen: dependency-free QR generation for Python, prompts, and terminals.
- [`errors.py`](errors.py) — QRpen exception hierarchy.
- [`models.py`](models.py) — Typed public models for QRpen.
- [`pyproject.toml`](pyproject.toml) — Provide pyproject toml content.

### Subdirectories

- [`examples/`](examples/README.md) — Runnable examples for the qrpen package.

<!-- exactus:inventory:end -->
