Skip to content

Commit 8279539

Browse files
committed
docs(readme): update readme
1 parent d01f188 commit 8279539

1 file changed

Lines changed: 107 additions & 99 deletions

File tree

README.md

Lines changed: 107 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,194 +1,202 @@
1-
# JSONLT Python package
1+
# jsonlt
22

33
<!-- vale off -->
4+
[![PyPI](https://img.shields.io/pypi/v/jsonlt-python)](https://pypi.org/project/jsonlt-python/)
45
[![CI](https://github.com/jsonlt/jsonlt-python/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/jsonlt/jsonlt-python/actions/workflows/ci.yml)
56
[![Codecov](https://codecov.io/gh/jsonlt/jsonlt-python/branch/main/graph/badge.svg)](https://codecov.io/gh/jsonlt/jsonlt-python)
6-
[![CodSpeed Badge](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/jsonlt/jsonlt-python?utm_source=badge)
7+
[![CodSpeed Badge](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/jsonlt/jsonlt-python)
78
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
89
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT)
910
<!-- vale on -->
1011

11-
**jsonlt** is the Python reference implementation of the [JSON Lines Table (JSONLT) specification][jsonlt].
12-
13-
JSONLT is a data format for storing keyed records in append-only files using [JSON Lines](https://jsonlines.org/). The format optimizes for version control diffs and human readability.
12+
The Python reference implementation of [JSONLT (JSON Lines Table)](https://jsonlt.org), a data format for storing keyed records in append-only files. JSONLT builds on [JSON Lines](https://jsonlines.org/) and optimizes for version control. Modifications append new lines rather than rewriting existing content, producing clean and meaningful diffs.
1413

1514
> [!NOTE]
16-
> This package is in development and not yet ready for production use.
15+
> This package is under active development. The API may change before the 1.0 release.
16+
17+
## Resources
18+
19+
- [Specification](https://spec.jsonlt.org): formal definition of the JSONLT format
20+
- [Documentation](https://docs.jsonlt.org): guides, tutorials, and API reference
21+
- [Conformance tests](https://github.com/jsonlt/jsonlt/tree/main/conformance): language-agnostic test suite
1722

1823
## Installation
1924

2025
```bash
21-
pip install jsonlt-python
26+
pip install --pre jsonlt-python
2227

2328
# Or
2429

25-
uv add jsonlt-python
30+
uv add --pre jsonlt-python
2631
```
2732

28-
## Quick start
33+
Requires Python 3.10 or later.
2934

30-
### Basic operations
35+
## Quick start
3136

3237
```python
3338
from jsonlt import Table
3439

35-
# Open or create a table with a simple key
40+
# Open or create a table
3641
table = Table("users.jsonlt", key="id")
3742

3843
# Insert or update records
3944
table.put({"id": "alice", "role": "admin", "email": "alice@example.com"})
4045
table.put({"id": "bob", "role": "user", "email": "bob@example.com"})
4146

42-
# Read a record by key
43-
user = table.get("alice")
44-
print(user) # {"id": "alice", "role": "admin", "email": "alice@example.com"}
45-
46-
# Check if a key exists
47-
if table.has("bob"):
48-
print("Bob exists")
47+
# Read records
48+
user = table.get("alice") # Returns the record or None
49+
exists = table.has("bob") # Returns True
4950

50-
# Delete a record
51+
# Delete records (appends a tombstone)
5152
table.delete("bob")
5253

53-
# Get all records
54+
# Iterate over all records
5455
for record in table.all():
5556
print(record)
5657
```
5758

58-
### Compound keys
59+
The underlying file after these operations:
5960

60-
JSONLT supports multi-field compound keys:
61+
```jsonl
62+
{"id": "alice", "role": "admin", "email": "alice@example.com"}
63+
{"id": "bob", "role": "user", "email": "bob@example.com"}
64+
{"id": "bob", "$deleted": true}
65+
```
66+
67+
## When to use JSONLT
68+
69+
JSONLT works well for configuration, metadata, and small-to-medium datasets where you want human-readable files that play nicely with Git. It's a good fit when you need keyed record storage but don't want the overhead of a database, and when you want to see exactly what changed in a pull request.
70+
71+
JSONLT is not a database. For large datasets, high write throughput, query operations, or concurrent multi-process access, consider SQLite or a full-featured database.
72+
73+
## Compound keys
74+
75+
JSONLT supports multi-field compound keys for composite identifiers:
6176

6277
```python
63-
# Using a tuple of field names for compound keys
6478
orders = Table("orders.jsonlt", key=("customer_id", "order_id"))
6579

6680
orders.put({"customer_id": "alice", "order_id": 1, "total": 99.99})
6781
orders.put({"customer_id": "alice", "order_id": 2, "total": 149.99})
6882

69-
# Access with compound key
7083
order = orders.get(("alice", 1))
7184
```
7285

73-
### Transactions
86+
## Transactions
7487

75-
Use transactions for atomic updates with conflict detection:
88+
Transactions provide snapshot isolation and atomic writes with conflict detection:
7689

7790
```python
7891
from jsonlt import Table, ConflictError
7992

8093
table = Table("counters.jsonlt", key="name")
8194

82-
# Context manager commits on success, aborts on exception
8395
with table.transaction() as tx:
8496
counter = tx.get("visits")
85-
if counter:
86-
tx.put({"name": "visits", "count": counter["count"] + 1})
87-
else:
88-
tx.put({"name": "visits", "count": 1})
97+
new_count = (counter["count"] + 1) if counter else 1
98+
tx.put({"name": "visits", "count": new_count})
99+
# Commits automatically; rolls back on exception
89100

90-
# Handle conflicts from concurrent modifications
101+
# Handle concurrent modification conflicts
91102
try:
92103
with table.transaction() as tx:
93104
tx.put({"name": "counter", "value": 42})
94105
except ConflictError as e:
95106
print(f"Conflict on key: {e.key}")
96107
```
97108

98-
### Finding records
109+
## Finding records
99110

100111
```python
101-
from jsonlt import Table
102-
103-
table = Table("products.jsonlt", key="sku")
104-
105112
# Find all records matching a predicate
106113
expensive = table.find(lambda r: r.get("price", 0) > 100)
107114

108115
# Find with limit
109-
top_3 = table.find(lambda r: r.get("in_stock", False), limit=3)
116+
top_3 = table.find(lambda r: r.get("in_stock"), limit=3)
110117

111-
# Find the first matching record
112-
first_match = table.find_one(lambda r: r.get("category") == "electronics")
118+
# Find the first match
119+
first = table.find_one(lambda r: r.get("category") == "electronics")
113120
```
114121

115-
### Table maintenance
122+
## Maintenance
116123

117124
```python
118-
from jsonlt import Table
119-
120-
table = Table("data.jsonlt", key="id")
121-
122-
# Compact the table (removes tombstones and superseded records)
125+
# Compact the file (removes tombstones and superseded records)
123126
table.compact()
124127

125-
# Clear all records (keeps header if present)
128+
# Clear all records
126129
table.clear()
127-
```
128130

129-
## API overview
130-
131-
### Table class
132-
133-
The `Table` class is the primary interface for working with JSONLT files.
131+
# Force reload from disk
132+
table.reload()
133+
```
134134

135-
| Method | Description |
136-
|-------------------------------|--------------------------------------------------|
137-
| `Table(path, key)` | Open or create a table at the given path |
138-
| `get(key)` | Get a record by key, returns `None` if not found |
139-
| `has(key)` | Check if a key exists |
140-
| `put(record)` | Insert or update a record |
141-
| `delete(key)` | Delete a record, returns whether it existed |
142-
| `all()` | Get all records in key order |
143-
| `keys()` | Get all keys in key order |
144-
| `items()` | Get all (key, record) pairs in key order |
145-
| `count()` | Get the number of records |
146-
| `find(predicate, limit=None)` | Find records matching a predicate |
147-
| `find_one(predicate)` | Find the first matching record |
148-
| `transaction()` | Start a new transaction |
149-
| `compact()` | Compact the table file |
150-
| `clear()` | Remove all records |
151-
| `reload()` | Force reload from disk |
135+
## API summary
136+
137+
### Table
138+
139+
| Method | Description |
140+
|-------------------------------|--------------------------------|
141+
| `Table(path, key)` | Open or create a table |
142+
| `get(key)` | Get a record by key, or `None` |
143+
| `has(key)` | Check if a key exists |
144+
| `put(record)` | Insert or update a record |
145+
| `delete(key)` | Delete a record |
146+
| `all()` | Iterate all records |
147+
| `keys()` | Iterate all keys |
148+
| `items()` | Iterate (key, record) pairs |
149+
| `count()` | Number of records |
150+
| `find(predicate, limit=None)` | Find matching records |
151+
| `find_one(predicate)` | Find first match |
152+
| `transaction()` | Start a transaction |
153+
| `compact()` | Remove historical entries |
154+
| `clear()` | Remove all records |
155+
| `reload()` | Reload from disk |
156+
157+
The `Table` class also supports `len(table)`, `key in table`, and `for record in table`.
158+
159+
### Transaction
160+
161+
| Method | Description |
162+
|---------------|-------------------|
163+
| `get(key)` | Get from snapshot |
164+
| `has(key)` | Check in snapshot |
165+
| `put(record)` | Buffer a write |
166+
| `delete(key)` | Buffer a deletion |
167+
| `commit()` | Write to disk |
168+
| `abort()` | Discard changes |
169+
170+
### Exceptions
152171

153-
The `Table` class also supports idiomatic Python operations:
172+
All exceptions inherit from `JSONLTError`:
154173

155-
- `len(table)` - number of records
156-
- `key in table` - check if key exists
157-
- `for record in table` - iterate over records
174+
| Exception | Description |
175+
|--------------------|---------------------------|
176+
| `ParseError` | Invalid file format |
177+
| `InvalidKeyError` | Invalid or missing key |
178+
| `FileError` | I/O error |
179+
| `LockError` | Cannot get lock |
180+
| `LimitError` | Size limit exceeded |
181+
| `TransactionError` | Invalid transaction state |
182+
| `ConflictError` | Write-write conflict |
158183

159-
### Transaction class
184+
## Conformance
160185

161-
The `Transaction` class provides snapshot isolation and buffered writes.
186+
This library implements the [JSONLT 1.0 Specification](https://jsonlt.org/spec). It provides both Lenient and Strict Parser conformance profiles, and generates Strict-conformant output by default.
162187

163-
| Method | Description |
164-
|---------------|--------------------------------------------|
165-
| `get(key)` | Get a record from the transaction snapshot |
166-
| `has(key)` | Check if a key exists in the snapshot |
167-
| `put(record)` | Buffer a record for commit |
168-
| `delete(key)` | Buffer a deletion for commit |
169-
| `commit()` | Write buffered changes to disk |
170-
| `abort()` | Discard buffered changes |
188+
As the reference implementation, jsonlt-python passes the [JSONLT conformance test suite](https://github.com/jsonlt/jsonlt/tree/main/tests). Implementers of other JSONLT libraries can use these tests to verify compatibility.
171189

172-
### Exception hierarchy
190+
## Acknowledgements
173191

174-
All exceptions inherit from `JSONLTError`:
192+
The JSONLT format draws from related work including [BEADS](https://github.com/steveyegge/beads), which uses JSONL for git-backed structured storage.
175193

176-
| Exception | Description |
177-
|--------------------|--------------------------------|
178-
| `ParseError` | Invalid file format or content |
179-
| `InvalidKeyError` | Invalid or missing key |
180-
| `FileError` | File I/O error |
181-
| `LockError` | Cannot obtain file lock |
182-
| `LimitError` | Size limit exceeded |
183-
| `TransactionError` | Transaction state error |
184-
| `ConflictError` | Write-write conflict detected |
194+
### AI disclosure
185195

186-
## Documentation
196+
The development of this library involved AI language models, specifically Claude (Anthropic). AI tools contributed to drafting code, tests, and documentation. Human authors made all design decisions and final implementations, and they reviewed, edited, and validated AI-generated content. The authors take full responsibility for the correctness of this software.
187197

188-
For detailed documentation, tutorials, and the full specification, visit [jsonlt.org/docs](https://jsonlt.org/docs).
198+
This disclosure promotes transparency about modern software development practices.
189199

190200
## License
191201

192202
MIT License. See [LICENSE](LICENSE) for details.
193-
194-
[jsonlt]: https://jsonlt.org/

0 commit comments

Comments
 (0)