Skip to main content

text-spreadsheet for Python

Let a language model read a whole multi-sheet spreadsheet as text. The model calls one tool with the path of a file, or a folder of files, on your machine, and Excel, ODS, CSV, JSON, SQLite, Parquet, Arrow and MTSV come back as MTSV: one plain-text file where a tab separates fields, a line break separates records, and a form feed separates sheets.

A language model reads text, so a binary workbook is a dead end — without pandas or openpyxl in the loop, it cannot see inside an .xlsx at all. This converts the whole file, every sheet, in one call, so the model reads a spreadsheet the way it reads any other text file.

Install

In an environment of its own:

pipx install text-spreadsheet

Then tell your host to launch text-spreadsheet, with no arguments. It is one entry, once — after that the tool is in every session. Most hosts read a configuration file:

{
  "mcpServers": {
    "text-spreadsheet": {
      "command": "text-spreadsheet"
    }
  }
}

Some hosts use servers instead of mcpServers and add a type, and some have their own command that writes the file for you.

The version is the version field of pyproject.toml, and versions follow Semantic Versioning.

The tool

The model calls read with a path, of a file or of a folder:

read("/home/me/book.xlsx")

and gets a map: the files, their sheets, how many records each holds and how many a filter keeps, the columns of each, where each sheet's lines are, and what each conversion left behind.

<FF>file
file	source	artifact	converted	status
1	/home/me/book.xlsx	/home/me/.cache/text-spreadsheet/home/me/book.xlsx.mtsv	yes	read
<FF>sheets
sheet	file	sheet name	records	matches	first line	last line
1	1	People	4	4	1	6
2	1	Orders	200	200	7	208
<FF>columns
sheet	position	field name
1	1	Name
1	2	Age
<FF>left behind
file	what
1	cell type n

Adding a position returns that part instead of the map:

read("/home/me/book.xlsx", sheet="2")
read("/home/me/book.xlsx", sheet="2", rows="40-120")
read("/home/me/book.xlsx", sheet="2", rows="40-*", fields="2;4")

Each position counts from 1 and is written as 2, 1;3, 1-3 or 2-*, as RFC 7111 writes a selection of a tabular file. Positions that do not exist are left out; an address not written that way is refused.

A filter keeps the records whose fields meet a condition, written as an RFC 9535 filter: @[0] is a record's first field.

read("/home/me/book.xlsx", filter="@[2] == 'open'")
read("/home/me/book.xlsx", sheet="2", rows="1-50", filter="search(@[1], 'Ltd')")

With no position, the map counts the matches of each sheet; with one, rows counts the records the filter keeps. Text is compared exactly, and patterns are I-Regexp: [0-9], not \d.

A folder is read without its subfolders and without names that begin with a dot, in name order, and its sheets are numbered across its files. A file with no format, or one that cannot be read, is named in the map with its status, and the others are still read.

What is kept

Every conversion leaves an MTSV copy of the file under your cache directory — ~/.cache/text-spreadsheet on Linux, ~/Library/Caches/text-spreadsheet on macOS — mirroring the path of the file it came from, with .mtsv added to its name, and what the conversion left behind beside it, with -metadata.mtsv added. A later call reads that copy unless the file has changed since, and the map names where it is, so it can also be read directly. An MTSV file is read where it is, and not copied.

Nothing else is kept, and nothing outside this machine is contacted.

As a library

from text_spreadsheet import read

text = read("/home/me/book.xlsx")

read returns MTSV text, whatever the format it came from, and takes the same sheet, rows, fields and filter as the tool. Whatever a spreadsheet holds that MTSV does not — formatting, formulas, types — is left behind, and named in the map.

Layout

Each module hides one decision, named beside it.

src/text_spreadsheet/
  _field         what a field can hold, and how text it cannot is written
  _positions     how a list of positions is written, and what it names
  _filter        how a filter is written, and which records it keeps
  _selection     which sheets, records and fields a call names
  _left_behind   what an integration left behind, as it reported it
  _cache         where a copy and its metadata live, and when fresh
  _conversion    how one file becomes MTSV text
  _input         what a path names: a file, or a folder of files
  _map           what a group of files is made of
  __init__       the operation: input, selection, and the reply
  _server        the tool, the server, and how a refusal is reported
  __main__       the command a host launches
tests/           one test file per module above

Use points one way: __main__ to _server to read; read to _input, _filter, _selection and _map; _input to _conversion and _field; _conversion to _cache, _field and _left_behind; _map to _field; _selection to _positions. Nothing points back up, and nothing but _server knows the protocol.

Test

From the root of the repository:

python3 -m venv .venv
.venv/bin/pip install ./python
.venv/bin/python -m unittest discover -s python/tests

License

MIT

Metadata

Release files for text-spreadsheet 0.3.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 text-spreadsheet 0.3.0
File Size Uploaded
text_spreadsheet-0.3.0.tar.gz 17.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for text-spreadsheet 0.3.0
File Interpreter ABI Platform
text_spreadsheet-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 37.2 kB

Release files / text_spreadsheet-0.3.0.tar.gz

Download URL text_spreadsheet-0.3.0.tar.gz
Size 17.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e02c66ce9a876987f3001bdf420171c43b4e550df74639e0b9406548a58385f2
BLAKE2b-256 checksum
How to use checksums
046558d6600dd3d000b6f3737cb39183cac580f2ac3173df6f0e7591306e9904
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / text_spreadsheet-0.3.0-py3-none-any.whl

Download URL text_spreadsheet-0.3.0-py3-none-any.whl
Size 19.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3a786d97d14351cb34c27590045f348505b0d2c95171603ebb5b392c2fe318d9
BLAKE2b-256 checksum
How to use checksums
52d7d7b141092768fa09e54d6825420bef954c9be3db74af3a1df72aabb08770
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.1

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

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