Skip to main content

etapsky-sdf

SDF (Smart Document Format) Python reference implementation — producer, reader, validator, signer.

License: BUSL-1.1

SDF is an open file format that combines a human-readable PDF layer with a machine-readable JSON layer in a single file. etapsky-sdf is the Python reference implementation of the SDF specification.


Installation

pip install etapsky-sdf

Or from source (monorepo):

cd packages/sdf-python
pip install -e ".[dev]"

Requirements: Python 3.11+, jsonschema, reportlab, cryptography


Quick start

Produce a .sdf file

from sdf import build_sdf

schema = {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "required": ["document_type", "invoice_number"],
    "properties": {
        "document_type": {"type": "string"},
        "invoice_number": {"type": "string"},
        "total": {
            "type": "object",
            "properties": {
                "amount": {"type": "string"},
                "currency": {"type": "string"},
            },
        },
    },
}

data = {
    "document_type": "invoice",
    "invoice_number": "INV-2026-001",
    "total": {"amount": "1250.00", "currency": "EUR"},
}

buffer = build_sdf(
    data,
    schema,
    issuer="Acme Supplies GmbH",
    issuer_id="DE123456789",
    document_type="invoice",
    recipient="Global Logistics AG",
)

with open("invoice.sdf", "wb") as f:
    f.write(buffer)

Read and validate a .sdf file

from sdf import parse_sdf

with open("invoice.sdf", "rb") as f:
    buffer = f.read()

result = parse_sdf(buffer)

print(result.meta.document_id)    # UUID v4
print(result.meta.sdf_version)   # '0.1'
print(result.data["invoice_number"])  # 'INV-2026-001'
# result.pdf_bytes — serve to a PDF viewer for human review

Validate schema directly

from sdf import validate_schema, validate_schema_or_throw

result = validate_schema(data, schema)
if not result.valid:
    print(result.errors)
else:
    print("Valid")

# Or raise on invalid:
validate_schema_or_throw(data, schema)

Sign and verify

from sdf import (
    generate_key_pair,
    export_public_key,
    export_private_key,
    import_public_key,
    import_private_key,
    sign_sdf,
    verify_sig,
)

# Generate ECDSA P-256 key pair
priv, pub = generate_key_pair("ECDSA")

# Export / import (Base64 SPKI / PKCS#8)
pub_b64 = export_public_key(pub)
priv_b64 = export_private_key(priv)
pub = import_public_key(pub_b64)
priv = import_private_key(priv_b64)

# Sign
signed = sign_sdf(buffer, priv, include_pdf=True)

# Verify
ok = verify_sig(signed, pub)
assert ok

API

Producer — sdf.build_sdf

build_sdf(data, schema, issuer, *, issuer_id=None, document_type=None, recipient=None, recipient_id=None, schema_id=None, tags=None) -> bytes

Produces a .sdf file buffer. Validates data against schema before producing — raises SDFValidationError on failure.

Reader — sdf.parse_sdf

parse_sdf(buffer: bytes | bytearray) -> SDFParseResult

Reads and validates a .sdf buffer. Returns SDFParseResult(meta, data, schema, pdf_bytes).

Validator — sdf.validate_*

  • validate_meta(meta) -> SDFMeta — Validates meta.json against normative schema
  • validate_schema(data, schema) -> SDFValidationResult — Returns {valid, errors}
  • validate_schema_or_throw(data, schema) — Raises SDFValidationError on failure

Signer — sdf.signer

  • generate_key_pair(algorithm="ECDSA") — ECDSA P-256 or RSA 2048
  • export_public_key, export_private_key, import_public_key, import_private_key
  • sign_sdf(buffer, private_key, *, include_pdf=True, algorithm="ECDSA") -> bytes
  • verify_sig(buffer, public_key, *, include_pdf=None) -> bool

Error handling

All errors extend SDFError with a code field:

from sdf import parse_sdf, SDFError, SDF_ERRORS

try:
    result = parse_sdf(buffer)
except SDFError as e:
    if e.code == SDF_ERRORS["NOT_ZIP"]:
        ...
    elif e.code == SDF_ERRORS["SCHEMA_MISMATCH"]:
        ...

Examples

cd packages/sdf-python
python examples/produce_invoice.py   # creates invoice.sdf
python examples/read_invoice.py [path.sdf]
python examples/sign_and_verify.py

Tests

cd packages/sdf-python
pip install -e ".[dev]"
pytest

What is SDF?

A .sdf file is a ZIP archive containing:

invoice.sdf
├── visual.pdf      ← human-readable layer (any PDF viewer)
├── data.json       ← machine-readable layer
├── schema.json     ← validation rules
├── meta.json       ← identity and provenance
└── signature.sig   ← digital signature (optional)

License

BUSL-1.1 — Copyright (c) 2026 Yunus YILDIZ

See LICENSE and the root LICENSE for terms.

Metadata

Release files for etapsky-sdf 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for etapsky-sdf 0.1.1
File Size Uploaded
etapsky_sdf-0.1.1.tar.gz 13.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for etapsky-sdf 0.1.1
File Interpreter ABI Platform
etapsky_sdf-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 29.3 kB

Release files / etapsky_sdf-0.1.1.tar.gz

Download URL etapsky_sdf-0.1.1.tar.gz
Size 13.9 kB
Tags Source
SHA-256 checksum
How to use checksums
fdb21d6de1ecef8c28d75b5edc3870e76913655e1753c7394f3a8b1e7f9ff118
BLAKE2b-256 checksum
How to use checksums
14657dc152d7d2af15333f4c7847a3ec10be417ec0adbd6c056f0c41b75d3563
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.2

Release files / etapsky_sdf-0.1.1-py3-none-any.whl

Download URL etapsky_sdf-0.1.1-py3-none-any.whl
Size 15.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
409bdb9afe7f58482543a8bc8c245f598e52eb1fffec1bc52929a9095d7d6a28
BLAKE2b-256 checksum
How to use checksums
cb433ed58079aba4e14e76bb7c53dad90e83a72db4a9ffe421d640b5b5c7a258
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.2

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page