j-perm 0.2.2__py3-none-any.whl → 0.2.4__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/constructs/ref.py +1 -1
- j_perm/engine.py +3 -1
- j_perm/ops/_assert.py +1 -1
- j_perm/ops/_assert_d.py +1 -1
- j_perm/ops/_exec.py +3 -3
- j_perm/ops/_if.py +3 -3
- j_perm/ops/copy.py +3 -2
- j_perm/ops/copy_d.py +2 -2
- j_perm/ops/delete.py +1 -1
- j_perm/ops/distinct.py +2 -2
- j_perm/ops/foreach.py +1 -1
- j_perm/ops/replace_root.py +1 -1
- j_perm/ops/set.py +2 -2
- j_perm/ops/update.py +3 -3
- j_perm/subst.py +61 -27
- {j_perm-0.2.2.dist-info → j_perm-0.2.4.dist-info}/METADATA +3 -3
- {j_perm-0.2.2.dist-info → j_perm-0.2.4.dist-info}/RECORD +19 -19
- {j_perm-0.2.2.dist-info → j_perm-0.2.4.dist-info}/WHEEL +0 -0
- {j_perm-0.2.2.dist-info → j_perm-0.2.4.dist-info}/top_level.txt +0 -0
j_perm/constructs/ref.py
CHANGED
|
@@ -9,7 +9,7 @@ from ..special_resolver import _MISSING, SpecialRegistry
|
|
|
9
9
|
@SpecialRegistry.register("$ref")
|
|
10
10
|
def of_ref(node: Mapping[str, Any], src: Mapping[str, Any], engine: "ActionEngine") -> Any:
|
|
11
11
|
# Expand templates inside "$ref" using configured substitutor
|
|
12
|
-
ptr = engine.substitutor.substitute(node["$ref"], src)
|
|
12
|
+
ptr = engine.substitutor.substitute(node["$ref"], src, engine)
|
|
13
13
|
|
|
14
14
|
dflt = node.get("$default", _MISSING)
|
|
15
15
|
try:
|
j_perm/engine.py
CHANGED
|
@@ -51,6 +51,8 @@ class ActionEngine:
|
|
|
51
51
|
normalizer: Normalizer = field(default_factory=Normalizer)
|
|
52
52
|
pointer_manager: PointerManager = field(default_factory=PointerManager)
|
|
53
53
|
|
|
54
|
+
max_depth: int = 50
|
|
55
|
+
|
|
54
56
|
def apply_actions(
|
|
55
57
|
self,
|
|
56
58
|
actions: Any,
|
|
@@ -111,7 +113,7 @@ default_engine = ActionEngine()
|
|
|
111
113
|
def apply_actions(
|
|
112
114
|
actions: Any,
|
|
113
115
|
*,
|
|
114
|
-
dest:
|
|
116
|
+
dest: Dest,
|
|
115
117
|
source: JsonLikeSource,
|
|
116
118
|
) -> Any:
|
|
117
119
|
"""Convenience function: apply a DSL script using the default engine."""
|
j_perm/ops/_assert.py
CHANGED
|
@@ -13,7 +13,7 @@ def op_assert(
|
|
|
13
13
|
engine: "ActionEngine",
|
|
14
14
|
) -> MutableMapping[str, Any]:
|
|
15
15
|
"""Assert node existence and/or value at JSON Pointer path in dest."""
|
|
16
|
-
path = engine.substitutor.substitute(step["path"], src)
|
|
16
|
+
path = engine.substitutor.substitute(step["path"], src, engine)
|
|
17
17
|
|
|
18
18
|
try:
|
|
19
19
|
current = engine.pointer_manager.get_pointer(src, path)
|
j_perm/ops/_assert_d.py
CHANGED
|
@@ -13,7 +13,7 @@ def op_assert_d(
|
|
|
13
13
|
engine: "ActionEngine",
|
|
14
14
|
) -> MutableMapping[str, Any]:
|
|
15
15
|
"""Assert node existence and/or value at JSON Pointer path in dest."""
|
|
16
|
-
path = engine.substitutor.substitute(step["path"], dest)
|
|
16
|
+
path = engine.substitutor.substitute(step["path"], dest, engine)
|
|
17
17
|
|
|
18
18
|
try:
|
|
19
19
|
current = engine.pointer_manager.get_pointer(dest, path)
|
j_perm/ops/_exec.py
CHANGED
|
@@ -23,20 +23,20 @@ def op_exec(
|
|
|
23
23
|
raise ValueError("exec operation requires either 'from' or 'actions' parameter")
|
|
24
24
|
|
|
25
25
|
if has_from:
|
|
26
|
-
actions_ptr = engine.substitutor.substitute(step["from"], src)
|
|
26
|
+
actions_ptr = engine.substitutor.substitute(step["from"], src, engine)
|
|
27
27
|
try:
|
|
28
28
|
actions = engine.pointer_manager.maybe_slice(actions_ptr, src)
|
|
29
29
|
except Exception:
|
|
30
30
|
if "default" in step:
|
|
31
31
|
actions = engine.special.resolve(step["default"], src, engine)
|
|
32
32
|
if isinstance(actions, (str, list, dict)):
|
|
33
|
-
actions = engine.substitutor.substitute(actions, src)
|
|
33
|
+
actions = engine.substitutor.substitute(actions, src, engine)
|
|
34
34
|
else:
|
|
35
35
|
raise ValueError(f"Cannot find actions at {actions_ptr}")
|
|
36
36
|
else:
|
|
37
37
|
actions = engine.special.resolve(step["actions"], src, engine)
|
|
38
38
|
if isinstance(actions, (str, list, dict)):
|
|
39
|
-
actions = engine.substitutor.substitute(actions, src)
|
|
39
|
+
actions = engine.substitutor.substitute(actions, src, engine)
|
|
40
40
|
|
|
41
41
|
merge = bool(step.get("merge", False))
|
|
42
42
|
|
j_perm/ops/_if.py
CHANGED
|
@@ -16,7 +16,7 @@ def op_if(
|
|
|
16
16
|
"""Conditionally execute nested actions based on a path or expression."""
|
|
17
17
|
if "path" in step:
|
|
18
18
|
try:
|
|
19
|
-
ptr = engine.substitutor.substitute(step["path"], src)
|
|
19
|
+
ptr = engine.substitutor.substitute(step["path"], src, engine)
|
|
20
20
|
current = engine.pointer_manager.maybe_slice(ptr, dest)
|
|
21
21
|
missing = False
|
|
22
22
|
except Exception:
|
|
@@ -24,14 +24,14 @@ def op_if(
|
|
|
24
24
|
missing = True
|
|
25
25
|
|
|
26
26
|
if "equals" in step:
|
|
27
|
-
expected = engine.substitutor.substitute(step["equals"], src)
|
|
27
|
+
expected = engine.substitutor.substitute(step["equals"], src, engine)
|
|
28
28
|
cond_val = current == expected and not missing
|
|
29
29
|
elif step.get("exists"):
|
|
30
30
|
cond_val = not missing
|
|
31
31
|
else:
|
|
32
32
|
cond_val = bool(current) and not missing
|
|
33
33
|
else:
|
|
34
|
-
raw_cond = engine.substitutor.substitute(step.get("cond"), src)
|
|
34
|
+
raw_cond = engine.substitutor.substitute(step.get("cond"), src, engine)
|
|
35
35
|
cond_val = bool(raw_cond)
|
|
36
36
|
|
|
37
37
|
branch_key = "then" if cond_val else "else"
|
j_perm/ops/copy.py
CHANGED
|
@@ -15,11 +15,11 @@ def op_copy(
|
|
|
15
15
|
engine: "ActionEngine",
|
|
16
16
|
) -> MutableMapping[str, Any]:
|
|
17
17
|
"""Copy value from source pointer into dest path."""
|
|
18
|
-
path = engine.substitutor.substitute(step["path"], src)
|
|
18
|
+
path = engine.substitutor.substitute(step["path"], src, engine)
|
|
19
19
|
create = bool(step.get("create", True))
|
|
20
20
|
extend_list = bool(step.get("extend", True))
|
|
21
21
|
|
|
22
|
-
ptr = engine.substitutor.substitute(step["from"], src)
|
|
22
|
+
ptr = engine.substitutor.substitute(step["from"], src, engine)
|
|
23
23
|
ignore = bool(step.get("ignore_missing", False))
|
|
24
24
|
|
|
25
25
|
try:
|
|
@@ -36,4 +36,5 @@ def op_copy(
|
|
|
36
36
|
{"op": "set", "path": path, "value": value, "create": create, "extend": extend_list},
|
|
37
37
|
dest,
|
|
38
38
|
src,
|
|
39
|
+
engine
|
|
39
40
|
)
|
j_perm/ops/copy_d.py
CHANGED
|
@@ -15,10 +15,10 @@ def op_copy_d(
|
|
|
15
15
|
engine: "ActionEngine",
|
|
16
16
|
) -> MutableMapping[str, Any]:
|
|
17
17
|
"""Copy value from dest (self) into another dest path."""
|
|
18
|
-
path = engine.substitutor.substitute(step["path"], src)
|
|
18
|
+
path = engine.substitutor.substitute(step["path"], src, engine)
|
|
19
19
|
create = bool(step.get("create", True))
|
|
20
20
|
|
|
21
|
-
ptr = engine.substitutor.substitute(step["from"], dest)
|
|
21
|
+
ptr = engine.substitutor.substitute(step["from"], dest, engine)
|
|
22
22
|
ignore = bool(step.get("ignore_missing", False))
|
|
23
23
|
|
|
24
24
|
try:
|
j_perm/ops/delete.py
CHANGED
|
@@ -13,7 +13,7 @@ def op_delete(
|
|
|
13
13
|
engine: "ActionEngine",
|
|
14
14
|
) -> MutableMapping[str, Any]:
|
|
15
15
|
"""Delete node at the given JSON Pointer path in dest."""
|
|
16
|
-
path = engine.substitutor.substitute(step["path"], src)
|
|
16
|
+
path = engine.substitutor.substitute(step["path"], src, engine)
|
|
17
17
|
ignore = bool(step.get("ignore_missing", True))
|
|
18
18
|
|
|
19
19
|
try:
|
j_perm/ops/distinct.py
CHANGED
|
@@ -13,14 +13,14 @@ def op_distinct(
|
|
|
13
13
|
engine: "ActionEngine",
|
|
14
14
|
) -> MutableMapping[str, Any]:
|
|
15
15
|
"""Remove duplicates from a list at the given path, preserving order."""
|
|
16
|
-
path = engine.substitutor.substitute(step["path"], src)
|
|
16
|
+
path = engine.substitutor.substitute(step["path"], src, engine)
|
|
17
17
|
lst = engine.pointer_manager.get_pointer(dest, path)
|
|
18
18
|
|
|
19
19
|
if not isinstance(lst, list):
|
|
20
20
|
raise TypeError(f"{path} is not a list (distinct)")
|
|
21
21
|
|
|
22
22
|
key = step.get("key", None)
|
|
23
|
-
key_path = engine.substitutor.substitute(key, src)
|
|
23
|
+
key_path = engine.substitutor.substitute(key, src, engine)
|
|
24
24
|
|
|
25
25
|
seen = set()
|
|
26
26
|
unique = []
|
j_perm/ops/foreach.py
CHANGED
|
@@ -14,7 +14,7 @@ def op_foreach(
|
|
|
14
14
|
engine: "ActionEngine",
|
|
15
15
|
) -> MutableMapping[str, Any]:
|
|
16
16
|
"""Iterate over array in source and execute nested actions for each element."""
|
|
17
|
-
arr_ptr = engine.substitutor.substitute(step["in"], src)
|
|
17
|
+
arr_ptr = engine.substitutor.substitute(step["in"], src, engine)
|
|
18
18
|
|
|
19
19
|
default = copy.deepcopy(step.get("default", []))
|
|
20
20
|
skip_empty = bool(step.get("skip_empty", True))
|
j_perm/ops/replace_root.py
CHANGED
|
@@ -10,5 +10,5 @@ def op_replace_root(step, dest, src, engine):
|
|
|
10
10
|
"""Replace the whole dest root value with the resolved special value."""
|
|
11
11
|
value = engine.special.resolve(step["value"], src, engine)
|
|
12
12
|
if isinstance(value, (str, list, dict)):
|
|
13
|
-
value = engine.substitutor.substitute(value, src)
|
|
13
|
+
value = engine.substitutor.substitute(value, src, engine)
|
|
14
14
|
return copy.deepcopy(value)
|
j_perm/ops/set.py
CHANGED
|
@@ -13,13 +13,13 @@ def op_set(
|
|
|
13
13
|
engine: "ActionEngine",
|
|
14
14
|
) -> MutableMapping[str, Any]:
|
|
15
15
|
"""Set or append a value at JSON Pointer path in dest."""
|
|
16
|
-
path = engine.substitutor.substitute(step["path"], src)
|
|
16
|
+
path = engine.substitutor.substitute(step["path"], src, engine)
|
|
17
17
|
create = bool(step.get("create", True))
|
|
18
18
|
extend_list = bool(step.get("extend", True))
|
|
19
19
|
|
|
20
20
|
value = engine.special.resolve(step["value"], src, engine)
|
|
21
21
|
if isinstance(value, (str, list, Mapping)):
|
|
22
|
-
value = engine.substitutor.substitute(value, src)
|
|
22
|
+
value = engine.substitutor.substitute(value, src, engine)
|
|
23
23
|
|
|
24
24
|
parent, leaf = engine.pointer_manager.ensure_parent(dest, path, create=create)
|
|
25
25
|
|
j_perm/ops/update.py
CHANGED
|
@@ -14,12 +14,12 @@ def op_update(
|
|
|
14
14
|
engine: "ActionEngine",
|
|
15
15
|
) -> MutableMapping[str, Any]:
|
|
16
16
|
"""Update a mapping at the given path using a mapping from source or inline value."""
|
|
17
|
-
path = engine.substitutor.substitute(step["path"], src)
|
|
17
|
+
path = engine.substitutor.substitute(step["path"], src, engine)
|
|
18
18
|
create = bool(step.get("create", True))
|
|
19
19
|
deep = bool(step.get("deep", False))
|
|
20
20
|
|
|
21
21
|
if "from" in step:
|
|
22
|
-
ptr = engine.substitutor.substitute(step["from"], src)
|
|
22
|
+
ptr = engine.substitutor.substitute(step["from"], src, engine)
|
|
23
23
|
try:
|
|
24
24
|
update_value = copy.deepcopy(engine.pointer_manager.maybe_slice(ptr, src))
|
|
25
25
|
except Exception:
|
|
@@ -30,7 +30,7 @@ def op_update(
|
|
|
30
30
|
elif "value" in step:
|
|
31
31
|
update_value = engine.special.resolve(step["value"], src, engine)
|
|
32
32
|
if isinstance(update_value, (str, list, Mapping)):
|
|
33
|
-
update_value = engine.substitutor.substitute(update_value, src)
|
|
33
|
+
update_value = engine.substitutor.substitute(update_value, src, engine)
|
|
34
34
|
else:
|
|
35
35
|
raise ValueError("update operation requires either 'from' or 'value' parameter")
|
|
36
36
|
|
j_perm/subst.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import copy
|
|
4
3
|
import json
|
|
5
4
|
from dataclasses import dataclass, field
|
|
6
5
|
from typing import Any, Callable, Mapping
|
|
@@ -184,21 +183,30 @@ class TemplateSubstitutor:
|
|
|
184
183
|
# Public API
|
|
185
184
|
# -------------------------------------------------------------------------
|
|
186
185
|
|
|
187
|
-
def substitute(self, obj: Any, data: Mapping[str, Any]) -> Any:
|
|
188
|
-
|
|
186
|
+
def substitute(self, obj: Any, data: Mapping[str, Any], engine: "ActionEngine") -> Any:
|
|
187
|
+
res = self.deep_substitute(obj, data, engine)
|
|
188
|
+
return self._final_unescape(res)
|
|
189
189
|
|
|
190
|
-
def flat_substitute(self, tmpl: str, data: Mapping[str, Any]) -> Any:
|
|
191
|
-
if
|
|
190
|
+
def flat_substitute(self, tmpl: str, data: Mapping[str, Any], engine: "ActionEngine") -> Any:
|
|
191
|
+
if not self._has_unescaped_placeholder(tmpl):
|
|
192
192
|
return tmpl
|
|
193
193
|
|
|
194
|
-
if tmpl.startswith("${") and tmpl.endswith("}"):
|
|
195
|
-
body = tmpl[2:-1]
|
|
196
|
-
return copy.deepcopy(self._resolve_expr(body, data))
|
|
197
|
-
|
|
198
194
|
out: list[str] = []
|
|
199
195
|
i = 0
|
|
200
196
|
|
|
201
197
|
while i < len(tmpl):
|
|
198
|
+
# literal "${"
|
|
199
|
+
if tmpl[i:i + 3] == "$${":
|
|
200
|
+
out.append("$${")
|
|
201
|
+
i += 3
|
|
202
|
+
continue
|
|
203
|
+
|
|
204
|
+
# literal "$"
|
|
205
|
+
if tmpl[i:i + 2] == "$$":
|
|
206
|
+
out.append("$$")
|
|
207
|
+
i += 2
|
|
208
|
+
continue
|
|
209
|
+
|
|
202
210
|
if tmpl[i: i + 2] == "${":
|
|
203
211
|
depth = 0
|
|
204
212
|
j = i + 2
|
|
@@ -211,7 +219,7 @@ class TemplateSubstitutor:
|
|
|
211
219
|
elif ch == "}":
|
|
212
220
|
if depth == 0:
|
|
213
221
|
expr = tmpl[i + 2: j]
|
|
214
|
-
val = self._resolve_expr(expr, data)
|
|
222
|
+
val = self._resolve_expr(expr, data, engine)
|
|
215
223
|
|
|
216
224
|
if isinstance(val, (Mapping, list)):
|
|
217
225
|
rendered = json.dumps(val, ensure_ascii=False)
|
|
@@ -234,29 +242,29 @@ class TemplateSubstitutor:
|
|
|
234
242
|
|
|
235
243
|
return "".join(out)
|
|
236
244
|
|
|
237
|
-
def deep_substitute(self, obj: Any, data: Mapping[str, Any], _depth: int = 0) -> Any:
|
|
238
|
-
if _depth >
|
|
245
|
+
def deep_substitute(self, obj: Any, data: Mapping[str, Any], engine: "ActionEngine", _depth: int = 0) -> Any:
|
|
246
|
+
if _depth > engine.max_depth:
|
|
239
247
|
raise RecursionError("too deep interpolation")
|
|
240
248
|
|
|
241
249
|
if isinstance(obj, str):
|
|
242
|
-
out = self.flat_substitute(obj, data)
|
|
243
|
-
if isinstance(out, str) and
|
|
244
|
-
return self.deep_substitute(out, data, _depth + 1)
|
|
250
|
+
out = self.flat_substitute(obj, data, engine)
|
|
251
|
+
if isinstance(out, str) and self._has_unescaped_placeholder(out):
|
|
252
|
+
return self.deep_substitute(out, data, engine, _depth + 1)
|
|
245
253
|
return out
|
|
246
254
|
|
|
247
255
|
if isinstance(obj, list):
|
|
248
|
-
return [self.deep_substitute(item, data, _depth) for item in obj]
|
|
256
|
+
return [self.deep_substitute(item, data, engine, _depth) for item in obj]
|
|
249
257
|
|
|
250
258
|
if isinstance(obj, tuple):
|
|
251
|
-
return [self.deep_substitute(item, data, _depth) for item in obj]
|
|
259
|
+
return [self.deep_substitute(item, data, engine, _depth) for item in obj]
|
|
252
260
|
|
|
253
261
|
if isinstance(obj, Mapping):
|
|
254
262
|
out: dict[Any, Any] = {}
|
|
255
263
|
for k, v in obj.items():
|
|
256
|
-
new_key = self.deep_substitute(k, data, _depth) if isinstance(k, str) else k
|
|
264
|
+
new_key = self.deep_substitute(k, data, engine, _depth) if isinstance(k, str) else k
|
|
257
265
|
if new_key in out:
|
|
258
266
|
raise KeyError(f"duplicate key after substitution: {new_key!r}")
|
|
259
|
-
out[new_key] = self.deep_substitute(v, data, _depth)
|
|
267
|
+
out[new_key] = self.deep_substitute(v, data, engine, _depth)
|
|
260
268
|
return out
|
|
261
269
|
|
|
262
270
|
return obj
|
|
@@ -265,7 +273,33 @@ class TemplateSubstitutor:
|
|
|
265
273
|
# Internals
|
|
266
274
|
# -------------------------------------------------------------------------
|
|
267
275
|
|
|
268
|
-
def
|
|
276
|
+
def _final_unescape(self, obj: Any) -> Any:
|
|
277
|
+
if isinstance(obj, str):
|
|
278
|
+
return obj.replace("$${", "${").replace("$$", "$")
|
|
279
|
+
if isinstance(obj, list):
|
|
280
|
+
return [self._final_unescape(x) for x in obj]
|
|
281
|
+
if isinstance(obj, tuple):
|
|
282
|
+
return tuple(self._final_unescape(x) for x in obj)
|
|
283
|
+
if isinstance(obj, Mapping):
|
|
284
|
+
return {self._final_unescape(k) if isinstance(k, str) else k: self._final_unescape(v)
|
|
285
|
+
for k, v in obj.items()}
|
|
286
|
+
return obj
|
|
287
|
+
|
|
288
|
+
@staticmethod
|
|
289
|
+
def _has_unescaped_placeholder(s: str) -> bool:
|
|
290
|
+
i = 0
|
|
291
|
+
while True:
|
|
292
|
+
j = s.find("${", i)
|
|
293
|
+
if j == -1:
|
|
294
|
+
return False
|
|
295
|
+
if j > 0 and s[j - 1] == "$":
|
|
296
|
+
i = j + 2
|
|
297
|
+
continue
|
|
298
|
+
return True
|
|
299
|
+
|
|
300
|
+
return False
|
|
301
|
+
|
|
302
|
+
def _resolve_expr(self, expr: str, data: Mapping[str, Any], engine: "ActionEngine") -> Any:
|
|
269
303
|
expr = expr.strip()
|
|
270
304
|
|
|
271
305
|
# 1) Casters
|
|
@@ -273,26 +307,26 @@ class TemplateSubstitutor:
|
|
|
273
307
|
tag = f"{prefix}:"
|
|
274
308
|
if expr.startswith(tag):
|
|
275
309
|
inner = expr[len(tag):]
|
|
276
|
-
value = self.flat_substitute(inner, data)
|
|
310
|
+
value = self.flat_substitute(inner, data, engine)
|
|
277
311
|
|
|
278
|
-
if isinstance(value, str) and
|
|
279
|
-
value = self.flat_substitute(value, data)
|
|
312
|
+
if isinstance(value, str) and self._has_unescaped_placeholder(value):
|
|
313
|
+
value = self.flat_substitute(value, data, engine)
|
|
280
314
|
|
|
281
315
|
return fn(value)
|
|
282
316
|
|
|
283
317
|
# 2) JMESPath
|
|
284
318
|
if expr.startswith("?"):
|
|
285
319
|
query_raw = expr[1:].lstrip()
|
|
286
|
-
query_expanded = self.flat_substitute(query_raw, data)
|
|
320
|
+
query_expanded = self.flat_substitute(query_raw, data, engine)
|
|
287
321
|
return jmespath.search(query_expanded, data, options=self._jp_options)
|
|
288
322
|
|
|
289
323
|
# 3) Nested template
|
|
290
|
-
if
|
|
291
|
-
return self.flat_substitute(expr, data)
|
|
324
|
+
if self._has_unescaped_placeholder(expr):
|
|
325
|
+
return self.flat_substitute(expr, data, engine)
|
|
292
326
|
|
|
293
327
|
# 4) JSON Pointer fallback
|
|
294
328
|
pointer = "/" + expr.lstrip("/")
|
|
295
329
|
try:
|
|
296
|
-
return engine.pointer_manager.maybe_slice(pointer, data)
|
|
330
|
+
return engine.pointer_manager.maybe_slice(pointer, data)
|
|
297
331
|
except Exception:
|
|
298
332
|
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: j-perm
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: json permutation library
|
|
5
5
|
Author-email: Roman <kuschanow@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -799,8 +799,8 @@ def my_op(step, dest, src, engine):
|
|
|
799
799
|
from j_perm import SpecialRegistry
|
|
800
800
|
|
|
801
801
|
@SpecialRegistry.register("$upper")
|
|
802
|
-
def sp_upper(node, src, resolver):
|
|
803
|
-
value = resolver.substitutor.substitute(node["$upper"], src)
|
|
802
|
+
def sp_upper(node, src, resolver, engine):
|
|
803
|
+
value = resolver.substitutor.substitute(node["$upper"], src, engine)
|
|
804
804
|
return str(value).upper()
|
|
805
805
|
```
|
|
806
806
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
j_perm/__init__.py,sha256=81aLdcmlUg51R6xR-VXVDDUeM87ezy3ZuiLpblHZ_wk,873
|
|
2
|
-
j_perm/engine.py,sha256=
|
|
2
|
+
j_perm/engine.py,sha256=gHJdg-j_8UW9jmMQT6DIiNulJw5BQmSCEZihlGZsWJs,4053
|
|
3
3
|
j_perm/normalizer.py,sha256=zxWtARRNuzS-zgFuB40dqU0oaUUk8PLKJNOPNb5wbRw,2672
|
|
4
4
|
j_perm/op_handler.py,sha256=h28thz_18DwZTb9IZtTd6kfsZj7hN4UsmU4uf3aMYpo,1649
|
|
5
5
|
j_perm/pointers.py,sha256=Czhq9vre_HnxhT1iOs8cDcKdCvEum5_YdvaEzoZ3iTY,3205
|
|
6
6
|
j_perm/special_resolver.py,sha256=khRVWXrE3Vch1gbxsfFwj9JQ37pZ-_ojMeh-G2Vv7bs,4032
|
|
7
|
-
j_perm/subst.py,sha256=
|
|
7
|
+
j_perm/subst.py,sha256=I1O9qdmJp9TYjpfnqOgyIgL064hWGCmsGoxCbFWCBL4,11026
|
|
8
8
|
j_perm/casters/__init__.py,sha256=mD49oMEyj6oDfSKXEJ8DbnmqkSypfEEg3VMI_rfaK-4,114
|
|
9
9
|
j_perm/casters/_bool.py,sha256=qRsT7IcFBApD09elKUyUUaZmfePSIsOsKQHQHsgnHsw,230
|
|
10
10
|
j_perm/casters/_float.py,sha256=C4r-h6zbkjmQnoEdE2RDMhSkW9oGrvxbQngJZ2T7_tU,153
|
|
@@ -12,28 +12,28 @@ j_perm/casters/_int.py,sha256=f1BKqsULiG6Puov1qcGS_inSnv0hZtQ0deQEMP0v0i4,145
|
|
|
12
12
|
j_perm/casters/_str.py,sha256=v1_BD1_hPbOtvO5CKYAlNEGbMhpR56eKCnV2a2Q4kGU,145
|
|
13
13
|
j_perm/constructs/__init__.py,sha256=TTUPSMyvj8HSfPikrFqXaFsechc9aOIbjtVjy4TOolE,50
|
|
14
14
|
j_perm/constructs/eval.py,sha256=UzjZK27UAzsl3s26Y3RWBPhuKX1Az0fK6xk-cgpS8pQ,452
|
|
15
|
-
j_perm/constructs/ref.py,sha256=
|
|
15
|
+
j_perm/constructs/ref.py,sha256=WgzEo54IhGWvBVSwPGTeqCRLDyK5uPJ01p5Wjd1YdNM,634
|
|
16
16
|
j_perm/funcs/__init__.py,sha256=8yIafxhCH5B7jXrsautQEtl4Qt8RcUK7IWNniORj9ow,31
|
|
17
17
|
j_perm/funcs/subtract.py,sha256=8W49TsrnIU4EVjS8tWQY2GXlX2nAaQ1O9O1JlrVYdIw,288
|
|
18
18
|
j_perm/ops/__init__.py,sha256=j_U4Aq0iwEvZOF0jqMmlQA0NisJsHNJWzqkfyMWuHFA,364
|
|
19
|
-
j_perm/ops/_assert.py,sha256=
|
|
20
|
-
j_perm/ops/_assert_d.py,sha256=
|
|
21
|
-
j_perm/ops/_exec.py,sha256=
|
|
22
|
-
j_perm/ops/_if.py,sha256=
|
|
23
|
-
j_perm/ops/copy.py,sha256=
|
|
24
|
-
j_perm/ops/copy_d.py,sha256=
|
|
25
|
-
j_perm/ops/delete.py,sha256=
|
|
26
|
-
j_perm/ops/distinct.py,sha256=
|
|
27
|
-
j_perm/ops/foreach.py,sha256=
|
|
28
|
-
j_perm/ops/replace_root.py,sha256=
|
|
29
|
-
j_perm/ops/set.py,sha256=
|
|
30
|
-
j_perm/ops/update.py,sha256=
|
|
19
|
+
j_perm/ops/_assert.py,sha256=vXsQBNIBQYLNSrO6u-vg4_oavvK5N_u-MAc8AqnISBk,769
|
|
20
|
+
j_perm/ops/_assert_d.py,sha256=sG1DC-ElJi54EN2LPzzbvw_5jtOoR1w6j_Ml3mO5Gwo,779
|
|
21
|
+
j_perm/ops/_exec.py,sha256=e3TCFN7bzJ_mjPbpm4ZZq0Dbz-YoJhOiHH1Dt4PwY3k,1919
|
|
22
|
+
j_perm/ops/_if.py,sha256=QziuiEOSkcOMMbyHm_C9IYRhybdtqiLdtQSBbyEL6To,1596
|
|
23
|
+
j_perm/ops/copy.py,sha256=485Gejp_qv3KN6SPu9vriSaJ7i1OxQj7McbQcNOPq20,1123
|
|
24
|
+
j_perm/ops/copy_d.py,sha256=iTlZ6lE1gMMcCaUjVWhbXHpBxd97OLXM9Ml5SP0Xvbw,1015
|
|
25
|
+
j_perm/ops/delete.py,sha256=YwPyMxPZ2LnCVC__bivvDLxlsvT2mnrmNIH7Qgw7bjk,894
|
|
26
|
+
j_perm/ops/distinct.py,sha256=eL7Ja4YNVCpsrgiuMxew2xqO3pLitJyAI3ygzy3hSVs,1066
|
|
27
|
+
j_perm/ops/foreach.py,sha256=zbELdguV5He_7nBoekaFsn6dsqBQuRzCoPIB44weUbE,1415
|
|
28
|
+
j_perm/ops/replace_root.py,sha256=klPY9E3KsPfnswIM4CdX_JPXGE1WWjr0sXSXSwn3ooo,453
|
|
29
|
+
j_perm/ops/set.py,sha256=YJjS1BXEEdPxFbUcJGu4YZPt0HHsk9cixpk0OnVQB4E,1886
|
|
30
|
+
j_perm/ops/update.py,sha256=9ouXm4ICNBqr03gJXUvV78AiytgkA4K2Fwb648r8rhE,2457
|
|
31
31
|
j_perm/schema/__init__.py,sha256=mhEbGdi1MgLeEm1IL8-tkTtbIdrdlvQi22sBr7vCUqg,3392
|
|
32
32
|
j_perm/shorthands/__init__.py,sha256=zvsu15iExYtUrct6Ob4IRs6Ao46PoZaCKVIUhMBY4Dk,117
|
|
33
33
|
j_perm/shorthands/_assert.py,sha256=iRvuUGlN5Bj9G5Bo-aXUa4MQujgmrR3N-PhDeee6xcY,555
|
|
34
34
|
j_perm/shorthands/assign_or_append.py,sha256=TsSzaQXb5qoKtY6tvx_skHob-695Zii5roUfXltznAQ,621
|
|
35
35
|
j_perm/shorthands/delete.py,sha256=PZeTRcP6-Q3SdbdyruWWXtMJ9mTnz1CBCHiOpHNI06Q,311
|
|
36
|
-
j_perm-0.2.
|
|
37
|
-
j_perm-0.2.
|
|
38
|
-
j_perm-0.2.
|
|
39
|
-
j_perm-0.2.
|
|
36
|
+
j_perm-0.2.4.dist-info/METADATA,sha256=ocLOygg0xjsrbelwpNrX0fMlDPT2He_Ur-NatWC0keM,17674
|
|
37
|
+
j_perm-0.2.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
38
|
+
j_perm-0.2.4.dist-info/top_level.txt,sha256=yveBxREqVn9DliNwmen1QWoxR0uta7bU5giS1CCffRI,7
|
|
39
|
+
j_perm-0.2.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|