python-jsonpath 2.0.2__tar.gz → 2.1.0__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.
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/PKG-INFO +28 -2
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/README.md +27 -1
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/__about__.py +1 -1
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/env.py +4 -4
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/patch.py +70 -6
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/pyproject.toml +3 -3
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/.gitignore +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/LICENSE.txt +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/__init__.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/__main__.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/_data.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/_types.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/cli.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/exceptions.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/filter.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/fluent_api.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/__init__.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/_pattern.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/arguments.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/count.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/filter_function.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/is_instance.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/keys.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/length.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/match.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/search.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/starts_with.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/typeof.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/value.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/lex.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/lru_cache.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/match.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/parse.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/path.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/pointer.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/py.typed +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/segments.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/selectors.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/serialize.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/stream.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/token.py +0 -0
- {python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/unescape.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-jsonpath
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: JSONPath, JSON Pointer and JSON Patch for Python.
|
|
5
5
|
Project-URL: Documentation, https://jg-rp.github.io/python-jsonpath/
|
|
6
6
|
Project-URL: Issues, https://github.com/jg-rp/python-jsonpath/issues
|
|
@@ -149,7 +149,10 @@ print(jane_score) # 55
|
|
|
149
149
|
|
|
150
150
|
### JSON Patch
|
|
151
151
|
|
|
152
|
-
We also include an [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902) compliant implementation of JSON Patch. See JSON Patch [quick start](https://jg-rp.github.io/python-jsonpath/quickstart/#patchapplypatch-data) and [API reference](https://jg-rp.github.io/python-jsonpath/api/#jsonpath.JSONPatch)
|
|
152
|
+
We also include an [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902) compliant implementation of JSON Patch. See JSON Patch [quick start](https://jg-rp.github.io/python-jsonpath/quickstart/#patchapplypatch-data) and the [API reference](https://jg-rp.github.io/python-jsonpath/api/#jsonpath.JSONPatch).
|
|
153
|
+
|
|
154
|
+
> [!WARNING]
|
|
155
|
+
> Objects passed to `patch.apply()` and `JSONPatch.apply()` are modified in place, even if a patch operation fails. Use `patch.atomic()` or `JSONPatch.atomic()` if you need to preserve input data on patch failure.
|
|
153
156
|
|
|
154
157
|
```python
|
|
155
158
|
from jsonpath import patch
|
|
@@ -164,7 +167,30 @@ patch_operations = [
|
|
|
164
167
|
data = {"some": {"other": "thing"}}
|
|
165
168
|
patch.apply(patch_operations, data)
|
|
166
169
|
print(data) # {'some': {'other': 'thing', 'foo': {'bar': [1], 'else': 'thing'}}}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Use `patch.atomic()` or `JSONPatch.atomic()` if you need to preserve input data on patch failure.
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
import contextlib
|
|
176
|
+
|
|
177
|
+
from jsonpath import JSONPatchError
|
|
178
|
+
from jsonpath import patch
|
|
179
|
+
|
|
180
|
+
patch_operations = [
|
|
181
|
+
{"op": "add", "path": "/some/foo", "value": {"foo": {}}},
|
|
182
|
+
{"op": "add", "path": "/some/foo", "value": {"bar": []}},
|
|
183
|
+
{"op": "copy", "from": "/some/other", "path": "/some/foo/else"},
|
|
184
|
+
{"op": "add", "path": "/some/foo/bar/-", "value": 1},
|
|
185
|
+
{"op": "test", "path": "/some/thing", "value": "baz"}, # Always fails
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
data = {"some": {"other": "thing"}}
|
|
189
|
+
|
|
190
|
+
with contextlib.suppress(JSONPatchError):
|
|
191
|
+
patch.atomic(patch_operations, data)
|
|
167
192
|
|
|
193
|
+
assert data == {"some": {"other": "thing"}}
|
|
168
194
|
```
|
|
169
195
|
|
|
170
196
|
## License
|
|
@@ -119,7 +119,10 @@ print(jane_score) # 55
|
|
|
119
119
|
|
|
120
120
|
### JSON Patch
|
|
121
121
|
|
|
122
|
-
We also include an [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902) compliant implementation of JSON Patch. See JSON Patch [quick start](https://jg-rp.github.io/python-jsonpath/quickstart/#patchapplypatch-data) and [API reference](https://jg-rp.github.io/python-jsonpath/api/#jsonpath.JSONPatch)
|
|
122
|
+
We also include an [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902) compliant implementation of JSON Patch. See JSON Patch [quick start](https://jg-rp.github.io/python-jsonpath/quickstart/#patchapplypatch-data) and the [API reference](https://jg-rp.github.io/python-jsonpath/api/#jsonpath.JSONPatch).
|
|
123
|
+
|
|
124
|
+
> [!WARNING]
|
|
125
|
+
> Objects passed to `patch.apply()` and `JSONPatch.apply()` are modified in place, even if a patch operation fails. Use `patch.atomic()` or `JSONPatch.atomic()` if you need to preserve input data on patch failure.
|
|
123
126
|
|
|
124
127
|
```python
|
|
125
128
|
from jsonpath import patch
|
|
@@ -134,7 +137,30 @@ patch_operations = [
|
|
|
134
137
|
data = {"some": {"other": "thing"}}
|
|
135
138
|
patch.apply(patch_operations, data)
|
|
136
139
|
print(data) # {'some': {'other': 'thing', 'foo': {'bar': [1], 'else': 'thing'}}}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Use `patch.atomic()` or `JSONPatch.atomic()` if you need to preserve input data on patch failure.
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
import contextlib
|
|
146
|
+
|
|
147
|
+
from jsonpath import JSONPatchError
|
|
148
|
+
from jsonpath import patch
|
|
149
|
+
|
|
150
|
+
patch_operations = [
|
|
151
|
+
{"op": "add", "path": "/some/foo", "value": {"foo": {}}},
|
|
152
|
+
{"op": "add", "path": "/some/foo", "value": {"bar": []}},
|
|
153
|
+
{"op": "copy", "from": "/some/other", "path": "/some/foo/else"},
|
|
154
|
+
{"op": "add", "path": "/some/foo/bar/-", "value": 1},
|
|
155
|
+
{"op": "test", "path": "/some/thing", "value": "baz"}, # Always fails
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
data = {"some": {"other": "thing"}}
|
|
159
|
+
|
|
160
|
+
with contextlib.suppress(JSONPatchError):
|
|
161
|
+
patch.atomic(patch_operations, data)
|
|
137
162
|
|
|
163
|
+
assert data == {"some": {"other": "thing"}}
|
|
138
164
|
```
|
|
139
165
|
|
|
140
166
|
## License
|
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
try:
|
|
6
|
-
import regex # noqa: F401
|
|
6
|
+
import regex # type: ignore # noqa: F401
|
|
7
7
|
|
|
8
8
|
REGEX_AVAILABLE = True
|
|
9
9
|
except ImportError:
|
|
10
|
-
REGEX_AVAILABLE = False
|
|
10
|
+
REGEX_AVAILABLE = False # type: ignore
|
|
11
11
|
|
|
12
12
|
try:
|
|
13
|
-
import iregexp_check # noqa: F401
|
|
13
|
+
import iregexp_check # type: ignore # noqa: F401
|
|
14
14
|
|
|
15
15
|
IREGEXP_AVAILABLE = True
|
|
16
16
|
except ImportError:
|
|
17
|
-
IREGEXP_AVAILABLE = False
|
|
17
|
+
IREGEXP_AVAILABLE = False # type: ignore
|
|
18
18
|
|
|
19
19
|
from decimal import Decimal
|
|
20
20
|
from operator import getitem
|
|
@@ -71,7 +71,7 @@ class OpAdd(Op):
|
|
|
71
71
|
if target == "-":
|
|
72
72
|
parent.append(self.value)
|
|
73
73
|
else:
|
|
74
|
-
index = self.path._index(target) # noqa: SLF001
|
|
74
|
+
index = self.path._index(target) # type: ignore # noqa: SLF001
|
|
75
75
|
if index == len(parent):
|
|
76
76
|
parent.append(self.value)
|
|
77
77
|
else:
|
|
@@ -303,12 +303,12 @@ class OpCopy(Op):
|
|
|
303
303
|
self, data: Union[MutableSequence[object], MutableMapping[str, object]]
|
|
304
304
|
) -> Union[MutableSequence[object], MutableMapping[str, object]]:
|
|
305
305
|
"""Apply this patch operation to _data_."""
|
|
306
|
-
|
|
306
|
+
_, source_obj = self.source.resolve_parent(data)
|
|
307
307
|
|
|
308
308
|
if source_obj is UNDEFINED:
|
|
309
309
|
raise JSONPatchError("source object does not exist")
|
|
310
310
|
|
|
311
|
-
dest_parent,
|
|
311
|
+
dest_parent, _ = self.dest.resolve_parent(data)
|
|
312
312
|
|
|
313
313
|
if dest_parent is None:
|
|
314
314
|
# Copy source to root
|
|
@@ -639,7 +639,7 @@ class JSONPatch:
|
|
|
639
639
|
|
|
640
640
|
If _data_ is a string or file-like object, it will be loaded with
|
|
641
641
|
_json.loads_. Otherwise _data_ should be a JSON-like data structure and
|
|
642
|
-
will be modified in place.
|
|
642
|
+
will be modified in place, even if a patch operation fails.
|
|
643
643
|
|
|
644
644
|
When modifying _data_ in place, we return modified data too. This is
|
|
645
645
|
to allow for replacing _data's_ root element, which is allowed by some
|
|
@@ -674,6 +674,37 @@ class JSONPatch:
|
|
|
674
674
|
|
|
675
675
|
return _data
|
|
676
676
|
|
|
677
|
+
def atomic(
|
|
678
|
+
self,
|
|
679
|
+
data: Union[List[Any], Dict[str, Any]],
|
|
680
|
+
) -> object:
|
|
681
|
+
"""Apply this patch to _data_ atomically.
|
|
682
|
+
|
|
683
|
+
Unlike `apply()`, if any patch operation fails, _data_ remains
|
|
684
|
+
unchanged.
|
|
685
|
+
|
|
686
|
+
Arguments:
|
|
687
|
+
data: A Python object representing JSON-like data.
|
|
688
|
+
|
|
689
|
+
Returns:
|
|
690
|
+
Patched _data_.
|
|
691
|
+
|
|
692
|
+
Raises:
|
|
693
|
+
JSONPatchError: When a patch operation fails.
|
|
694
|
+
JSONPatchTestFailure: When a _test_ operation does not pass.
|
|
695
|
+
`JSONPatchTestFailure` is a subclass of `JSONPatchError`.
|
|
696
|
+
"""
|
|
697
|
+
data_ = copy.deepcopy(data)
|
|
698
|
+
self.apply(data_) # This could raise a JSONPatchError.
|
|
699
|
+
data.clear()
|
|
700
|
+
|
|
701
|
+
if isinstance(data, dict):
|
|
702
|
+
data.update(data_)
|
|
703
|
+
else:
|
|
704
|
+
data.extend(data_)
|
|
705
|
+
|
|
706
|
+
return data
|
|
707
|
+
|
|
677
708
|
def asdicts(self) -> List[Dict[str, object]]:
|
|
678
709
|
"""Return a list of this patch's operations as dictionaries."""
|
|
679
710
|
return [op.asdict() for op in self.ops]
|
|
@@ -690,7 +721,7 @@ def apply(
|
|
|
690
721
|
|
|
691
722
|
If _data_ is a string or file-like object, it will be loaded with
|
|
692
723
|
_json.loads_. Otherwise _data_ should be a JSON-like data structure and
|
|
693
|
-
will be **modified in-place
|
|
724
|
+
will be **modified in-place**, even if a patch operation fails.
|
|
694
725
|
|
|
695
726
|
When modifying _data_ in-place, we return modified data too. This is
|
|
696
727
|
to allow for replacing _data's_ root element, which is allowed by some
|
|
@@ -711,10 +742,43 @@ def apply(
|
|
|
711
742
|
JSONPatchError: When a patch operation fails.
|
|
712
743
|
JSONPatchTestFailure: When a _test_ operation does not pass.
|
|
713
744
|
`JSONPatchTestFailure` is a subclass of `JSONPatchError`.
|
|
714
|
-
|
|
715
745
|
"""
|
|
716
746
|
return JSONPatch(
|
|
717
747
|
patch,
|
|
718
748
|
unicode_escape=unicode_escape,
|
|
719
749
|
uri_decode=uri_decode,
|
|
720
750
|
).apply(data)
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
def atomic(
|
|
754
|
+
patch: Union[str, IOBase, Iterable[Mapping[str, object]], None],
|
|
755
|
+
data: Union[List[Any], Dict[str, Any]],
|
|
756
|
+
*,
|
|
757
|
+
unicode_escape: bool = True,
|
|
758
|
+
uri_decode: bool = False,
|
|
759
|
+
) -> object:
|
|
760
|
+
"""Apply patch operations from _patch_ to _data_ atomically.
|
|
761
|
+
|
|
762
|
+
Unlike `apply()`, if any patch operation fails, _data_ remains unchanged.
|
|
763
|
+
|
|
764
|
+
Arguments:
|
|
765
|
+
patch: A JSON Patch formatted document or equivalent Python objects.
|
|
766
|
+
data: A Python object representing JSON-like data.
|
|
767
|
+
unicode_escape: If `True`, UTF-16 escape sequences will be decoded
|
|
768
|
+
before parsing JSON pointers.
|
|
769
|
+
uri_decode: If `True`, JSON pointers will be unescaped using _urllib_
|
|
770
|
+
before being parsed.
|
|
771
|
+
|
|
772
|
+
Returns:
|
|
773
|
+
Patched _data_.
|
|
774
|
+
|
|
775
|
+
Raises:
|
|
776
|
+
JSONPatchError: When a patch operation fails.
|
|
777
|
+
JSONPatchTestFailure: When a _test_ operation does not pass.
|
|
778
|
+
`JSONPatchTestFailure` is a subclass of `JSONPatchError`.
|
|
779
|
+
"""
|
|
780
|
+
return JSONPatch(
|
|
781
|
+
patch,
|
|
782
|
+
unicode_escape=unicode_escape,
|
|
783
|
+
uri_decode=uri_decode,
|
|
784
|
+
).atomic(data)
|
|
@@ -107,7 +107,7 @@ exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"]
|
|
|
107
107
|
[tool.mypy]
|
|
108
108
|
files = ["jsonpath", "tests"]
|
|
109
109
|
exclude = ["tests/nts", "tests/cts"]
|
|
110
|
-
python_version = "3.
|
|
110
|
+
python_version = "3.10"
|
|
111
111
|
disallow_subclassing_any = true
|
|
112
112
|
disallow_untyped_calls = true
|
|
113
113
|
disallow_untyped_defs = true
|
|
@@ -152,8 +152,8 @@ exclude = [
|
|
|
152
152
|
line-length = 88
|
|
153
153
|
|
|
154
154
|
|
|
155
|
-
# Assume Python 3.
|
|
156
|
-
target-version = "
|
|
155
|
+
# Assume Python 3.8.
|
|
156
|
+
target-version = "py38"
|
|
157
157
|
|
|
158
158
|
[tool.ruff.lint]
|
|
159
159
|
select = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_jsonpath-2.0.2 → python_jsonpath-2.1.0}/jsonpath/function_extensions/filter_function.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|