Metadata-Version: 2.4
Name: larztable
Version: 0.1.0
Summary: Query and render tabular data in one small object: fluent filter/sort/aggregate + pretty terminal tables, CSV, Markdown. Pure Python, zero dependencies.
Author: larz-scripter
License: MIT
Project-URL: Homepage, https://github.com/larz-scripter/larztable
Project-URL: Repository, https://github.com/larz-scripter/larztable
Project-URL: Documentation, https://github.com/larz-scripter/larztable#readme
Project-URL: Issues, https://github.com/larz-scripter/larztable/issues
Keywords: table,tabular,csv,query,dataframe,pretty-print,tabulate-alternative,terminal-table,zero-dependency,pure-python
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# larztable

**Query *and* render tabular data — in one small object. Zero dependencies.**

Most tools make you choose: a query/dataframe library (heavy) or a pretty-printer
(no querying). larztable is both, tiny. Load rows, filter/sort/aggregate them
with a fluent Django-style API, then print a clean terminal table or export to
CSV/Markdown — no pandas, no tabulate.

```python
from larztable import Table

t = Table.from_dicts([
    {"name": "Ada", "age": 36, "role": "admin"},
    {"name": "Bo",  "age": 24, "role": "user"},
    {"name": "Cy",  "age": 41, "role": "user"},
])

print(t.where(role="user").sort("age", reverse=True).select("name", "age"))
```

```
┌──────┬─────┐
│ name │ age │
├──────┼─────┤
│ Cy   │  41 │
│ Bo   │  24 │
└──────┴─────┘
```

## Why

- **One tool for both jobs.** Querying and presenting are the same object:
  `.where()`, `.sort()`, `.select()`, `.limit()`, `.group_by()`, aggregates — then
  `print(t)`, `t.to_csv()`, `t.to_markdown()`.
- **Expressive filters.** Django-style lookups —
  `where(age__gt=30, role="user", name__icontains="a")` — plus arbitrary
  predicate functions.
- **Reads like data.** Numbers auto-right-align in the Unicode table; CSV
  round-trips; Markdown for docs and PRs.
- **Zero dependencies.** No pandas, no tabulate, no numpy.

## Install

```bash
pip install larztable
```

## Query

```python
t.where(role="admin")                       # equality
t.where(age__gte=30, age__lt=40)            # gt/gte/lt/lte/ne/in/contains/...
t.where(lambda r: r["age"] % 2 == 0)        # any predicate
t.sort("age", reverse=True)
t.select("name", "age")
t.limit(10, offset=5)
t.distinct("role")

# aggregates
t.count(); t.sum("age"); t.avg("age"); t.min("age"); t.max("age")
t.group_by("role").count()                  # Table of role, count
t.group_by("role").avg("age")               # Table of role, age_avg
```

Every query returns a **new** Table (the original is untouched), so chains are
safe.

## Load & export

```python
Table.from_csv("data.csv")
Table.from_csv_string("name,age\nAda,36\n")
Table.from_dicts([...])
Table.from_rows([["Ada", 36]], columns=["name", "age"])

t.to_csv("out.csv"); t.to_csv()             # string
t.to_markdown()
t.to_dicts(); t.to_rows()
print(t)                                    # pretty terminal table
```

## Tests

```bash
python -m unittest discover -s tests -v   # 27 tests, zero deps
```

## The Larz stack

Pure-Python, zero-dependency building blocks: **[larz](https://github.com/larz-scripter/larz)** · **[larzchain](https://github.com/larz-scripter/larzchain)** · **[larzmoney](https://github.com/larz-scripter/larzmoney)** · **[larzcrypt](https://github.com/larz-scripter/larzcrypt)** · **[larzdb](https://github.com/larz-scripter/larzdb)** · **[larzagent](https://github.com/larz-scripter/larzagent)** · **[larzchart](https://github.com/larz-scripter/larzchart)** · **[larzmark](https://github.com/larz-scripter/larzmark)** · **[larztask](https://github.com/larz-scripter/larztask)** · **[larzvault](https://github.com/larz-scripter/larzvault)** · **[larzvm](https://github.com/larz-scripter/larzvm)** · **[larzcache](https://github.com/larz-scripter/larzcache)** · **[larzvalidate](https://github.com/larz-scripter/larzvalidate)** · **[larzid](https://github.com/larz-scripter/larzid)** · **[larzrpc](https://github.com/larz-scripter/larzrpc)** · **[larzstate](https://github.com/larz-scripter/larzstate)** · **[larzhttp](https://github.com/larz-scripter/larzhttp)** · **[larzconf](https://github.com/larz-scripter/larzconf)** · **[larzcron](https://github.com/larz-scripter/larzcron)** · **[larzlimit](https://github.com/larz-scripter/larzlimit)** · **[larzlog](https://github.com/larz-scripter/larzlog)** · **[larzcli](https://github.com/larz-scripter/larzcli)** · **[larzretry](https://github.com/larz-scripter/larzretry)** · **[larztime](https://github.com/larz-scripter/larztime)** · **[larzpdf](https://github.com/larz-scripter/larzpdf)** · **[larzpack](https://github.com/larz-scripter/larzpack)** · **[larztemplate](https://github.com/larz-scripter/larztemplate)** · **[larzcolor](https://github.com/larz-scripter/larzcolor)** · **larztable**

## License

MIT © larz-scripter
