j-perm 0.1.3__py3-none-any.whl → 0.2.0__py3-none-any.whl
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.
- j_perm/__init__.py +15 -7
- j_perm/casters/__init__.py +4 -0
- j_perm/casters/_bool.py +9 -0
- j_perm/casters/_float.py +8 -0
- j_perm/casters/_int.py +8 -0
- j_perm/casters/_str.py +8 -0
- j_perm/constructs/__init__.py +2 -0
- j_perm/constructs/eval.py +16 -0
- j_perm/constructs/ref.py +21 -0
- j_perm/engine.py +139 -63
- j_perm/funcs/__init__.py +1 -0
- j_perm/funcs/subtract.py +11 -0
- j_perm/op_handler.py +57 -0
- j_perm/ops/__init__.py +1 -0
- j_perm/ops/{assert.py → _assert.py} +4 -4
- j_perm/ops/_exec.py +8 -9
- j_perm/ops/_if.py +8 -9
- j_perm/ops/copy.py +5 -5
- j_perm/ops/copy_d.py +5 -5
- j_perm/ops/delete.py +4 -4
- j_perm/ops/distinct.py +5 -5
- j_perm/ops/foreach.py +6 -7
- j_perm/ops/replace_root.py +5 -7
- j_perm/ops/set.py +6 -7
- j_perm/ops/update.py +7 -8
- j_perm/schema/__init__.py +109 -109
- j_perm/special_resolver.py +115 -0
- j_perm/subst.py +300 -0
- j_perm-0.2.0.dist-info/METADATA +818 -0
- j_perm-0.2.0.dist-info/RECORD +34 -0
- {j_perm-0.1.3.dist-info → j_perm-0.2.0.dist-info}/WHEEL +1 -1
- j_perm/jmes_ext.py +0 -17
- j_perm/registry.py +0 -30
- j_perm/utils/special.py +0 -41
- j_perm/utils/subst.py +0 -133
- j_perm/utils/tuples.py +0 -17
- j_perm-0.1.3.dist-info/METADATA +0 -116
- j_perm-0.1.3.dist-info/RECORD +0 -26
- {j_perm-0.1.3.dist-info → j_perm-0.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
j_perm/__init__.py,sha256=RUpTLecqmkXgyy91s8DHNMEStW4almMYGHTJMmLR5NY,714
|
|
2
|
+
j_perm/engine.py,sha256=xKSokxnkuVUyGZcsC1F88xzBw3vLpPPPUD1iHYKuKsI,5562
|
|
3
|
+
j_perm/op_handler.py,sha256=h28thz_18DwZTb9IZtTd6kfsZj7hN4UsmU4uf3aMYpo,1649
|
|
4
|
+
j_perm/special_resolver.py,sha256=khRVWXrE3Vch1gbxsfFwj9JQ37pZ-_ojMeh-G2Vv7bs,4032
|
|
5
|
+
j_perm/subst.py,sha256=oW21Gs2nTEQLcOC_xMKzeuZFtfNvnB2QZAIWl7U4TSg,9802
|
|
6
|
+
j_perm/casters/__init__.py,sha256=mD49oMEyj6oDfSKXEJ8DbnmqkSypfEEg3VMI_rfaK-4,114
|
|
7
|
+
j_perm/casters/_bool.py,sha256=qRsT7IcFBApD09elKUyUUaZmfePSIsOsKQHQHsgnHsw,230
|
|
8
|
+
j_perm/casters/_float.py,sha256=C4r-h6zbkjmQnoEdE2RDMhSkW9oGrvxbQngJZ2T7_tU,153
|
|
9
|
+
j_perm/casters/_int.py,sha256=f1BKqsULiG6Puov1qcGS_inSnv0hZtQ0deQEMP0v0i4,145
|
|
10
|
+
j_perm/casters/_str.py,sha256=v1_BD1_hPbOtvO5CKYAlNEGbMhpR56eKCnV2a2Q4kGU,145
|
|
11
|
+
j_perm/constructs/__init__.py,sha256=TTUPSMyvj8HSfPikrFqXaFsechc9aOIbjtVjy4TOolE,50
|
|
12
|
+
j_perm/constructs/eval.py,sha256=ZckFMcerRWnu-51WAEdm35kuO7t_EzqvtiCAgVWDsjQ,457
|
|
13
|
+
j_perm/constructs/ref.py,sha256=eUrRCanKAEWZ98jOAHNhjs5UhXNAm17NWd4Cbus_cyY,654
|
|
14
|
+
j_perm/funcs/__init__.py,sha256=8yIafxhCH5B7jXrsautQEtl4Qt8RcUK7IWNniORj9ow,31
|
|
15
|
+
j_perm/funcs/subtract.py,sha256=0UW3McKL7VDPVj0UwfvZlrSXGs1uQ6yIdLz5rPqa7bY,293
|
|
16
|
+
j_perm/ops/__init__.py,sha256=G4j6MGnEVnHSeJIBwrpV9oMk7s_djlEaOmLRW_4IEEo,329
|
|
17
|
+
j_perm/ops/_assert.py,sha256=l07DjqsMbvoTDzLbVVcMciblYw8O4D6gBwPt3yFKPhs,758
|
|
18
|
+
j_perm/ops/_exec.py,sha256=-esjfF2te1NvkclrJJ9lGU7YdwY_15vuxMihG08HhQM,1934
|
|
19
|
+
j_perm/ops/_if.py,sha256=DNYp0j3-3YYMIR_CcDM3Ai0CpW2Qt4SYtKxk-9onu8c,1590
|
|
20
|
+
j_perm/ops/copy.py,sha256=fV2rE92JyTRqo91GjXwWucklDR1T1ZcFHHbxG1F8S9g,1110
|
|
21
|
+
j_perm/ops/copy_d.py,sha256=2SGHoq4vaD79diJos_oO3pvZvC_XrQorxhXAgZ5l09E,1017
|
|
22
|
+
j_perm/ops/delete.py,sha256=7SzLE9W_dlmcLOVzKjOzIFLSAHf9nGlagbhbwIH_PmI,916
|
|
23
|
+
j_perm/ops/distinct.py,sha256=RoVIIRNm7C9iAjcPZHpoMfgKw6pGx7nuLkYwruhHeYY,1036
|
|
24
|
+
j_perm/ops/foreach.py,sha256=6tEQ9PyiWBvrm0eANg18p5hV-OvIiL2O1rdqWOC18tQ,1425
|
|
25
|
+
j_perm/ops/replace_root.py,sha256=FFyc-95n3kTzcOXrnjwDdvwOnKNitXKb_1F25MMnXd8,445
|
|
26
|
+
j_perm/ops/set.py,sha256=-kFFgHxeq65K5vLzDe6PhUoLT-ksoZYUVL1Jxf8bRA0,1882
|
|
27
|
+
j_perm/ops/update.py,sha256=gvJTh3vS4zD-lpaqN23w5OO3hTtkSdu8RPy0V8r8Rwg,2471
|
|
28
|
+
j_perm/schema/__init__.py,sha256=mhEbGdi1MgLeEm1IL8-tkTtbIdrdlvQi22sBr7vCUqg,3392
|
|
29
|
+
j_perm/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
|
+
j_perm/utils/pointers.py,sha256=X1HSCag4t-qq5zTvBMRAlBKXwpHVNNZYJrdJRtyEr4g,2788
|
|
31
|
+
j_perm-0.2.0.dist-info/METADATA,sha256=DuPKOquojX3jKmrER86guVZXtha52te5M2xo3oN3Azc,16228
|
|
32
|
+
j_perm-0.2.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
33
|
+
j_perm-0.2.0.dist-info/top_level.txt,sha256=yveBxREqVn9DliNwmen1QWoxR0uta7bU5giS1CCffRI,7
|
|
34
|
+
j_perm-0.2.0.dist-info/RECORD,,
|
j_perm/jmes_ext.py
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import jmespath
|
|
4
|
-
from jmespath import functions as _jp_funcs
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class _UserFunctions(_jp_funcs.Functions):
|
|
8
|
-
"""Container for custom JMESPath functions used by the DSL."""
|
|
9
|
-
|
|
10
|
-
@_jp_funcs.signature({'types': ['number']}, {'types': ['number']})
|
|
11
|
-
def _func_subtract(self, a: float, b: float) -> float:
|
|
12
|
-
"""JMESPath function that subtracts two numbers (a - b)."""
|
|
13
|
-
return a - b
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
USER_FUNCTIONS = _UserFunctions()
|
|
17
|
-
JP_OPTIONS = jmespath.Options(custom_functions=USER_FUNCTIONS)
|
j_perm/registry.py
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Any, Callable, Dict, MutableMapping, Mapping, TypeAlias
|
|
4
|
-
|
|
5
|
-
Handler: TypeAlias = Callable[
|
|
6
|
-
[dict, MutableMapping[str, Any], Mapping[str, Any]],
|
|
7
|
-
MutableMapping[str, Any],
|
|
8
|
-
]
|
|
9
|
-
|
|
10
|
-
_OP_HANDLERS: Dict[str, Handler] = {}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def register_op(name: str) -> Callable[[Handler], Handler]:
|
|
14
|
-
"""Decorator that registers a DSL operation handler under a given name."""
|
|
15
|
-
|
|
16
|
-
def decorator(func: Handler) -> Handler:
|
|
17
|
-
if name in _OP_HANDLERS:
|
|
18
|
-
raise ValueError(f"Handler for op '{name}' is already registered")
|
|
19
|
-
_OP_HANDLERS[name] = func
|
|
20
|
-
return func
|
|
21
|
-
|
|
22
|
-
return decorator
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def get_handler(name: str) -> Handler:
|
|
26
|
-
"""Return a registered handler or raise ValueError if it does not exist."""
|
|
27
|
-
try:
|
|
28
|
-
return _OP_HANDLERS[name]
|
|
29
|
-
except KeyError:
|
|
30
|
-
raise ValueError(f"Unknown op '{name}'") from None
|
j_perm/utils/special.py
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import copy
|
|
4
|
-
from typing import Any, Mapping
|
|
5
|
-
|
|
6
|
-
from .pointers import maybe_slice
|
|
7
|
-
from .subst import substitute
|
|
8
|
-
from ..engine import apply_actions
|
|
9
|
-
|
|
10
|
-
_MISSING = object()
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def resolve_special(val: Any, src: Mapping[str, Any]):
|
|
14
|
-
"""Resolve $ref / $eval constructs inside an arbitrary value tree."""
|
|
15
|
-
if isinstance(val, dict):
|
|
16
|
-
if "$ref" in val:
|
|
17
|
-
ptr = substitute(val["$ref"], src)
|
|
18
|
-
dflt = val.get("$default", _MISSING)
|
|
19
|
-
try:
|
|
20
|
-
return copy.deepcopy(maybe_slice(ptr, src))
|
|
21
|
-
except Exception:
|
|
22
|
-
if dflt is not _MISSING:
|
|
23
|
-
return copy.deepcopy(dflt)
|
|
24
|
-
raise
|
|
25
|
-
|
|
26
|
-
if "$eval" in val:
|
|
27
|
-
out = apply_actions(val["$eval"], dest={}, source=src)
|
|
28
|
-
if "$select" in val:
|
|
29
|
-
sel = maybe_slice(val["$select"], out) # type: ignore[arg-type]
|
|
30
|
-
return sel
|
|
31
|
-
return out
|
|
32
|
-
|
|
33
|
-
return {k: resolve_special(v, src) for k, v in val.items()}
|
|
34
|
-
|
|
35
|
-
if isinstance(val, list):
|
|
36
|
-
return [resolve_special(x, src) for x in val]
|
|
37
|
-
|
|
38
|
-
if isinstance(val, tuple):
|
|
39
|
-
return tuple(resolve_special(x, src) for x in val)
|
|
40
|
-
|
|
41
|
-
return val
|
j_perm/utils/subst.py
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import copy
|
|
4
|
-
import json
|
|
5
|
-
from typing import Any, Mapping, List
|
|
6
|
-
|
|
7
|
-
import jmespath
|
|
8
|
-
|
|
9
|
-
from ..jmes_ext import JP_OPTIONS
|
|
10
|
-
|
|
11
|
-
_CASTERS = {
|
|
12
|
-
"int": int,
|
|
13
|
-
"float": float,
|
|
14
|
-
"str": str,
|
|
15
|
-
"bool": lambda x: bool(int(x)) if isinstance(x, (int, str)) else bool(x),
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def _resolve_expr(expr: str, data: Mapping[str, Any]) -> Any:
|
|
20
|
-
"""Resolve a single ${...} expression body."""
|
|
21
|
-
from .pointers import maybe_slice # local import to avoid cycles
|
|
22
|
-
|
|
23
|
-
expr = expr.strip()
|
|
24
|
-
|
|
25
|
-
# 1) simple casters like int:/path
|
|
26
|
-
for prefix, fn in _CASTERS.items():
|
|
27
|
-
tag = f"{prefix}:"
|
|
28
|
-
if expr.startswith(tag):
|
|
29
|
-
inner = expr[len(tag):]
|
|
30
|
-
value = flat_substitute(inner, data)
|
|
31
|
-
if isinstance(value, str) and value.startswith("${") and value.endswith("}"):
|
|
32
|
-
value = flat_substitute(value, data)
|
|
33
|
-
return fn(value)
|
|
34
|
-
|
|
35
|
-
# 2) JMESPath expression ? <expr>
|
|
36
|
-
if expr.startswith("?"):
|
|
37
|
-
query_raw = expr[1:].lstrip()
|
|
38
|
-
query_expanded = flat_substitute(query_raw, data)
|
|
39
|
-
return jmespath.search(query_expanded, data, options=JP_OPTIONS)
|
|
40
|
-
|
|
41
|
-
# 3) nested template ${...}
|
|
42
|
-
if expr.startswith("${") and expr.endswith("}"):
|
|
43
|
-
return flat_substitute(expr, data)
|
|
44
|
-
|
|
45
|
-
# 4) default: treat as JSON Pointer (relative to root)
|
|
46
|
-
pointer = "/" + expr.lstrip("/")
|
|
47
|
-
try:
|
|
48
|
-
return maybe_slice(pointer, data) # type: ignore[arg-type]
|
|
49
|
-
except Exception:
|
|
50
|
-
return None
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def flat_substitute(tmpl: str, data: Mapping[str, Any]) -> Any:
|
|
54
|
-
"""One-pass interpolation that replaces all ${...} occurrences in a string."""
|
|
55
|
-
if "${" not in tmpl:
|
|
56
|
-
return tmpl
|
|
57
|
-
|
|
58
|
-
# Entire string is a single ${...}
|
|
59
|
-
if tmpl.startswith("${") and tmpl.endswith("}"):
|
|
60
|
-
body = tmpl[2:-1]
|
|
61
|
-
return copy.deepcopy(_resolve_expr(body, data))
|
|
62
|
-
|
|
63
|
-
out: List[str] = []
|
|
64
|
-
i = 0
|
|
65
|
-
while i < len(tmpl):
|
|
66
|
-
if tmpl[i:i + 2] == "${":
|
|
67
|
-
depth = 0
|
|
68
|
-
j = i + 2
|
|
69
|
-
|
|
70
|
-
while j < len(tmpl):
|
|
71
|
-
ch = tmpl[j]
|
|
72
|
-
|
|
73
|
-
if ch == "{" and tmpl[j - 1] == "$":
|
|
74
|
-
depth += 1
|
|
75
|
-
elif ch == "}":
|
|
76
|
-
if depth == 0:
|
|
77
|
-
expr = tmpl[i + 2:j]
|
|
78
|
-
val = _resolve_expr(expr, data)
|
|
79
|
-
|
|
80
|
-
if isinstance(val, (Mapping, list)):
|
|
81
|
-
rendered = json.dumps(val, ensure_ascii=False)
|
|
82
|
-
else:
|
|
83
|
-
rendered = str(val)
|
|
84
|
-
|
|
85
|
-
out.append(rendered)
|
|
86
|
-
i = j + 1
|
|
87
|
-
break
|
|
88
|
-
depth -= 1
|
|
89
|
-
|
|
90
|
-
j += 1
|
|
91
|
-
else:
|
|
92
|
-
# no closing brace found, treat '${' as a literal
|
|
93
|
-
out.append(tmpl[i])
|
|
94
|
-
i += 1
|
|
95
|
-
else:
|
|
96
|
-
out.append(tmpl[i])
|
|
97
|
-
i += 1
|
|
98
|
-
|
|
99
|
-
return "".join(out)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def deep_substitute(obj: Any, data: Mapping[str, Any], _depth: int = 0) -> Any:
|
|
103
|
-
"""Recursively apply interpolation to strings, mapping keys/values and sequences."""
|
|
104
|
-
if _depth > 50:
|
|
105
|
-
raise RecursionError("too deep interpolation")
|
|
106
|
-
|
|
107
|
-
if isinstance(obj, str):
|
|
108
|
-
out = flat_substitute(obj, data)
|
|
109
|
-
if isinstance(out, str) and "${" in out:
|
|
110
|
-
return deep_substitute(out, data, _depth + 1)
|
|
111
|
-
return out
|
|
112
|
-
|
|
113
|
-
if isinstance(obj, list):
|
|
114
|
-
return [deep_substitute(item, data, _depth) for item in obj]
|
|
115
|
-
|
|
116
|
-
if isinstance(obj, tuple):
|
|
117
|
-
return [deep_substitute(item, data, _depth) for item in obj]
|
|
118
|
-
|
|
119
|
-
if isinstance(obj, Mapping):
|
|
120
|
-
out: dict[Any, Any] = {}
|
|
121
|
-
for k, v in obj.items():
|
|
122
|
-
new_key = deep_substitute(k, data, _depth) if isinstance(k, str) else k
|
|
123
|
-
if new_key in out:
|
|
124
|
-
raise KeyError(f"duplicate key after substitution: {new_key!r}")
|
|
125
|
-
out[new_key] = deep_substitute(v, data, _depth)
|
|
126
|
-
return out
|
|
127
|
-
|
|
128
|
-
return obj
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
# Public alias mirroring the original _substitute name
|
|
132
|
-
substitute = deep_substitute
|
|
133
|
-
substitute.__name__ = "substitute"
|
j_perm/utils/tuples.py
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Any, Mapping
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def tuples_to_lists(obj: Any) -> Any:
|
|
7
|
-
"""Recursively convert all tuples into lists so JMESPath indexers work reliably."""
|
|
8
|
-
if isinstance(obj, tuple):
|
|
9
|
-
return [tuples_to_lists(x) for x in obj]
|
|
10
|
-
|
|
11
|
-
if isinstance(obj, list):
|
|
12
|
-
return [tuples_to_lists(x) for x in obj]
|
|
13
|
-
|
|
14
|
-
if isinstance(obj, Mapping):
|
|
15
|
-
return {k: tuples_to_lists(v) for k, v in obj.items()}
|
|
16
|
-
|
|
17
|
-
return obj
|
j_perm-0.1.3.dist-info/METADATA
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: j-perm
|
|
3
|
-
Version: 0.1.3
|
|
4
|
-
Summary: jsom permutation library
|
|
5
|
-
Author-email: Roman <kuschanow@gmail.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/kuschanow/j-perm
|
|
8
|
-
Project-URL: Source, https://github.com/kuschanow/j-perm
|
|
9
|
-
Project-URL: Tracker, https://github.com/kuschanow/j-perm/issues
|
|
10
|
-
Requires-Python: >=3.10
|
|
11
|
-
Description-Content-Type: text/markdown
|
|
12
|
-
Requires-Dist: jmespath
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# JSON patch applier
|
|
16
|
-
|
|
17
|
-
A small, composable JSON transformation DSL implemented in Python.
|
|
18
|
-
|
|
19
|
-
The library lets you describe transformations as data (a list of steps) and then
|
|
20
|
-
apply them to an input document. It supports JSON Pointer paths, custom
|
|
21
|
-
JMESPath expressions, interpolation with `${...}` syntax, and a set of
|
|
22
|
-
built-in operations.
|
|
23
|
-
|
|
24
|
-
## Features
|
|
25
|
-
|
|
26
|
-
- JSON Pointer read/write with support for:
|
|
27
|
-
- root pointers (`''`, `'/'`, `'.'`)
|
|
28
|
-
- relative `..` segments
|
|
29
|
-
- list slices like `/items[1:3]`
|
|
30
|
-
- String interpolation:
|
|
31
|
-
- `${/path/to/node}` — JSON Pointer lookup
|
|
32
|
-
- `${int:/path}` / `${float:/path}` / `${bool:/path}` — simple casters
|
|
33
|
-
- `${? some.jmespath(expression) }` — JMESPath with custom functions
|
|
34
|
-
- Special values:
|
|
35
|
-
- `$ref` — reference into the source document
|
|
36
|
-
- `$eval` — nested DSL evaluation with optional `$select`
|
|
37
|
-
- Rich set of operations:
|
|
38
|
-
- `set`, `copy`, `copyD`, `delete`, `assert`
|
|
39
|
-
- `foreach`, `if`, `distinct`
|
|
40
|
-
- `replace_root`, `exec`, `update`
|
|
41
|
-
- Schema helper: approximate JSON Schema generation for a given DSL script.
|
|
42
|
-
|
|
43
|
-
## Basic usage
|
|
44
|
-
|
|
45
|
-
```python
|
|
46
|
-
from j_perm import apply_actions
|
|
47
|
-
|
|
48
|
-
source = {
|
|
49
|
-
"users": [
|
|
50
|
-
{"name": "Alice", "age": 17},
|
|
51
|
-
{"name": "Bob", "age": 22}
|
|
52
|
-
]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
actions = [
|
|
56
|
-
# Start with empty list
|
|
57
|
-
{"op": "replace_root", "value": []},
|
|
58
|
-
|
|
59
|
-
# For each user - build a simplified object
|
|
60
|
-
{
|
|
61
|
-
"op": "foreach",
|
|
62
|
-
"in": "/users",
|
|
63
|
-
"as": "u",
|
|
64
|
-
"do": [
|
|
65
|
-
{
|
|
66
|
-
"op": "set",
|
|
67
|
-
"path": "/-",
|
|
68
|
-
"value": {
|
|
69
|
-
"name": "${/u/name}",
|
|
70
|
-
"is_adult": {
|
|
71
|
-
"$eval": [
|
|
72
|
-
{"op": "replace_root", "value": False},
|
|
73
|
-
{
|
|
74
|
-
"op": "if",
|
|
75
|
-
"cond": "${?`${/u/age}` >= `18`}",
|
|
76
|
-
"then": [{"op": "replace_root", "value": True}]
|
|
77
|
-
}
|
|
78
|
-
]
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
]
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
|
|
86
|
-
result = apply_actions(actions, dest={}, source=source)
|
|
87
|
-
# result -> {"fullName": "Alice", "isAdult": True}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Schema generation
|
|
91
|
-
|
|
92
|
-
```python
|
|
93
|
-
from j_perm import build_schema
|
|
94
|
-
|
|
95
|
-
schema = build_schema(script)
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
`schema` is a JSON-Schema-like structure that you can use for documentation,
|
|
99
|
-
validation or introspection.
|
|
100
|
-
|
|
101
|
-
## Extending with custom operations
|
|
102
|
-
|
|
103
|
-
```python
|
|
104
|
-
from j_perm import register_op
|
|
105
|
-
|
|
106
|
-
@register_op("my_op")
|
|
107
|
-
def my_op(step, dest, src):
|
|
108
|
-
# implement your logic here
|
|
109
|
-
return dest
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
Any registered operation can then be used in DSL scripts via `{"op": "my_op", ...}`.
|
|
113
|
-
|
|
114
|
-
## License
|
|
115
|
-
|
|
116
|
-
This package is provided as-is; feel free to adapt it to your project structure.
|
j_perm-0.1.3.dist-info/RECORD
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
j_perm/__init__.py,sha256=2be5yKOQ_3owmfpZB4op_uso6rHf06aUiOBuiVZO8rU,354
|
|
2
|
-
j_perm/engine.py,sha256=5u0aB_hr9qgwMRaq_KKo34z-dUo6rdFmnc6XIIi3Bss,2484
|
|
3
|
-
j_perm/jmes_ext.py,sha256=z4Feqx0H_4EzEILYd6jo7AGvsyFvabAfp2kVXL_E5Mg,527
|
|
4
|
-
j_perm/registry.py,sha256=mq6TrP9kehJlqCOp-bflGAetEwoE2PHFoRbM7E-ov6o,890
|
|
5
|
-
j_perm/ops/__init__.py,sha256=TdwKGx97X9_1Ti-VWLNBt5DGwR-cvXS7lkJf1lMD7Oo,298
|
|
6
|
-
j_perm/ops/_exec.py,sha256=7Ip1keFIv2V29sb-N10cRGTHrKhI6MP-zgTNx8aPNvM,1887
|
|
7
|
-
j_perm/ops/_if.py,sha256=ggQa73LmXbPmgkvOdeaY7czTzFaWRrVWpFL4EZ0tZY4,1569
|
|
8
|
-
j_perm/ops/assert.py,sha256=p-wu1wcoPzrgT1VtKSoQAd8ff06unz-gvaETPGW3cB0,735
|
|
9
|
-
j_perm/ops/copy.py,sha256=7cKQrRci31MxbVX7nuDGpuQDytTQ1rTF5RoL1FV2wlg,1068
|
|
10
|
-
j_perm/ops/copy_d.py,sha256=kzzOCqOpVvEeNZ-ypIi7r__ei13E0aOQsLDi0QkDxuY,975
|
|
11
|
-
j_perm/ops/delete.py,sha256=j4VZ-cnc_Txg7lgkJgJcQV9YDRIIXlTge9lRi03gPQk,893
|
|
12
|
-
j_perm/ops/distinct.py,sha256=U8BO14Nf5wLE19hR7-oNQuv2rWHTv7QKkViXfNn561E,994
|
|
13
|
-
j_perm/ops/foreach.py,sha256=EYNiM2zpxOLvX5W23ajIHrBOpbqNdV4256EAUdac_es,1442
|
|
14
|
-
j_perm/ops/replace_root.py,sha256=pUreYnQDC6jekLZMnDsRx1MsBVsKzWX-KMea5jHHqts,475
|
|
15
|
-
j_perm/ops/set.py,sha256=27CdeSoQRP2hNqTXWMvFMqxEj3BISOX7iySZdLftxHs,1869
|
|
16
|
-
j_perm/ops/update.py,sha256=JvaajmKhzHrcD_tVTT9JB-lSPaCsyvFAIt7OvXiwqT4,2439
|
|
17
|
-
j_perm/schema/__init__.py,sha256=xJML5yc85qnU-_aSTLeeDqfPYqo9-DfrENihnp1DfK8,3201
|
|
18
|
-
j_perm/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
j_perm/utils/pointers.py,sha256=X1HSCag4t-qq5zTvBMRAlBKXwpHVNNZYJrdJRtyEr4g,2788
|
|
20
|
-
j_perm/utils/special.py,sha256=KhKgrmR_pRyIbMubtV-62nNPzoLIMbxVBGpOPZQTTlA,1221
|
|
21
|
-
j_perm/utils/subst.py,sha256=hPLtqgaRTzJmvDGuQxM9VnIMCKK08IAWo_gfhogb57s,4077
|
|
22
|
-
j_perm/utils/tuples.py,sha256=0XsMId9J2T7MxtmpWQaNnbmxhileTs8Xm_vSPICkxNI,469
|
|
23
|
-
j_perm-0.1.3.dist-info/METADATA,sha256=nQqj6jp30FxhTi39rghOfOYGU2gvuSR5bvxrE1p_81U,3169
|
|
24
|
-
j_perm-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
25
|
-
j_perm-0.1.3.dist-info/top_level.txt,sha256=yveBxREqVn9DliNwmen1QWoxR0uta7bU5giS1CCffRI,7
|
|
26
|
-
j_perm-0.1.3.dist-info/RECORD,,
|
|
File without changes
|