jsonl-diff 0.1.1__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/PKG-INFO +46 -33
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/README.md +45 -32
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/jsonl_diff.egg-info/PKG-INFO +46 -33
- jsonl_diff-0.1.2/jsonl_diff.py +1373 -0
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/pyproject.toml +1 -1
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/tests/test_cli.py +307 -1
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/tests/test_diff.py +356 -5
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/tests/test_sources.py +31 -0
- jsonl_diff-0.1.1/jsonl_diff.py +0 -758
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/LICENSE +0 -0
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/jsonl_diff.egg-info/SOURCES.txt +0 -0
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/jsonl_diff.egg-info/dependency_links.txt +0 -0
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/jsonl_diff.egg-info/entry_points.txt +0 -0
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/jsonl_diff.egg-info/requires.txt +0 -0
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/jsonl_diff.egg-info/top_level.txt +0 -0
- {jsonl_diff-0.1.1 → jsonl_diff-0.1.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jsonl-diff
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: A lightweight, pure-Python tool for comparing large JSONL/NDJSON datasets without loading them entirely into memory.
|
|
5
5
|
Author-email: rmoralespp <rmoralespp@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -67,11 +67,8 @@ Compare large JSONL/NDJSON datasets **by record identity instead of line
|
|
|
67
67
|
position**, without loading the complete inputs into memory.
|
|
68
68
|
|
|
69
69
|
`jsonl-diff` matches records using one or more top-level fields and reports:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
* `added`
|
|
73
|
-
* `deleted`
|
|
74
|
-
* `modified`
|
|
70
|
+
`equal`, `added`, `deleted`, `modified`, and tolerated duplicates in each
|
|
71
|
+
source.
|
|
75
72
|
|
|
76
73
|
It is useful for snapshots, ETL validation, migrations, exports, and CI checks.
|
|
77
74
|
|
|
@@ -79,10 +76,8 @@ It is useful for snapshots, ETL validation, migrations, exports, and CI checks.
|
|
|
79
76
|
|
|
80
77
|
## Installation
|
|
81
78
|
|
|
82
|
-
Python 3.8–3.14.
|
|
83
|
-
|
|
84
79
|
```bash
|
|
85
|
-
|
|
80
|
+
pip install jsonl-diff
|
|
86
81
|
```
|
|
87
82
|
|
|
88
83
|
## Quick start
|
|
@@ -114,6 +109,8 @@ Records:
|
|
|
114
109
|
added: 1
|
|
115
110
|
deleted: 0
|
|
116
111
|
modified: 1
|
|
112
|
+
OLD duplicates: 0
|
|
113
|
+
NEW duplicates: 0
|
|
117
114
|
```
|
|
118
115
|
|
|
119
116
|
Record order does not matter.
|
|
@@ -121,14 +118,15 @@ Record order does not matter.
|
|
|
121
118
|
## Features
|
|
122
119
|
|
|
123
120
|
* Single or composite top-level identities.
|
|
124
|
-
* Disk-backed comparison for large datasets ([architecture](docs/architecture.md)).
|
|
125
|
-
* Optional JMESPath filtering with `--where`.
|
|
126
|
-
* Configurable duplicate handling: `error`, `first`, or `last`.
|
|
127
|
-
* Exact RFC 6901 JSON Pointer ignores.
|
|
121
|
+
* Disk-backed comparison for large datasets ([architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md)).
|
|
122
|
+
* Optional **JMESPath** filtering with `--where`.
|
|
123
|
+
* Configurable duplicate handling with counts and diagnostics: `error`, `first`, or `last`.
|
|
124
|
+
* Exact **RFC 6901** JSON Pointer ignores.
|
|
125
|
+
* Optional disk-backed observed-schema diff for fields, types, nullability, and requiredness.
|
|
128
126
|
* Semantic number comparison using `Decimal`.
|
|
129
127
|
* Deterministic summaries and change iteration.
|
|
130
128
|
* Original OLD/NEW physical line numbers.
|
|
131
|
-
* Machine-readable JSONL change log with `--details` ([format](docs/details-format.md)).
|
|
129
|
+
* Machine-readable JSONL change log with `--details` ([format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md)).
|
|
132
130
|
* Local, HTTP/HTTPS, file-like, and supported compressed sources.
|
|
133
131
|
* CLI and Python API using the same comparison engine.
|
|
134
132
|
|
|
@@ -137,7 +135,7 @@ Record order does not matter.
|
|
|
137
135
|
```text
|
|
138
136
|
jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
|
|
139
137
|
[--duplicates {error,first,last}] [--details FILE] [--quiet]
|
|
140
|
-
[--max-temp MAX_TEMP]
|
|
138
|
+
[--schema-diff] [--schema-ignore POINTER] [--max-temp MAX_TEMP]
|
|
141
139
|
old new
|
|
142
140
|
```
|
|
143
141
|
|
|
@@ -147,10 +145,12 @@ jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
|
|
|
147
145
|
| `--key KEY` | Required top-level identity field; repeat or comma-separate for composite keys |
|
|
148
146
|
| `--ignore POINTER` | RFC 6901 pointer to exclude from content comparison |
|
|
149
147
|
| `--where EXPRESSION` | JMESPath filter applied to each record |
|
|
150
|
-
| `--duplicates POLICY` | `error` (default),
|
|
148
|
+
| `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last` |
|
|
151
149
|
| `--details FILE` | Write deterministic machine-readable JSONL changes |
|
|
150
|
+
| `--schema-diff` | Compare observed fields, types, nullability, and requiredness |
|
|
151
|
+
| `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling |
|
|
152
152
|
| `--quiet` | Suppress the normal summary |
|
|
153
|
-
| `--max-temp BYTES` |
|
|
153
|
+
| `--max-temp BYTES` | Best-effort budget for `jsonl-diff` workspace temporary storage |
|
|
154
154
|
|
|
155
155
|
Examples:
|
|
156
156
|
|
|
@@ -169,18 +169,24 @@ jsonl-diff old.jsonl new.jsonl \
|
|
|
169
169
|
--key id \
|
|
170
170
|
--where 'deleted_at == `null`'
|
|
171
171
|
|
|
172
|
+
# Detect observed schema drift
|
|
173
|
+
jsonl-diff old.jsonl new.jsonl \
|
|
174
|
+
--key id \
|
|
175
|
+
--schema-diff \
|
|
176
|
+
--schema-ignore /metadata
|
|
177
|
+
|
|
172
178
|
# Compressed input
|
|
173
179
|
jsonl-diff old.jsonl.xz new.jsonl.gz --key id
|
|
174
180
|
```
|
|
175
181
|
|
|
176
182
|
### Exit codes
|
|
177
183
|
|
|
178
|
-
| Code | Meaning
|
|
179
|
-
| ---: |
|
|
180
|
-
| `0` |
|
|
181
|
-
| `1` |
|
|
182
|
-
| `2` | Input, resource, output, or runtime error
|
|
183
|
-
| `3` | Invalid CLI configuration or usage
|
|
184
|
+
| Code | Meaning |
|
|
185
|
+
| ---: | ---------------------------------------------------------- |
|
|
186
|
+
| `0` | No record, duplicate, or requested observed-schema issues |
|
|
187
|
+
| `1` | Record differences, tolerated duplicates, or schema changes |
|
|
188
|
+
| `2` | Input, resource, output, or runtime error |
|
|
189
|
+
| `3` | Invalid CLI configuration or usage |
|
|
184
190
|
|
|
185
191
|
## Python API
|
|
186
192
|
|
|
@@ -193,11 +199,15 @@ with diff(
|
|
|
193
199
|
key=("country", "customerId"),
|
|
194
200
|
ignore=("/updated_at",),
|
|
195
201
|
where='country == `"ES"`',
|
|
202
|
+
schema_diff=True,
|
|
196
203
|
) as result:
|
|
197
204
|
print(result.summary)
|
|
198
205
|
|
|
199
206
|
for change in result.changes(ChangeOperation.MODIFIED):
|
|
200
207
|
print(change.key, change.old_line, change.new_line)
|
|
208
|
+
|
|
209
|
+
for change in result.schema_changes():
|
|
210
|
+
print(change.operation, change.path)
|
|
201
211
|
```
|
|
202
212
|
|
|
203
213
|
`diff()` returns a disk-backed `DiffResult`, used as a context manager.
|
|
@@ -220,7 +230,7 @@ The public exception hierarchy is rooted at `JsonlDiffError`:
|
|
|
220
230
|
* `DuplicateKeyError`
|
|
221
231
|
* `ResourceError`
|
|
222
232
|
|
|
223
|
-
See the [Python API reference](docs/python-api.md) for the full callable
|
|
233
|
+
See the [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) for the full callable
|
|
224
234
|
signature, result models, `Decimal` key semantics, and error hierarchy.
|
|
225
235
|
|
|
226
236
|
## Comparison semantics
|
|
@@ -231,15 +241,18 @@ signature, result models, `Decimal` key semantics, and error hierarchy.
|
|
|
231
241
|
* Blank lines, malformed JSON, duplicate properties, `NaN`, and infinities are rejected.
|
|
232
242
|
* Identity fields must be top-level scalar values (`null` allowed only as one component of a composite key).
|
|
233
243
|
* Identity types remain significant: `"1"` ≠ `1`, `true` ≠ `1`.
|
|
234
|
-
* Duplicate identities fail by default; `--duplicates first`/`last`
|
|
244
|
+
* Duplicate identities fail by default; `--duplicates first`/`last` select one
|
|
245
|
+
occurrence, report every discarded occurrence, and return exit code `1`.
|
|
235
246
|
* Object property order is ignored; array order is significant.
|
|
236
247
|
* Numbers are compared by mathematical value: `1`, `1.0`, and `1e0` are equal.
|
|
237
248
|
* Unicode strings are compared without normalization.
|
|
238
249
|
* Changes are reported in deterministic identity order.
|
|
239
250
|
|
|
240
251
|
`--where` selects which records participate; `--key` defines identity;
|
|
241
|
-
`--ignore` removes fields from content comparison.
|
|
242
|
-
|
|
252
|
+
`--ignore` removes fields from content comparison. With `--schema-diff`,
|
|
253
|
+
`--schema-ignore` independently removes fields from observed-schema profiling.
|
|
254
|
+
See
|
|
255
|
+
[Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) for the full rules,
|
|
243
256
|
including duplicate handling, ignore-pointer edge cases, `--where` evaluation
|
|
244
257
|
order, and canonical number formatting.
|
|
245
258
|
|
|
@@ -255,7 +268,7 @@ Supported compression:
|
|
|
255
268
|
* xz
|
|
256
269
|
* Zstandard on Python 3.14
|
|
257
270
|
|
|
258
|
-
See [architecture](docs/architecture.md) for the full source/compression
|
|
271
|
+
See [architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) for the full source/compression
|
|
259
272
|
support matrix and how sources are delegated to `py-jsonl`.
|
|
260
273
|
|
|
261
274
|
## Limitations
|
|
@@ -268,7 +281,7 @@ support matrix and how sources are delegated to `py-jsonl`.
|
|
|
268
281
|
* nested identities or automatic key detection
|
|
269
282
|
* fuzzy matching or numeric tolerances
|
|
270
283
|
* unordered-array comparison
|
|
271
|
-
* schema
|
|
284
|
+
* validation against a declared schema or input repair
|
|
272
285
|
* ZIP, database, or cloud-provider inputs
|
|
273
286
|
* GUI or HTML reports
|
|
274
287
|
|
|
@@ -276,10 +289,10 @@ It is a **dataset reconciliation tool**, not a general-purpose visual JSON diff.
|
|
|
276
289
|
|
|
277
290
|
## Further reading
|
|
278
291
|
|
|
279
|
-
* [Comparison semantics](docs/comparison-semantics.md) — identity, duplicates, ignores, `--where`, canonical numbers, determinism.
|
|
280
|
-
* [Disk-backed architecture](docs/architecture.md) — SQLite index, `max_temp`, cleanup, sources and compression.
|
|
281
|
-
* [Details JSONL format](docs/details-format.md) — machine-readable `--details` output schema.
|
|
282
|
-
* [Python API reference](docs/python-api.md) — full signature, result models, and error hierarchy.
|
|
292
|
+
* [Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) — identity, duplicates, ignores, `--where`, canonical numbers, determinism.
|
|
293
|
+
* [Disk-backed architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) — SQLite index, `max_temp`, cleanup, sources and compression.
|
|
294
|
+
* [Details JSONL format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md) — machine-readable `--details` output schema.
|
|
295
|
+
* [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) — full signature, result models, and error hierarchy.
|
|
283
296
|
|
|
284
297
|
## Development
|
|
285
298
|
|
|
@@ -12,11 +12,8 @@ Compare large JSONL/NDJSON datasets **by record identity instead of line
|
|
|
12
12
|
position**, without loading the complete inputs into memory.
|
|
13
13
|
|
|
14
14
|
`jsonl-diff` matches records using one or more top-level fields and reports:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* `added`
|
|
18
|
-
* `deleted`
|
|
19
|
-
* `modified`
|
|
15
|
+
`equal`, `added`, `deleted`, `modified`, and tolerated duplicates in each
|
|
16
|
+
source.
|
|
20
17
|
|
|
21
18
|
It is useful for snapshots, ETL validation, migrations, exports, and CI checks.
|
|
22
19
|
|
|
@@ -24,10 +21,8 @@ It is useful for snapshots, ETL validation, migrations, exports, and CI checks.
|
|
|
24
21
|
|
|
25
22
|
## Installation
|
|
26
23
|
|
|
27
|
-
Python 3.8–3.14.
|
|
28
|
-
|
|
29
24
|
```bash
|
|
30
|
-
|
|
25
|
+
pip install jsonl-diff
|
|
31
26
|
```
|
|
32
27
|
|
|
33
28
|
## Quick start
|
|
@@ -59,6 +54,8 @@ Records:
|
|
|
59
54
|
added: 1
|
|
60
55
|
deleted: 0
|
|
61
56
|
modified: 1
|
|
57
|
+
OLD duplicates: 0
|
|
58
|
+
NEW duplicates: 0
|
|
62
59
|
```
|
|
63
60
|
|
|
64
61
|
Record order does not matter.
|
|
@@ -66,14 +63,15 @@ Record order does not matter.
|
|
|
66
63
|
## Features
|
|
67
64
|
|
|
68
65
|
* Single or composite top-level identities.
|
|
69
|
-
* Disk-backed comparison for large datasets ([architecture](docs/architecture.md)).
|
|
70
|
-
* Optional JMESPath filtering with `--where`.
|
|
71
|
-
* Configurable duplicate handling: `error`, `first`, or `last`.
|
|
72
|
-
* Exact RFC 6901 JSON Pointer ignores.
|
|
66
|
+
* Disk-backed comparison for large datasets ([architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md)).
|
|
67
|
+
* Optional **JMESPath** filtering with `--where`.
|
|
68
|
+
* Configurable duplicate handling with counts and diagnostics: `error`, `first`, or `last`.
|
|
69
|
+
* Exact **RFC 6901** JSON Pointer ignores.
|
|
70
|
+
* Optional disk-backed observed-schema diff for fields, types, nullability, and requiredness.
|
|
73
71
|
* Semantic number comparison using `Decimal`.
|
|
74
72
|
* Deterministic summaries and change iteration.
|
|
75
73
|
* Original OLD/NEW physical line numbers.
|
|
76
|
-
* Machine-readable JSONL change log with `--details` ([format](docs/details-format.md)).
|
|
74
|
+
* Machine-readable JSONL change log with `--details` ([format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md)).
|
|
77
75
|
* Local, HTTP/HTTPS, file-like, and supported compressed sources.
|
|
78
76
|
* CLI and Python API using the same comparison engine.
|
|
79
77
|
|
|
@@ -82,7 +80,7 @@ Record order does not matter.
|
|
|
82
80
|
```text
|
|
83
81
|
jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
|
|
84
82
|
[--duplicates {error,first,last}] [--details FILE] [--quiet]
|
|
85
|
-
[--max-temp MAX_TEMP]
|
|
83
|
+
[--schema-diff] [--schema-ignore POINTER] [--max-temp MAX_TEMP]
|
|
86
84
|
old new
|
|
87
85
|
```
|
|
88
86
|
|
|
@@ -92,10 +90,12 @@ jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
|
|
|
92
90
|
| `--key KEY` | Required top-level identity field; repeat or comma-separate for composite keys |
|
|
93
91
|
| `--ignore POINTER` | RFC 6901 pointer to exclude from content comparison |
|
|
94
92
|
| `--where EXPRESSION` | JMESPath filter applied to each record |
|
|
95
|
-
| `--duplicates POLICY` | `error` (default),
|
|
93
|
+
| `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last` |
|
|
96
94
|
| `--details FILE` | Write deterministic machine-readable JSONL changes |
|
|
95
|
+
| `--schema-diff` | Compare observed fields, types, nullability, and requiredness |
|
|
96
|
+
| `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling |
|
|
97
97
|
| `--quiet` | Suppress the normal summary |
|
|
98
|
-
| `--max-temp BYTES` |
|
|
98
|
+
| `--max-temp BYTES` | Best-effort budget for `jsonl-diff` workspace temporary storage |
|
|
99
99
|
|
|
100
100
|
Examples:
|
|
101
101
|
|
|
@@ -114,18 +114,24 @@ jsonl-diff old.jsonl new.jsonl \
|
|
|
114
114
|
--key id \
|
|
115
115
|
--where 'deleted_at == `null`'
|
|
116
116
|
|
|
117
|
+
# Detect observed schema drift
|
|
118
|
+
jsonl-diff old.jsonl new.jsonl \
|
|
119
|
+
--key id \
|
|
120
|
+
--schema-diff \
|
|
121
|
+
--schema-ignore /metadata
|
|
122
|
+
|
|
117
123
|
# Compressed input
|
|
118
124
|
jsonl-diff old.jsonl.xz new.jsonl.gz --key id
|
|
119
125
|
```
|
|
120
126
|
|
|
121
127
|
### Exit codes
|
|
122
128
|
|
|
123
|
-
| Code | Meaning
|
|
124
|
-
| ---: |
|
|
125
|
-
| `0` |
|
|
126
|
-
| `1` |
|
|
127
|
-
| `2` | Input, resource, output, or runtime error
|
|
128
|
-
| `3` | Invalid CLI configuration or usage
|
|
129
|
+
| Code | Meaning |
|
|
130
|
+
| ---: | ---------------------------------------------------------- |
|
|
131
|
+
| `0` | No record, duplicate, or requested observed-schema issues |
|
|
132
|
+
| `1` | Record differences, tolerated duplicates, or schema changes |
|
|
133
|
+
| `2` | Input, resource, output, or runtime error |
|
|
134
|
+
| `3` | Invalid CLI configuration or usage |
|
|
129
135
|
|
|
130
136
|
## Python API
|
|
131
137
|
|
|
@@ -138,11 +144,15 @@ with diff(
|
|
|
138
144
|
key=("country", "customerId"),
|
|
139
145
|
ignore=("/updated_at",),
|
|
140
146
|
where='country == `"ES"`',
|
|
147
|
+
schema_diff=True,
|
|
141
148
|
) as result:
|
|
142
149
|
print(result.summary)
|
|
143
150
|
|
|
144
151
|
for change in result.changes(ChangeOperation.MODIFIED):
|
|
145
152
|
print(change.key, change.old_line, change.new_line)
|
|
153
|
+
|
|
154
|
+
for change in result.schema_changes():
|
|
155
|
+
print(change.operation, change.path)
|
|
146
156
|
```
|
|
147
157
|
|
|
148
158
|
`diff()` returns a disk-backed `DiffResult`, used as a context manager.
|
|
@@ -165,7 +175,7 @@ The public exception hierarchy is rooted at `JsonlDiffError`:
|
|
|
165
175
|
* `DuplicateKeyError`
|
|
166
176
|
* `ResourceError`
|
|
167
177
|
|
|
168
|
-
See the [Python API reference](docs/python-api.md) for the full callable
|
|
178
|
+
See the [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) for the full callable
|
|
169
179
|
signature, result models, `Decimal` key semantics, and error hierarchy.
|
|
170
180
|
|
|
171
181
|
## Comparison semantics
|
|
@@ -176,15 +186,18 @@ signature, result models, `Decimal` key semantics, and error hierarchy.
|
|
|
176
186
|
* Blank lines, malformed JSON, duplicate properties, `NaN`, and infinities are rejected.
|
|
177
187
|
* Identity fields must be top-level scalar values (`null` allowed only as one component of a composite key).
|
|
178
188
|
* Identity types remain significant: `"1"` ≠ `1`, `true` ≠ `1`.
|
|
179
|
-
* Duplicate identities fail by default; `--duplicates first`/`last`
|
|
189
|
+
* Duplicate identities fail by default; `--duplicates first`/`last` select one
|
|
190
|
+
occurrence, report every discarded occurrence, and return exit code `1`.
|
|
180
191
|
* Object property order is ignored; array order is significant.
|
|
181
192
|
* Numbers are compared by mathematical value: `1`, `1.0`, and `1e0` are equal.
|
|
182
193
|
* Unicode strings are compared without normalization.
|
|
183
194
|
* Changes are reported in deterministic identity order.
|
|
184
195
|
|
|
185
196
|
`--where` selects which records participate; `--key` defines identity;
|
|
186
|
-
`--ignore` removes fields from content comparison.
|
|
187
|
-
|
|
197
|
+
`--ignore` removes fields from content comparison. With `--schema-diff`,
|
|
198
|
+
`--schema-ignore` independently removes fields from observed-schema profiling.
|
|
199
|
+
See
|
|
200
|
+
[Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) for the full rules,
|
|
188
201
|
including duplicate handling, ignore-pointer edge cases, `--where` evaluation
|
|
189
202
|
order, and canonical number formatting.
|
|
190
203
|
|
|
@@ -200,7 +213,7 @@ Supported compression:
|
|
|
200
213
|
* xz
|
|
201
214
|
* Zstandard on Python 3.14
|
|
202
215
|
|
|
203
|
-
See [architecture](docs/architecture.md) for the full source/compression
|
|
216
|
+
See [architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) for the full source/compression
|
|
204
217
|
support matrix and how sources are delegated to `py-jsonl`.
|
|
205
218
|
|
|
206
219
|
## Limitations
|
|
@@ -213,7 +226,7 @@ support matrix and how sources are delegated to `py-jsonl`.
|
|
|
213
226
|
* nested identities or automatic key detection
|
|
214
227
|
* fuzzy matching or numeric tolerances
|
|
215
228
|
* unordered-array comparison
|
|
216
|
-
* schema
|
|
229
|
+
* validation against a declared schema or input repair
|
|
217
230
|
* ZIP, database, or cloud-provider inputs
|
|
218
231
|
* GUI or HTML reports
|
|
219
232
|
|
|
@@ -221,10 +234,10 @@ It is a **dataset reconciliation tool**, not a general-purpose visual JSON diff.
|
|
|
221
234
|
|
|
222
235
|
## Further reading
|
|
223
236
|
|
|
224
|
-
* [Comparison semantics](docs/comparison-semantics.md) — identity, duplicates, ignores, `--where`, canonical numbers, determinism.
|
|
225
|
-
* [Disk-backed architecture](docs/architecture.md) — SQLite index, `max_temp`, cleanup, sources and compression.
|
|
226
|
-
* [Details JSONL format](docs/details-format.md) — machine-readable `--details` output schema.
|
|
227
|
-
* [Python API reference](docs/python-api.md) — full signature, result models, and error hierarchy.
|
|
237
|
+
* [Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) — identity, duplicates, ignores, `--where`, canonical numbers, determinism.
|
|
238
|
+
* [Disk-backed architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) — SQLite index, `max_temp`, cleanup, sources and compression.
|
|
239
|
+
* [Details JSONL format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md) — machine-readable `--details` output schema.
|
|
240
|
+
* [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) — full signature, result models, and error hierarchy.
|
|
228
241
|
|
|
229
242
|
## Development
|
|
230
243
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jsonl-diff
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: A lightweight, pure-Python tool for comparing large JSONL/NDJSON datasets without loading them entirely into memory.
|
|
5
5
|
Author-email: rmoralespp <rmoralespp@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -67,11 +67,8 @@ Compare large JSONL/NDJSON datasets **by record identity instead of line
|
|
|
67
67
|
position**, without loading the complete inputs into memory.
|
|
68
68
|
|
|
69
69
|
`jsonl-diff` matches records using one or more top-level fields and reports:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
* `added`
|
|
73
|
-
* `deleted`
|
|
74
|
-
* `modified`
|
|
70
|
+
`equal`, `added`, `deleted`, `modified`, and tolerated duplicates in each
|
|
71
|
+
source.
|
|
75
72
|
|
|
76
73
|
It is useful for snapshots, ETL validation, migrations, exports, and CI checks.
|
|
77
74
|
|
|
@@ -79,10 +76,8 @@ It is useful for snapshots, ETL validation, migrations, exports, and CI checks.
|
|
|
79
76
|
|
|
80
77
|
## Installation
|
|
81
78
|
|
|
82
|
-
Python 3.8–3.14.
|
|
83
|
-
|
|
84
79
|
```bash
|
|
85
|
-
|
|
80
|
+
pip install jsonl-diff
|
|
86
81
|
```
|
|
87
82
|
|
|
88
83
|
## Quick start
|
|
@@ -114,6 +109,8 @@ Records:
|
|
|
114
109
|
added: 1
|
|
115
110
|
deleted: 0
|
|
116
111
|
modified: 1
|
|
112
|
+
OLD duplicates: 0
|
|
113
|
+
NEW duplicates: 0
|
|
117
114
|
```
|
|
118
115
|
|
|
119
116
|
Record order does not matter.
|
|
@@ -121,14 +118,15 @@ Record order does not matter.
|
|
|
121
118
|
## Features
|
|
122
119
|
|
|
123
120
|
* Single or composite top-level identities.
|
|
124
|
-
* Disk-backed comparison for large datasets ([architecture](docs/architecture.md)).
|
|
125
|
-
* Optional JMESPath filtering with `--where`.
|
|
126
|
-
* Configurable duplicate handling: `error`, `first`, or `last`.
|
|
127
|
-
* Exact RFC 6901 JSON Pointer ignores.
|
|
121
|
+
* Disk-backed comparison for large datasets ([architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md)).
|
|
122
|
+
* Optional **JMESPath** filtering with `--where`.
|
|
123
|
+
* Configurable duplicate handling with counts and diagnostics: `error`, `first`, or `last`.
|
|
124
|
+
* Exact **RFC 6901** JSON Pointer ignores.
|
|
125
|
+
* Optional disk-backed observed-schema diff for fields, types, nullability, and requiredness.
|
|
128
126
|
* Semantic number comparison using `Decimal`.
|
|
129
127
|
* Deterministic summaries and change iteration.
|
|
130
128
|
* Original OLD/NEW physical line numbers.
|
|
131
|
-
* Machine-readable JSONL change log with `--details` ([format](docs/details-format.md)).
|
|
129
|
+
* Machine-readable JSONL change log with `--details` ([format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md)).
|
|
132
130
|
* Local, HTTP/HTTPS, file-like, and supported compressed sources.
|
|
133
131
|
* CLI and Python API using the same comparison engine.
|
|
134
132
|
|
|
@@ -137,7 +135,7 @@ Record order does not matter.
|
|
|
137
135
|
```text
|
|
138
136
|
jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
|
|
139
137
|
[--duplicates {error,first,last}] [--details FILE] [--quiet]
|
|
140
|
-
[--max-temp MAX_TEMP]
|
|
138
|
+
[--schema-diff] [--schema-ignore POINTER] [--max-temp MAX_TEMP]
|
|
141
139
|
old new
|
|
142
140
|
```
|
|
143
141
|
|
|
@@ -147,10 +145,12 @@ jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
|
|
|
147
145
|
| `--key KEY` | Required top-level identity field; repeat or comma-separate for composite keys |
|
|
148
146
|
| `--ignore POINTER` | RFC 6901 pointer to exclude from content comparison |
|
|
149
147
|
| `--where EXPRESSION` | JMESPath filter applied to each record |
|
|
150
|
-
| `--duplicates POLICY` | `error` (default),
|
|
148
|
+
| `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last` |
|
|
151
149
|
| `--details FILE` | Write deterministic machine-readable JSONL changes |
|
|
150
|
+
| `--schema-diff` | Compare observed fields, types, nullability, and requiredness |
|
|
151
|
+
| `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling |
|
|
152
152
|
| `--quiet` | Suppress the normal summary |
|
|
153
|
-
| `--max-temp BYTES` |
|
|
153
|
+
| `--max-temp BYTES` | Best-effort budget for `jsonl-diff` workspace temporary storage |
|
|
154
154
|
|
|
155
155
|
Examples:
|
|
156
156
|
|
|
@@ -169,18 +169,24 @@ jsonl-diff old.jsonl new.jsonl \
|
|
|
169
169
|
--key id \
|
|
170
170
|
--where 'deleted_at == `null`'
|
|
171
171
|
|
|
172
|
+
# Detect observed schema drift
|
|
173
|
+
jsonl-diff old.jsonl new.jsonl \
|
|
174
|
+
--key id \
|
|
175
|
+
--schema-diff \
|
|
176
|
+
--schema-ignore /metadata
|
|
177
|
+
|
|
172
178
|
# Compressed input
|
|
173
179
|
jsonl-diff old.jsonl.xz new.jsonl.gz --key id
|
|
174
180
|
```
|
|
175
181
|
|
|
176
182
|
### Exit codes
|
|
177
183
|
|
|
178
|
-
| Code | Meaning
|
|
179
|
-
| ---: |
|
|
180
|
-
| `0` |
|
|
181
|
-
| `1` |
|
|
182
|
-
| `2` | Input, resource, output, or runtime error
|
|
183
|
-
| `3` | Invalid CLI configuration or usage
|
|
184
|
+
| Code | Meaning |
|
|
185
|
+
| ---: | ---------------------------------------------------------- |
|
|
186
|
+
| `0` | No record, duplicate, or requested observed-schema issues |
|
|
187
|
+
| `1` | Record differences, tolerated duplicates, or schema changes |
|
|
188
|
+
| `2` | Input, resource, output, or runtime error |
|
|
189
|
+
| `3` | Invalid CLI configuration or usage |
|
|
184
190
|
|
|
185
191
|
## Python API
|
|
186
192
|
|
|
@@ -193,11 +199,15 @@ with diff(
|
|
|
193
199
|
key=("country", "customerId"),
|
|
194
200
|
ignore=("/updated_at",),
|
|
195
201
|
where='country == `"ES"`',
|
|
202
|
+
schema_diff=True,
|
|
196
203
|
) as result:
|
|
197
204
|
print(result.summary)
|
|
198
205
|
|
|
199
206
|
for change in result.changes(ChangeOperation.MODIFIED):
|
|
200
207
|
print(change.key, change.old_line, change.new_line)
|
|
208
|
+
|
|
209
|
+
for change in result.schema_changes():
|
|
210
|
+
print(change.operation, change.path)
|
|
201
211
|
```
|
|
202
212
|
|
|
203
213
|
`diff()` returns a disk-backed `DiffResult`, used as a context manager.
|
|
@@ -220,7 +230,7 @@ The public exception hierarchy is rooted at `JsonlDiffError`:
|
|
|
220
230
|
* `DuplicateKeyError`
|
|
221
231
|
* `ResourceError`
|
|
222
232
|
|
|
223
|
-
See the [Python API reference](docs/python-api.md) for the full callable
|
|
233
|
+
See the [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) for the full callable
|
|
224
234
|
signature, result models, `Decimal` key semantics, and error hierarchy.
|
|
225
235
|
|
|
226
236
|
## Comparison semantics
|
|
@@ -231,15 +241,18 @@ signature, result models, `Decimal` key semantics, and error hierarchy.
|
|
|
231
241
|
* Blank lines, malformed JSON, duplicate properties, `NaN`, and infinities are rejected.
|
|
232
242
|
* Identity fields must be top-level scalar values (`null` allowed only as one component of a composite key).
|
|
233
243
|
* Identity types remain significant: `"1"` ≠ `1`, `true` ≠ `1`.
|
|
234
|
-
* Duplicate identities fail by default; `--duplicates first`/`last`
|
|
244
|
+
* Duplicate identities fail by default; `--duplicates first`/`last` select one
|
|
245
|
+
occurrence, report every discarded occurrence, and return exit code `1`.
|
|
235
246
|
* Object property order is ignored; array order is significant.
|
|
236
247
|
* Numbers are compared by mathematical value: `1`, `1.0`, and `1e0` are equal.
|
|
237
248
|
* Unicode strings are compared without normalization.
|
|
238
249
|
* Changes are reported in deterministic identity order.
|
|
239
250
|
|
|
240
251
|
`--where` selects which records participate; `--key` defines identity;
|
|
241
|
-
`--ignore` removes fields from content comparison.
|
|
242
|
-
|
|
252
|
+
`--ignore` removes fields from content comparison. With `--schema-diff`,
|
|
253
|
+
`--schema-ignore` independently removes fields from observed-schema profiling.
|
|
254
|
+
See
|
|
255
|
+
[Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) for the full rules,
|
|
243
256
|
including duplicate handling, ignore-pointer edge cases, `--where` evaluation
|
|
244
257
|
order, and canonical number formatting.
|
|
245
258
|
|
|
@@ -255,7 +268,7 @@ Supported compression:
|
|
|
255
268
|
* xz
|
|
256
269
|
* Zstandard on Python 3.14
|
|
257
270
|
|
|
258
|
-
See [architecture](docs/architecture.md) for the full source/compression
|
|
271
|
+
See [architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) for the full source/compression
|
|
259
272
|
support matrix and how sources are delegated to `py-jsonl`.
|
|
260
273
|
|
|
261
274
|
## Limitations
|
|
@@ -268,7 +281,7 @@ support matrix and how sources are delegated to `py-jsonl`.
|
|
|
268
281
|
* nested identities or automatic key detection
|
|
269
282
|
* fuzzy matching or numeric tolerances
|
|
270
283
|
* unordered-array comparison
|
|
271
|
-
* schema
|
|
284
|
+
* validation against a declared schema or input repair
|
|
272
285
|
* ZIP, database, or cloud-provider inputs
|
|
273
286
|
* GUI or HTML reports
|
|
274
287
|
|
|
@@ -276,10 +289,10 @@ It is a **dataset reconciliation tool**, not a general-purpose visual JSON diff.
|
|
|
276
289
|
|
|
277
290
|
## Further reading
|
|
278
291
|
|
|
279
|
-
* [Comparison semantics](docs/comparison-semantics.md) — identity, duplicates, ignores, `--where`, canonical numbers, determinism.
|
|
280
|
-
* [Disk-backed architecture](docs/architecture.md) — SQLite index, `max_temp`, cleanup, sources and compression.
|
|
281
|
-
* [Details JSONL format](docs/details-format.md) — machine-readable `--details` output schema.
|
|
282
|
-
* [Python API reference](docs/python-api.md) — full signature, result models, and error hierarchy.
|
|
292
|
+
* [Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) — identity, duplicates, ignores, `--where`, canonical numbers, determinism.
|
|
293
|
+
* [Disk-backed architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) — SQLite index, `max_temp`, cleanup, sources and compression.
|
|
294
|
+
* [Details JSONL format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md) — machine-readable `--details` output schema.
|
|
295
|
+
* [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) — full signature, result models, and error hierarchy.
|
|
283
296
|
|
|
284
297
|
## Development
|
|
285
298
|
|