jsonl-diff 0.1.4__tar.gz → 0.1.5__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.4 → jsonl_diff-0.1.5}/PKG-INFO +12 -13
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/README.md +11 -12
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/jsonl_diff.egg-info/PKG-INFO +12 -13
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/jsonl_diff.py +4 -4
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/pyproject.toml +1 -1
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/tests/test_cli.py +20 -0
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/tests/test_diff.py +44 -2
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/LICENSE +0 -0
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/jsonl_diff.egg-info/SOURCES.txt +0 -0
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/jsonl_diff.egg-info/dependency_links.txt +0 -0
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/jsonl_diff.egg-info/entry_points.txt +0 -0
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/jsonl_diff.egg-info/requires.txt +0 -0
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/jsonl_diff.egg-info/top_level.txt +0 -0
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/setup.cfg +0 -0
- {jsonl_diff-0.1.4 → jsonl_diff-0.1.5}/tests/test_sources.py +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.5
|
|
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
|
|
@@ -140,12 +140,11 @@ Record order does not matter.
|
|
|
140
140
|
* Exact **[RFC 6901](https://www.rfc-editor.org/info/rfc6901/)** JSON Pointer ignores.
|
|
141
141
|
* Optional disk-backed observed-schema diff for fields, types, nullability, and requiredness.
|
|
142
142
|
* Semantic number comparison using `Decimal`.
|
|
143
|
-
* Optional `msgspec` accelerator for ~2x faster large diffs (`pip install "jsonl-diff[speedups]"`).
|
|
144
143
|
* Deterministic summaries and change iteration.
|
|
145
144
|
* Original OLD/NEW physical line numbers.
|
|
146
145
|
* Machine-readable JSONL change log with `--details` ([format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md)).
|
|
147
146
|
* Local, HTTP/HTTPS, file-like, and supported compressed sources.
|
|
148
|
-
* Incremental top-level JSON
|
|
147
|
+
* Incremental parsing for JSONL/NDJSON by default, with support for top-level JSON arrays via `--format json`.
|
|
149
148
|
* CLI and Python API using the same comparison engine.
|
|
150
149
|
|
|
151
150
|
## CLI
|
|
@@ -165,14 +164,14 @@ jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
|
|
|
165
164
|
| `--key KEY` | Required top-level identity field; repeat or comma-separate for composite keys |
|
|
166
165
|
| `--ignore POINTER` | RFC 6901 pointer to exclude from content comparison |
|
|
167
166
|
| `--where EXPRESSION` | JMESPath filter applied to each record |
|
|
168
|
-
| `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last`
|
|
169
|
-
| `--missing-key POLICY`| `error` (default), or `null` to treat an absent identity field as `null`
|
|
167
|
+
| `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last` |
|
|
168
|
+
| `--missing-key POLICY`| `error` (default), or `null` to treat an absent identity field as `null` |
|
|
170
169
|
| `--details FILE` | Write deterministic machine-readable JSONL changes |
|
|
171
|
-
| `--schema-diff` | Compare observed fields, types, nullability, and requiredness
|
|
172
|
-
| `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling
|
|
170
|
+
| `--schema-diff` | Compare observed fields, types, nullability, and requiredness |
|
|
171
|
+
| `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling |
|
|
173
172
|
| `--quiet` | Suppress the normal summary |
|
|
174
173
|
| `--max-temp BYTES` | Best-effort budget for `jsonl-diff` workspace temporary storage |
|
|
175
|
-
| `--format FORMAT` | Input format: `jsonl` (default) or a top-level JSON array with `json`
|
|
174
|
+
| `--format FORMAT` | Input format: `jsonl` (default) or a top-level JSON array with `json` |
|
|
176
175
|
|
|
177
176
|
Examples:
|
|
178
177
|
|
|
@@ -273,7 +272,9 @@ signature, result models, `Decimal` key semantics, and error hierarchy.
|
|
|
273
272
|
elements are the records.
|
|
274
273
|
* Blank lines, malformed JSON, `NaN`, and infinities are rejected.
|
|
275
274
|
* Duplicate object property names within a record follow JSON's last-wins semantics: the last occurrence is kept.
|
|
276
|
-
* Identity fields must be top-level
|
|
275
|
+
* Identity fields must be top-level JSON values. Object member order is ignored
|
|
276
|
+
and array order is significant (`null` allowed only as one component of a
|
|
277
|
+
composite key).
|
|
277
278
|
* Identity types remain significant: `"1"` ≠ `1`, `true` ≠ `1`.
|
|
278
279
|
* Duplicate identities fail by default; `--duplicates first`/`last` select one
|
|
279
280
|
occurrence, report every discarded occurrence, and return exit code `1`.
|
|
@@ -293,9 +294,7 @@ order, and canonical number formatting.
|
|
|
293
294
|
## Sources & compression
|
|
294
295
|
|
|
295
296
|
Supported sources include local paths and HTTP/HTTPS URLs. The Python API
|
|
296
|
-
also accepts file-like objects.
|
|
297
|
-
the source and `ijson` for incremental parsing, so compression and remote
|
|
298
|
-
source handling are shared with JSONL input.
|
|
297
|
+
also accepts file-like objects.
|
|
299
298
|
|
|
300
299
|
Supported compression:
|
|
301
300
|
|
|
@@ -305,7 +304,7 @@ Supported compression:
|
|
|
305
304
|
* Zstandard on Python 3.14
|
|
306
305
|
|
|
307
306
|
See [architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) for the full source/compression
|
|
308
|
-
support matrix and how sources are
|
|
307
|
+
support matrix and how sources are managed.
|
|
309
308
|
|
|
310
309
|
## Limitations
|
|
311
310
|
|
|
@@ -82,12 +82,11 @@ Record order does not matter.
|
|
|
82
82
|
* Exact **[RFC 6901](https://www.rfc-editor.org/info/rfc6901/)** JSON Pointer ignores.
|
|
83
83
|
* Optional disk-backed observed-schema diff for fields, types, nullability, and requiredness.
|
|
84
84
|
* Semantic number comparison using `Decimal`.
|
|
85
|
-
* Optional `msgspec` accelerator for ~2x faster large diffs (`pip install "jsonl-diff[speedups]"`).
|
|
86
85
|
* Deterministic summaries and change iteration.
|
|
87
86
|
* Original OLD/NEW physical line numbers.
|
|
88
87
|
* Machine-readable JSONL change log with `--details` ([format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md)).
|
|
89
88
|
* Local, HTTP/HTTPS, file-like, and supported compressed sources.
|
|
90
|
-
* Incremental top-level JSON
|
|
89
|
+
* Incremental parsing for JSONL/NDJSON by default, with support for top-level JSON arrays via `--format json`.
|
|
91
90
|
* CLI and Python API using the same comparison engine.
|
|
92
91
|
|
|
93
92
|
## CLI
|
|
@@ -107,14 +106,14 @@ jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
|
|
|
107
106
|
| `--key KEY` | Required top-level identity field; repeat or comma-separate for composite keys |
|
|
108
107
|
| `--ignore POINTER` | RFC 6901 pointer to exclude from content comparison |
|
|
109
108
|
| `--where EXPRESSION` | JMESPath filter applied to each record |
|
|
110
|
-
| `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last`
|
|
111
|
-
| `--missing-key POLICY`| `error` (default), or `null` to treat an absent identity field as `null`
|
|
109
|
+
| `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last` |
|
|
110
|
+
| `--missing-key POLICY`| `error` (default), or `null` to treat an absent identity field as `null` |
|
|
112
111
|
| `--details FILE` | Write deterministic machine-readable JSONL changes |
|
|
113
|
-
| `--schema-diff` | Compare observed fields, types, nullability, and requiredness
|
|
114
|
-
| `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling
|
|
112
|
+
| `--schema-diff` | Compare observed fields, types, nullability, and requiredness |
|
|
113
|
+
| `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling |
|
|
115
114
|
| `--quiet` | Suppress the normal summary |
|
|
116
115
|
| `--max-temp BYTES` | Best-effort budget for `jsonl-diff` workspace temporary storage |
|
|
117
|
-
| `--format FORMAT` | Input format: `jsonl` (default) or a top-level JSON array with `json`
|
|
116
|
+
| `--format FORMAT` | Input format: `jsonl` (default) or a top-level JSON array with `json` |
|
|
118
117
|
|
|
119
118
|
Examples:
|
|
120
119
|
|
|
@@ -215,7 +214,9 @@ signature, result models, `Decimal` key semantics, and error hierarchy.
|
|
|
215
214
|
elements are the records.
|
|
216
215
|
* Blank lines, malformed JSON, `NaN`, and infinities are rejected.
|
|
217
216
|
* Duplicate object property names within a record follow JSON's last-wins semantics: the last occurrence is kept.
|
|
218
|
-
* Identity fields must be top-level
|
|
217
|
+
* Identity fields must be top-level JSON values. Object member order is ignored
|
|
218
|
+
and array order is significant (`null` allowed only as one component of a
|
|
219
|
+
composite key).
|
|
219
220
|
* Identity types remain significant: `"1"` ≠ `1`, `true` ≠ `1`.
|
|
220
221
|
* Duplicate identities fail by default; `--duplicates first`/`last` select one
|
|
221
222
|
occurrence, report every discarded occurrence, and return exit code `1`.
|
|
@@ -235,9 +236,7 @@ order, and canonical number formatting.
|
|
|
235
236
|
## Sources & compression
|
|
236
237
|
|
|
237
238
|
Supported sources include local paths and HTTP/HTTPS URLs. The Python API
|
|
238
|
-
also accepts file-like objects.
|
|
239
|
-
the source and `ijson` for incremental parsing, so compression and remote
|
|
240
|
-
source handling are shared with JSONL input.
|
|
239
|
+
also accepts file-like objects.
|
|
241
240
|
|
|
242
241
|
Supported compression:
|
|
243
242
|
|
|
@@ -247,7 +246,7 @@ Supported compression:
|
|
|
247
246
|
* Zstandard on Python 3.14
|
|
248
247
|
|
|
249
248
|
See [architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) for the full source/compression
|
|
250
|
-
support matrix and how sources are
|
|
249
|
+
support matrix and how sources are managed.
|
|
251
250
|
|
|
252
251
|
## Limitations
|
|
253
252
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jsonl-diff
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
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
|
|
@@ -140,12 +140,11 @@ Record order does not matter.
|
|
|
140
140
|
* Exact **[RFC 6901](https://www.rfc-editor.org/info/rfc6901/)** JSON Pointer ignores.
|
|
141
141
|
* Optional disk-backed observed-schema diff for fields, types, nullability, and requiredness.
|
|
142
142
|
* Semantic number comparison using `Decimal`.
|
|
143
|
-
* Optional `msgspec` accelerator for ~2x faster large diffs (`pip install "jsonl-diff[speedups]"`).
|
|
144
143
|
* Deterministic summaries and change iteration.
|
|
145
144
|
* Original OLD/NEW physical line numbers.
|
|
146
145
|
* Machine-readable JSONL change log with `--details` ([format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md)).
|
|
147
146
|
* Local, HTTP/HTTPS, file-like, and supported compressed sources.
|
|
148
|
-
* Incremental top-level JSON
|
|
147
|
+
* Incremental parsing for JSONL/NDJSON by default, with support for top-level JSON arrays via `--format json`.
|
|
149
148
|
* CLI and Python API using the same comparison engine.
|
|
150
149
|
|
|
151
150
|
## CLI
|
|
@@ -165,14 +164,14 @@ jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
|
|
|
165
164
|
| `--key KEY` | Required top-level identity field; repeat or comma-separate for composite keys |
|
|
166
165
|
| `--ignore POINTER` | RFC 6901 pointer to exclude from content comparison |
|
|
167
166
|
| `--where EXPRESSION` | JMESPath filter applied to each record |
|
|
168
|
-
| `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last`
|
|
169
|
-
| `--missing-key POLICY`| `error` (default), or `null` to treat an absent identity field as `null`
|
|
167
|
+
| `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last` |
|
|
168
|
+
| `--missing-key POLICY`| `error` (default), or `null` to treat an absent identity field as `null` |
|
|
170
169
|
| `--details FILE` | Write deterministic machine-readable JSONL changes |
|
|
171
|
-
| `--schema-diff` | Compare observed fields, types, nullability, and requiredness
|
|
172
|
-
| `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling
|
|
170
|
+
| `--schema-diff` | Compare observed fields, types, nullability, and requiredness |
|
|
171
|
+
| `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling |
|
|
173
172
|
| `--quiet` | Suppress the normal summary |
|
|
174
173
|
| `--max-temp BYTES` | Best-effort budget for `jsonl-diff` workspace temporary storage |
|
|
175
|
-
| `--format FORMAT` | Input format: `jsonl` (default) or a top-level JSON array with `json`
|
|
174
|
+
| `--format FORMAT` | Input format: `jsonl` (default) or a top-level JSON array with `json` |
|
|
176
175
|
|
|
177
176
|
Examples:
|
|
178
177
|
|
|
@@ -273,7 +272,9 @@ signature, result models, `Decimal` key semantics, and error hierarchy.
|
|
|
273
272
|
elements are the records.
|
|
274
273
|
* Blank lines, malformed JSON, `NaN`, and infinities are rejected.
|
|
275
274
|
* Duplicate object property names within a record follow JSON's last-wins semantics: the last occurrence is kept.
|
|
276
|
-
* Identity fields must be top-level
|
|
275
|
+
* Identity fields must be top-level JSON values. Object member order is ignored
|
|
276
|
+
and array order is significant (`null` allowed only as one component of a
|
|
277
|
+
composite key).
|
|
277
278
|
* Identity types remain significant: `"1"` ≠ `1`, `true` ≠ `1`.
|
|
278
279
|
* Duplicate identities fail by default; `--duplicates first`/`last` select one
|
|
279
280
|
occurrence, report every discarded occurrence, and return exit code `1`.
|
|
@@ -293,9 +294,7 @@ order, and canonical number formatting.
|
|
|
293
294
|
## Sources & compression
|
|
294
295
|
|
|
295
296
|
Supported sources include local paths and HTTP/HTTPS URLs. The Python API
|
|
296
|
-
also accepts file-like objects.
|
|
297
|
-
the source and `ijson` for incremental parsing, so compression and remote
|
|
298
|
-
source handling are shared with JSONL input.
|
|
297
|
+
also accepts file-like objects.
|
|
299
298
|
|
|
300
299
|
Supported compression:
|
|
301
300
|
|
|
@@ -305,7 +304,7 @@ Supported compression:
|
|
|
305
304
|
* Zstandard on Python 3.14
|
|
306
305
|
|
|
307
306
|
See [architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) for the full source/compression
|
|
308
|
-
support matrix and how sources are
|
|
307
|
+
support matrix and how sources are managed.
|
|
309
308
|
|
|
310
309
|
## Limitations
|
|
311
310
|
|
|
@@ -26,9 +26,9 @@ try: # Optional C-accelerated content canonicalization (Python 3.10+).
|
|
|
26
26
|
except ImportError:
|
|
27
27
|
_msgspec = None
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
JsonIdentityValue = Union[str, Decimal, bool, int, None, list, dict]
|
|
30
30
|
Number = Union[Decimal, int, float]
|
|
31
|
-
IdentityKey = Tuple[
|
|
31
|
+
IdentityKey = Tuple[JsonIdentityValue, ...]
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class _Num(Decimal):
|
|
@@ -605,8 +605,8 @@ def _identity(
|
|
|
605
605
|
# record into one indistinguishable identity.
|
|
606
606
|
if not composite:
|
|
607
607
|
raise ValueError("identity field {!r} must be a non-null scalar".format(name))
|
|
608
|
-
elif not isinstance(value, (str, Decimal, bool, int)):
|
|
609
|
-
raise ValueError("identity field {!r} must be a
|
|
608
|
+
elif not isinstance(value, (str, Decimal, bool, int, list, dict)):
|
|
609
|
+
raise ValueError("identity field {!r} must be a JSON value".format(name))
|
|
610
610
|
values.append(value)
|
|
611
611
|
return tuple(values)
|
|
612
612
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "jsonl-diff"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.5"
|
|
8
8
|
description = "A lightweight, pure-Python tool for comparing large JSONL/NDJSON datasets without loading them entirely into memory."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -597,6 +597,26 @@ class TestDetailsOutput:
|
|
|
597
597
|
# Assert
|
|
598
598
|
assert records[1]["key"] == [12345678901234567890]
|
|
599
599
|
|
|
600
|
+
def test_structured_key_is_written_to_details_as_json(
|
|
601
|
+
self,
|
|
602
|
+
write_jsonl,
|
|
603
|
+
tmp_path,
|
|
604
|
+
):
|
|
605
|
+
old = write_jsonl(
|
|
606
|
+
"old.jsonl",
|
|
607
|
+
[{"id": {"region": "ES", "customer": 7}, "value": "before"}],
|
|
608
|
+
)
|
|
609
|
+
new = write_jsonl(
|
|
610
|
+
"new.jsonl",
|
|
611
|
+
[{"id": {"customer": 7, "region": "ES"}, "value": "after"}],
|
|
612
|
+
)
|
|
613
|
+
details = tmp_path / "changes.jsonl"
|
|
614
|
+
|
|
615
|
+
main([str(old), str(new), "--key", "id", "--details", str(details), "--quiet"])
|
|
616
|
+
records = [json.loads(line) for line in details.read_text(encoding="utf-8").splitlines()]
|
|
617
|
+
|
|
618
|
+
assert records[1]["key"] == [{"customer": 7, "region": "ES"}]
|
|
619
|
+
|
|
600
620
|
def test_duplicate_events_follow_meta_and_include_policy_outcome(
|
|
601
621
|
self,
|
|
602
622
|
write_jsonl,
|
|
@@ -131,6 +131,50 @@ class TestDiffSummary:
|
|
|
131
131
|
|
|
132
132
|
|
|
133
133
|
class TestIdentityKeys:
|
|
134
|
+
@pytest.mark.parametrize(
|
|
135
|
+
"identity",
|
|
136
|
+
[
|
|
137
|
+
{"region": "ES", "customer": 7},
|
|
138
|
+
["ES", 7, {"active": True}],
|
|
139
|
+
],
|
|
140
|
+
)
|
|
141
|
+
def test_structured_identity_values_are_supported(self, write_jsonl, identity):
|
|
142
|
+
old = write_jsonl("old.jsonl", [{"id": identity, "value": "before"}])
|
|
143
|
+
new = write_jsonl("new.jsonl", [{"id": identity, "value": "after"}])
|
|
144
|
+
|
|
145
|
+
with diff(old, new, key="id") as result:
|
|
146
|
+
change = next(result.changes())
|
|
147
|
+
|
|
148
|
+
assert change.key == (identity,)
|
|
149
|
+
assert change.operation == ChangeOperation.MODIFIED
|
|
150
|
+
|
|
151
|
+
def test_identity_object_member_order_is_ignored(self, write_jsonl):
|
|
152
|
+
old = write_jsonl("old.jsonl", ['{"id":{"a":1,"b":{"x":2,"y":3}}}'])
|
|
153
|
+
new = write_jsonl("new.jsonl", ['{"id":{"b":{"y":3,"x":2},"a":1}}'])
|
|
154
|
+
|
|
155
|
+
with diff(old, new, key="id") as result:
|
|
156
|
+
summary = result.summary
|
|
157
|
+
|
|
158
|
+
assert summary == Summary(equal=1, added=0, deleted=0, modified=0)
|
|
159
|
+
|
|
160
|
+
def test_identity_array_order_is_significant(self, write_jsonl):
|
|
161
|
+
old = write_jsonl("old.jsonl", ['{"id":[1,2]}'])
|
|
162
|
+
new = write_jsonl("new.jsonl", ['{"id":[2,1]}'])
|
|
163
|
+
|
|
164
|
+
with diff(old, new, key="id") as result:
|
|
165
|
+
summary = result.summary
|
|
166
|
+
|
|
167
|
+
assert summary == Summary(equal=0, added=1, deleted=1, modified=0)
|
|
168
|
+
|
|
169
|
+
def test_identity_nested_numbers_use_json_numeric_semantics(self, write_jsonl):
|
|
170
|
+
old = write_jsonl("old.jsonl", ['{"id":{"version":1,"values":[2.0]}}'])
|
|
171
|
+
new = write_jsonl("new.jsonl", ['{"id":{"version":1.0,"values":[2e0]}}'])
|
|
172
|
+
|
|
173
|
+
with diff(old, new, key="id") as result:
|
|
174
|
+
summary = result.summary
|
|
175
|
+
|
|
176
|
+
assert summary == Summary(equal=1, added=0, deleted=0, modified=0)
|
|
177
|
+
|
|
134
178
|
def test_composite_key_is_returned_as_typed_tuple(self, write_jsonl):
|
|
135
179
|
# Arrange
|
|
136
180
|
old = write_jsonl("old.jsonl", [{"country": "ES", "customer": 7, "value": "before"}])
|
|
@@ -581,8 +625,6 @@ class TestInputValidation:
|
|
|
581
625
|
[
|
|
582
626
|
({}, "missing identity field"),
|
|
583
627
|
({"id": None}, "must be a non-null scalar"),
|
|
584
|
-
({"id": []}, "must be a non-null scalar"),
|
|
585
|
-
({"id": {}}, "must be a non-null scalar"),
|
|
586
628
|
],
|
|
587
629
|
)
|
|
588
630
|
def test_invalid_identity_component_is_rejected(self, write_jsonl, record, message):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|