dyngle 1.0.1__py3-none-any.whl → 1.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.
Potentially problematic release.
This version of dyngle might be problematic. Click here for more details.
- dyngle/__init__.py +9 -5
- dyngle/command/run_command.py +1 -1
- dyngle/model/expression.py +10 -4
- dyngle/model/live_data.py +20 -5
- dyngle/model/operation.py +4 -5
- {dyngle-1.0.1.dist-info → dyngle-1.2.0.dist-info}/METADATA +4 -5
- dyngle-1.2.0.dist-info/RECORD +15 -0
- {dyngle-1.0.1.dist-info → dyngle-1.2.0.dist-info}/WHEEL +1 -1
- dyngle-1.0.1.dist-info/RECORD +0 -15
- {dyngle-1.0.1.dist-info → dyngle-1.2.0.dist-info}/entry_points.txt +0 -0
dyngle/__init__.py
CHANGED
|
@@ -9,6 +9,7 @@ from dyngle.command import DyngleCommand
|
|
|
9
9
|
from dyngle.error import DyngleError
|
|
10
10
|
from dyngle.model.expression import expression
|
|
11
11
|
from dyngle.model.operation import Operation
|
|
12
|
+
from dyngle.model.template import Template
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class DyngleApp(WizApp):
|
|
@@ -53,19 +54,22 @@ class DyngleApp(WizApp):
|
|
|
53
54
|
if isinstance(config, list):
|
|
54
55
|
operation = Operation({}, config)
|
|
55
56
|
elif isinstance(config, dict):
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
expr_texts = config.get('expressions') or {}
|
|
58
|
+
expressions = _expressions_from_texts(expr_texts)
|
|
59
|
+
values = config.get('values') or {}
|
|
58
60
|
steps = config.get('steps') or []
|
|
59
|
-
operation = Operation(
|
|
61
|
+
operation = Operation(expressions | values, steps)
|
|
60
62
|
else:
|
|
61
63
|
raise DyngleError(f"Invalid operation configuration for {key}")
|
|
62
64
|
operations[key] = operation
|
|
63
65
|
return operations
|
|
64
66
|
|
|
65
67
|
@cached_property
|
|
66
|
-
def
|
|
68
|
+
def globals(self):
|
|
67
69
|
expr_texts = self._get_configuration_details('expressions')
|
|
68
|
-
|
|
70
|
+
expressions = _expressions_from_texts(expr_texts)
|
|
71
|
+
values = self._get_configuration_details('values')
|
|
72
|
+
return expressions | (values if values else {})
|
|
69
73
|
|
|
70
74
|
|
|
71
75
|
def _expressions_from_texts(expr_texts):
|
dyngle/command/run_command.py
CHANGED
|
@@ -42,6 +42,6 @@ class RunCommand(DyngleCommand):
|
|
|
42
42
|
self._validate_operation_exists(operations)
|
|
43
43
|
operation = operations[self.operation]
|
|
44
44
|
|
|
45
|
-
operation.run(data, self.app.
|
|
45
|
+
operation.run(data, self.app.globals)
|
|
46
46
|
|
|
47
47
|
return f'Operation "{self.operation}" completed successfully'
|
dyngle/model/expression.py
CHANGED
|
@@ -54,6 +54,7 @@ GLOBALS = {
|
|
|
54
54
|
"enumerate": enumerate,
|
|
55
55
|
"zip": zip,
|
|
56
56
|
"range": range,
|
|
57
|
+
"type": type
|
|
57
58
|
},
|
|
58
59
|
|
|
59
60
|
# Mathematical operations
|
|
@@ -107,11 +108,16 @@ def _evaluate(expression: str, locals: dict) -> str:
|
|
|
107
108
|
"""
|
|
108
109
|
try:
|
|
109
110
|
result = eval(expression, GLOBALS, locals)
|
|
110
|
-
except KeyError:
|
|
111
|
+
except KeyError as error:
|
|
111
112
|
raise DyngleError(f"The following expression contains " +
|
|
112
|
-
f"
|
|
113
|
+
f"invalid name '{error}:\n{expression}")
|
|
114
|
+
|
|
115
|
+
# Allow the use of a comma to separate sub-expressions, which can then use
|
|
116
|
+
# warus to set values, and only the last exxpression in the list returns a
|
|
117
|
+
# value.
|
|
113
118
|
result = result[-1] if isinstance(result, tuple) else result
|
|
114
|
-
|
|
119
|
+
|
|
120
|
+
return result
|
|
115
121
|
|
|
116
122
|
|
|
117
123
|
# The 'expression' function returns the expression object itself, which is
|
|
@@ -137,7 +143,7 @@ def expression(text: str) -> Callable[[dict], str]:
|
|
|
137
143
|
# syntax too
|
|
138
144
|
|
|
139
145
|
def resolve(key):
|
|
140
|
-
return live_data.resolve(key)
|
|
146
|
+
return live_data.resolve(key, str_only=False)
|
|
141
147
|
locals = locals | {'resolve': resolve}
|
|
142
148
|
|
|
143
149
|
# Perform the Python eval, expanded above
|
dyngle/model/live_data.py
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
from collections import UserDict
|
|
2
|
+
from datetime import date, timedelta
|
|
3
|
+
from numbers import Number
|
|
4
|
+
|
|
5
|
+
from yaml import safe_dump
|
|
2
6
|
|
|
3
7
|
from dyngle.error import DyngleError
|
|
4
8
|
|
|
5
9
|
|
|
6
10
|
class LiveData(UserDict):
|
|
7
11
|
|
|
8
|
-
def resolve(self, key: str):
|
|
12
|
+
def resolve(self, key: str, str_only: bool = True):
|
|
9
13
|
"""Given a key (which might be dot-separated), return
|
|
10
14
|
the value (which might include evaluating expressions)."""
|
|
11
15
|
|
|
@@ -16,7 +20,18 @@ class LiveData(UserDict):
|
|
|
16
20
|
raise DyngleError(
|
|
17
21
|
f"Invalid expression or data reference '{key}'")
|
|
18
22
|
current = current[part]
|
|
19
|
-
if callable(current)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
result = current(self) if callable(current) else current
|
|
24
|
+
return _stringify(result) if str_only else result
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _stringify(value) -> str:
|
|
28
|
+
if isinstance(value, bool):
|
|
29
|
+
return '.' if value is True else ''
|
|
30
|
+
elif isinstance(value, (Number, str, date, timedelta)):
|
|
31
|
+
return str(value)
|
|
32
|
+
elif isinstance(value, (list, dict, tuple)):
|
|
33
|
+
return safe_dump(value)
|
|
34
|
+
elif isinstance(value, set):
|
|
35
|
+
return safe_dump(list(value))
|
|
36
|
+
else:
|
|
37
|
+
raise DyngleError(f'Unable to serialize value of type {type(value)}')
|
dyngle/model/operation.py
CHANGED
|
@@ -12,14 +12,13 @@ from dyngle.model.template import Template
|
|
|
12
12
|
@dataclass
|
|
13
13
|
class Operation:
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
# Expressions and values defined within the operation
|
|
16
|
+
locals: dict
|
|
16
17
|
|
|
17
18
|
steps: list
|
|
18
19
|
|
|
19
|
-
def run(self, data: dict,
|
|
20
|
-
|
|
21
|
-
# Data takes precedence if names match
|
|
22
|
-
live_data = LiveData(expressions) | data
|
|
20
|
+
def run(self, data: dict, globals: dict):
|
|
21
|
+
live_data = LiveData(globals) | self.locals | data
|
|
23
22
|
for markup in self.steps:
|
|
24
23
|
step = Step(markup)
|
|
25
24
|
step.run(live_data)
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: dyngle
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Run lightweight local workflows
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Steampunk Wizard
|
|
7
7
|
Author-email: dyngle@steamwiz.io
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.13,<4.0
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
13
11
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
13
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
15
14
|
Requires-Dist: wizlib (>=3.3.8,<3.4.0)
|
|
16
15
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
dyngle/__init__.py,sha256=ZSBChSHOOTW68vZ-2q4ts8VhmEJ5hssG45jhbTTMvk0,2919
|
|
2
|
+
dyngle/__main__.py,sha256=pYRIwzix_AL8CdJaDDis_8yMBBWO2N72NNwkroo1dQo,95
|
|
3
|
+
dyngle/command/__init__.py,sha256=1S86gbef8MYvG-TWD5JRIWzFg7qV5xKhp9QXx9zEx5c,94
|
|
4
|
+
dyngle/command/run_command.py,sha256=gYTQjATRMu_81HLP-hrMz7GNw9Lcz2VjuhP7h_qYLcE,1514
|
|
5
|
+
dyngle/error.py,sha256=CGcTa8L4O1qsHEYnzp_JBbkvntJTv2Qz46wj_TI8NLk,39
|
|
6
|
+
dyngle/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
dyngle/model/expression.py,sha256=9nwfahjOHtScjdDzjwWIleo60lJjtXGrPGfroCbslvg,4431
|
|
8
|
+
dyngle/model/live_data.py,sha256=yWiTgb9w9KaJ2yynGEudfu89Z3hOoHcLdUXfEJRtZG4,1197
|
|
9
|
+
dyngle/model/operation.py,sha256=nSz-8Eh03xAvQlc6Wzn56t-dMArp9uJWY_8XJJZEIwc,1743
|
|
10
|
+
dyngle/model/safe_path.py,sha256=Hk2AhP6e3yKGh3kKrLLwhvAlMNx-j2jObBYJL-_doAU,3339
|
|
11
|
+
dyngle/model/template.py,sha256=MeXu--ZNtj_ujABU1GjjcQ1Ea_o_M-50LocuXFeOLRE,887
|
|
12
|
+
dyngle-1.2.0.dist-info/METADATA,sha256=0jg6HNybNbzJZZRr6-hEUDDMhHJVDNVrLdBZ3m8P7kA,9710
|
|
13
|
+
dyngle-1.2.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
14
|
+
dyngle-1.2.0.dist-info/entry_points.txt,sha256=rekiGhtweiHKm9g1jdGb3FhzqDrk1kigJDeSNollZSA,48
|
|
15
|
+
dyngle-1.2.0.dist-info/RECORD,,
|
dyngle-1.0.1.dist-info/RECORD
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
dyngle/__init__.py,sha256=Mku-FaOXp1HMBoQc6K9ZJfhr9n-CXxvtotRFzSZ042I,2728
|
|
2
|
-
dyngle/__main__.py,sha256=pYRIwzix_AL8CdJaDDis_8yMBBWO2N72NNwkroo1dQo,95
|
|
3
|
-
dyngle/command/__init__.py,sha256=1S86gbef8MYvG-TWD5JRIWzFg7qV5xKhp9QXx9zEx5c,94
|
|
4
|
-
dyngle/command/run_command.py,sha256=yq5VJv3XWtzTf9F_rW-_nANFPGGkIMQO3kiU5atEATo,1525
|
|
5
|
-
dyngle/error.py,sha256=CGcTa8L4O1qsHEYnzp_JBbkvntJTv2Qz46wj_TI8NLk,39
|
|
6
|
-
dyngle/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
dyngle/model/expression.py,sha256=FqYOfotUzTHDyON9cUCwyO5Cw4jTphY_TuWjQyhvSFY,4220
|
|
8
|
-
dyngle/model/live_data.py,sha256=6YdCfCDjhzMoCC5Znuwn_T-UpqeU_3I38M1mOBOLh2U,629
|
|
9
|
-
dyngle/model/operation.py,sha256=87TOCGr_ECgWaLOAkJs4xwqChZvE3FQiGU4jf33x8LY,1810
|
|
10
|
-
dyngle/model/safe_path.py,sha256=Hk2AhP6e3yKGh3kKrLLwhvAlMNx-j2jObBYJL-_doAU,3339
|
|
11
|
-
dyngle/model/template.py,sha256=MeXu--ZNtj_ujABU1GjjcQ1Ea_o_M-50LocuXFeOLRE,887
|
|
12
|
-
dyngle-1.0.1.dist-info/METADATA,sha256=jyuumkrmM3J37uXUvlVpssOGN1noeeSkcft8_IS4mwQ,9761
|
|
13
|
-
dyngle-1.0.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
14
|
-
dyngle-1.0.1.dist-info/entry_points.txt,sha256=rekiGhtweiHKm9g1jdGb3FhzqDrk1kigJDeSNollZSA,48
|
|
15
|
-
dyngle-1.0.1.dist-info/RECORD,,
|
|
File without changes
|