Skip to main content

Tablewise

Spreadsheet-grade document conversion to Markdown, with provenance. PDF, Word, Excel and PowerPoint in; clean, citable Markdown out — built for RAG, LLM ingestion and audit trails.

Every output file starts with a header that tells your retrieval layer where the text came from:

---
source: "2026-budget.xlsx"
engine: "excel"
converted: 2026-10-22
---

Three front ends, one decision engine:

  • tablewise CLI — one document in, one .md out. Scripts, agents, batches.
  • Desktop app (Tkinter) — for people who do not live in a terminal.
  • Hosted API — POST /v1/convert, per-month plans, no install. See PRICING.md.

The problem it solves

Most converters flatten a financial table into something no model can use. A three-level header (Hotel · 2026 · Real/Budget · Jan..Dec) comes out as 70 columns named Unnamed: 12, formulas vanish, and a percentage becomes 0.8769. A RAG built on that answers with the wrong number and no way to prove it.

Tablewise routes spreadsheets to an engine that reads the sheet as a sheet:

| Hotel | 2026 | 2026 | 2026 | | | Real | Budget | Last year | | | Jan | Feb | Jan | | ADR | 120.50 | 110 | 105.25 | | Occupancy | 87.69% | | |

  • Merged cells and multi-level headers preserved as a real Markdown table.
  • Dates as YYYY-MM-DD, percentages with their format, -0.00 never appears.
  • Hidden sheets kept but labelled (hidden sheet).
  • A formula that was never recalculated says (formula not calculated) instead of an empty cell that a model reads as zero.
  • Deterministic: no AI, no network, same bytes in → same Markdown out.

Quickstart

pip install -e .            # installs the `tablewise` command
tablewise report.pdf                    # -> ~/md-repo/report.md
tablewise budget.xlsx -o ~/md-repo -n "2026 budget"
tablewise contract.docx --dry-run       # print the engine command, do not run it

The desktop app:

python tablewise_app.py

The API:

curl -X POST https://api.tablewise.dev/v1/convert \
  -H "Authorization: Bearer $TABLEWISE_API_KEY" \
  -F "file=@budget.xlsx"

Why not just MarkItDown / Docling?

They are good engines and Tablewise uses both. The difference is the routing, the table fidelity and the provenance — not a new parser.

MarkItDown Docling Tablewise
Excel with merged / multi-level header flattened partial read as a sheet
Formula never recalculated empty cell empty cell labelled
Provenance header on every file no no yes
Deterministic, no AI, no network yes yes (heavy) yes
Desktop GUI for non-technical users no no yes
Hosted API with per-month plans and batch no no yes

Engine routing

Each extension has exactly one owner:

  • .xlsx .xlsm .xltx .xltm → motor_excel.py (openpyxl, local, no AI)
  • .pdf .docx .pptx → motor_docling.py (Docling, local, no AI)
  • .doc .rtf .odt → textutil (macOS) → HTML → motor_docling.py
  • .xls .ppt (Office 97-2003) → LibreOffice → .xlsx/.pptx → motor_excel.py / motor_docling.py
  • everything else (CSV, HTML, EPUB, …) → MarkItDown

The two own engines are motor_excel.py and motor_docling.py. A format without an available engine is refused with an explicit message, never silently degraded.

CLI reference

tablewise DOCUMENT [-o DIR] [-n NAME] [--python PATH] [--markitdown PATH]
                   [--force] [--dry-run] [-q] [--version]
  • Never overwrites an existing .md without --force.
  • Exit codes: 0 ok · 1 the engine produced no file · 2 invalid input.
  • --python / TABLEWISE_PYTHON: interpreter that carries docling/openpyxl.
  • --markitdown / TABLEWISE_MARKITDOWN: MarkItDown executable.

Hosted API

The API is the same engine behind HTTP, for teams that cannot install anything:

Plan Units / month Price
Free 50 $0
Starter 1,000 $19
Pro 5,000 $49
Business 25,000 $149

One unit = one PDF page, one spreadsheet sheet, one slide, or one document. Overage $0.015/unit. Annual −20%. The full contract (quota, DPA, refunds) is in PRICING.md and on the website.

Development

Runner: pytest, using the engines virtualenv (it carries openpyxl and PyYAML):

.venv/bin/python3 -m pytest -q              # 432 tests
.venv/bin/python3 -m pytest server/tests -q # 46 API tests
File What it covers
tests/test_core.py tablewise_core.py: extension routing, safe names, engine command (shlex, ~), YAML frontmatter, atomic write, free name
tests/test_motor_excel.py motor_excel.py on synthetic books: merged cells, unevaluated formulas, empty rows/columns, dates, hidden sheets, safety ceiling
tests/test_cli_motores.py engine CLI contract by subprocess (exit code + message, never a traceback)
tests/test_motor_docling.py .doc/.rtf/.odt preconversion to HTML with textutil (no Docling import; skipped off macOS)
tests/test_preconversion.py LibreOffice (soffice): lookup outside PATH and .xls → .xlsx keeping merges (skipped without LibreOffice)
tests/test_preconversion_errores.py preconversion.py with simulated subprocess.run: timeout, tool that cannot start, exit 0 without file, error code, own profile
tests/test_motor_docling_convertir.py motor_docling.convertir with an injected fake Docling: empty output, temp cleanup, .ppt routing, uppercase extensions
tests/test_entradas_externas.py .xls path, malformed array formulas, backslashes in the YAML header, non-UTF-8 output, BOM and CRLF
tests/test_preconversion_ejecutables_falsos.py textutil/LibreOffice boundary with fake executables
tests/test_app_convertir.py App.convert() with fake tkinter and engine: existing .md (cancel / numbered copy / overwrite), failing engine, non-UTF-8 output, partial writes
tests/test_motor_docling_cli.py motor_docling CLI with a fake docling package
tests/test_red_sintaxis.py regression net: every application file is valid Python and the app imports without opening a window
tests/test_cli.py tablewise CLI: same decisions as the app, --dry-run, no overwrite without --force, exit codes
tests/test_docs.py drift net: this README lists every test file and every routed extension

No test uses real documents.

Limits and security

  • Upload limit 25 MB and 2,000 units per request (configurable).
  • Engines run as subprocesses with a timeout; a hung converter cannot take the worker down.
  • API keys are stored as SHA-256 hashes and shown once.
  • No document content is logged. See web/privacy.html and web/dpa.html.
  • macOS-only pieces: textutil (.doc/.rtf/.odt) and the Tkinter app. LibreOffice is needed for .xls/.ppt.

License

MIT. See LICENSE.


Spanish engineering log, kept for continuity: README.es.md.

Metadata

Release files for tablewise 1.1.0

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

Source distribution (sdist)

Source distribution for tablewise 1.1.0
File Size Uploaded Provenance
tablewise-1.1.0.tar.gz 62.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for tablewise 1.1.0
File Interpreter ABI Platform
tablewise-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 94.9 kB

Release files / tablewise-1.1.0.tar.gz

Download URL tablewise-1.1.0.tar.gz
Size 62.1 kB
Tags Source
SHA-256 checksum
How to use checksums
9f65582fa9301a389e8de586acb8c68edea1ac5ffcd9a04fa6f2f97f9535722c
BLAKE2b-256 checksum
How to use checksums
14c4aa4010243d09297b61ce0b1b6a3058cb6a3e8177ac57537d10d74d15b02c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / tablewise-1.1.0-py3-none-any.whl

Download URL tablewise-1.1.0-py3-none-any.whl
Size 32.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2fa615eb7d6d8cf5cadc0c73395dcf21a7d5db8645a7ed7dfebc507f06c67e10
BLAKE2b-256 checksum
How to use checksums
631785c3000e444b5815777ee5e55d4531abfbf04e925627592518daa863046c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Security for tablewise 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files No provenance

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