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.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 tablewise 1.1.1
File Size Uploaded Provenance
tablewise-1.1.1.tar.gz 62.3 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 95.2 kB

Release files / tablewise-1.1.1.tar.gz

Download URL tablewise-1.1.1.tar.gz
Size 62.3 kB
Tags Source
SHA-256 checksum
How to use checksums
daa61b7cc937dc13ba43e2a25e972b2a0c25585ded12bfd67f134314aa3e52a1
BLAKE2b-256 checksum
How to use checksums
815de062d9efae4d2ea14664a539b022f27e80267542b4f511dab8adf18e1c06
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.1-py3-none-any.whl

Download URL tablewise-1.1.1-py3-none-any.whl
Size 32.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
42ac958e2e623ddec93b525c6c9b195fbf25144204771bde9cd2f49981e52b03
BLAKE2b-256 checksum
How to use checksums
d686b01af836d74d00d59ec2ef725592148d7451292bcd8801e537355704a3e8
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.1

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.1 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