Skip to main content

XTL (Excel Template Language) 0.1 — Python reference implementation

Project description

xtl-py

A Python reference implementation of XTL (Excel Template Language) 0.1 — a host-language–agnostic templating language that turns an .xlsx template plus an .xlsx data workbook into one or more rendered output workbooks.

xtl-py is the second implementation of the language, built alongside the TypeScript reference impl as portability validation: if both implementations produce identical output for the same conformance corpus, the spec is real.

  • Spec & TS reference: https://github.com/jinyoung4478/xl3
  • Conformance status: 88 / 89 stage-1 fixtures passing (98.9%). The single remaining failure (048-if-and-comparison-boundaries) is a documented TS-impl bug where the IF-condition normalizer omits = from its operator table — see PORTING_NOTES.md and issue #1 for details.

Install

pip install xtl-py

⚠️ The PyPI distribution name is xtl-py but the import name is xl3 (matching the TS package on npm).

from xl3 import convert  # NOT `import xtl_py`

Requires Python ≥ 3.11.

Quick start

from xl3 import convert

with open("template.xlsx", "rb") as f:
    template = f.read()
with open("data.xlsx", "rb") as f:
    data = f.read()

output_files = convert(template, data)

for f in output_files:
    with open(f.filename, "wb") as out:
        out.write(f.data)
    print("wrote", f.filename)

Runtime inputs (ADR-0010)

from xl3 import convert, ConvertOptions

output = convert(
    template,
    data,
    ConvertOptions(inputs={"month": "2026-05", "region": "Seoul"}),
)

Inspecting a template

from xl3 import preview, read_template_inputs

# Lightweight: returns parsed file/sheet/row counts + warnings without rendering.
result = preview(template, data)

# Just the input declarations (for building a host UI).
specs = read_template_inputs(template)

Structured errors

from xl3 import convert, is_xtl_error

try:
    convert(template, data)
except Exception as e:
    if is_xtl_error(e):
        print(e.code, e)  # e.g. "xl3/source/sheet-missing", message
    else:
        raise

Every spec-defined error carries a stable xl3/<category>/<id> code per ADR-0015. The English message is the conformance contract; hosts should dispatch on code.

Conformance runner

The package ships a CLI runner that implements conformance/runner-protocol.md:

# Full stage-1 run against an xl3 fixture directory
python -m xl3.runner --fixture-dir /path/to/xl3/conformance/fixtures

# JSON report
python -m xl3.runner --report json

# Filter
python -m xl3.runner --filter substitution
python -m xl3.runner --id-prefix 050

Output sample:

xl3-py 0.1.0a0 — XTL 0.1 (stage 1)
  pass   001-bracket-substitution
  pass   002-if-function
  ...
summary: 88/89 passed, 1 failed, 5 skipped

What is supported

Surface Status
Bracket substitution {{ [Col] }}
IF / IFEMPTY / ROUND / ABS / TEXT / TODAY / ROW
Aggregates SUM / COUNT / AVERAGE / MIN / MAX
XLOOKUP (3-arg + 4-arg)
Directives @filter / @sort / @top / @repeat right / @source / @join
__config__ / __inputs__ / __sources__ / __lists__ reserved sheets
ADR-0007 / 0008 / 0009 / 0017 value model ✅ (82 unit tests pinning the contract)
ADR-0002 filename sanitization
ADR-0003 numFmt-driven coercion
ADR-0010 runtime inputs (text / number / date / select)
ADR-0012 multi-source data model
ADR-0013 XLOOKUP cross-source
ADR-0014 single inner @join
ADR-0016 file/sheet group splitting (first-seen order)
Stage-2 canonical OOXML comparison ❌ (out of scope for v0.1; deferred)

Architecture

Pure-Python, sync API, single dependency on openpyxl for Excel I/O.

src/xl3/
├── __init__.py        # public API
├── errors.py          # XtlError + ADR-0015 stable code catalog
├── value_model.py     # is_empty / is_truthy / canonical_string /
│                      # canonical_number / compare_values
├── expression.py      # cell-template lexer + recursive-descent parser
├── evaluator.py       # AST eval + ROW / aggregates / XLOOKUP
├── functions.py       # IF / IFEMPTY / ROUND / ABS / TEXT / TODAY
├── directives.py      # @filter / @sort / @top / @repeat / @source / @join
│                      # + row-set transform pipeline
├── inputs.py          # ADR-0010 input resolution
├── filename.py        # ADR-0002 sanitization
├── parser.py          # template workbook → block plan
├── reader.py          # source workbook reader (multi-source)
├── renderer.py        # block-based renderer with file/sheet groups
├── pipeline.py        # convert / preview / read_template_inputs
└── runner/            # conformance runner CLI

Status

Pre-1.0 / alpha. API surface mirrors the TS reference. Breaking changes are possible until the spec freezes at XTL 1.0; see spec/STABILITY.md in the spec repo.

License

MIT — see the spec repo's LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xtl_py-0.1.0a1.tar.gz (75.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xtl_py-0.1.0a1-py3-none-any.whl (52.5 kB view details)

Uploaded Python 3

File details

Details for the file xtl_py-0.1.0a1.tar.gz.

File metadata

  • Download URL: xtl_py-0.1.0a1.tar.gz
  • Upload date:
  • Size: 75.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for xtl_py-0.1.0a1.tar.gz
Algorithm Hash digest
SHA256 a72a4afa138b85a6fe63a9f3c5ef097b021af60546abce6884f82b359d341728
MD5 a6ee91945bd3862a678aac611e8b6137
BLAKE2b-256 6eb9f7cf56baf6aa4ec7740bd56cc92ee212c36ce5c299545f78336a26140cec

See more details on using hashes here.

File details

Details for the file xtl_py-0.1.0a1-py3-none-any.whl.

File metadata

  • Download URL: xtl_py-0.1.0a1-py3-none-any.whl
  • Upload date:
  • Size: 52.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for xtl_py-0.1.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 469870517d8787bd63d90ab975b42ca5af6d9cb30bda9caa4b6ccdb32ff42794
MD5 1d07a6f86bb8a3a51780fc8306f2fc9f
BLAKE2b-256 916e71109cb2d097b9e02c059a7424424f31b2feb539d2a00e52c134ded187bd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page