dyngle 1.3.0__py3-none-any.whl → 1.5.1__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.
- dyngle/__init__.py +35 -57
- dyngle/command/__init__.py +1 -1
- dyngle/command/null_command.py +6 -0
- dyngle/command/run_command.py +12 -17
- dyngle/model/dyngleverse.py +37 -0
- dyngle/model/expression.py +13 -4
- dyngle/model/operation.py +88 -23
- {dyngle-1.3.0.dist-info → dyngle-1.5.1.dist-info}/METADATA +41 -3
- dyngle-1.5.1.dist-info/RECORD +17 -0
- dyngle-1.3.0.dist-info/RECORD +0 -15
- {dyngle-1.3.0.dist-info → dyngle-1.5.1.dist-info}/WHEEL +0 -0
- {dyngle-1.3.0.dist-info → dyngle-1.5.1.dist-info}/entry_points.txt +0 -0
dyngle/__init__.py
CHANGED
|
@@ -7,6 +7,7 @@ from wizlib.ui_handler import UIHandler
|
|
|
7
7
|
|
|
8
8
|
from dyngle.command import DyngleCommand
|
|
9
9
|
from dyngle.error import DyngleError
|
|
10
|
+
from dyngle.model.dyngleverse import Dyngleverse
|
|
10
11
|
from dyngle.model.expression import expression
|
|
11
12
|
from dyngle.model.operation import Operation
|
|
12
13
|
from dyngle.model.template import Template
|
|
@@ -18,62 +19,39 @@ class DyngleApp(WizApp):
|
|
|
18
19
|
name = 'dyngle'
|
|
19
20
|
handlers = [StreamHandler, ConfigHandler, UIHandler]
|
|
20
21
|
|
|
21
|
-
# For possible upstreaming to WizLib, a mechanism to "import" configuration
|
|
22
|
-
# settings from external files.
|
|
23
|
-
|
|
24
22
|
@property
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
def dyngleverse(self):
|
|
24
|
+
"""Offload the indexing of operation and expression definitions to
|
|
25
|
+
another class. But we keep import handling here in the app because we
|
|
26
|
+
might want to upstream import/include to WizLib at some point."""
|
|
27
|
+
|
|
28
|
+
if not hasattr(self, '_dyngleverse'):
|
|
29
|
+
self._dyngleverse = Dyngleverse()
|
|
30
|
+
imports = self._get_imports(self.config, [])
|
|
31
|
+
for imported_config in imports:
|
|
32
|
+
definitions = imported_config.get('dyngle')
|
|
33
|
+
self._dyngleverse.load_config(definitions)
|
|
34
|
+
self._dyngleverse.load_config(self.config.get('dyngle'))
|
|
35
|
+
return self._dyngleverse
|
|
36
|
+
|
|
37
|
+
def _get_imports(self,
|
|
38
|
+
config_handler: ConfigHandler,
|
|
39
|
+
no_loops: list) -> dict:
|
|
40
|
+
imports = config_handler.get('dyngle-imports')
|
|
41
|
+
confs = []
|
|
42
|
+
if imports:
|
|
43
|
+
for filename in imports:
|
|
44
|
+
import_path = Path(filename).expanduser()
|
|
45
|
+
# If the path is relative, resolve it relative to the importing
|
|
46
|
+
# config file
|
|
47
|
+
if not import_path.is_absolute() and config_handler.file:
|
|
48
|
+
config_dir = Path(config_handler.file).parent
|
|
49
|
+
full_filename = (config_dir / import_path).resolve()
|
|
50
|
+
else:
|
|
51
|
+
full_filename = import_path
|
|
52
|
+
if full_filename not in no_loops:
|
|
53
|
+
no_loops.append(full_filename)
|
|
54
|
+
child_handler = ConfigHandler(full_filename)
|
|
55
|
+
confs += self._get_imports(child_handler, no_loops)
|
|
32
56
|
confs.append(ConfigHandler(full_filename))
|
|
33
|
-
|
|
34
|
-
return self.__imported_configurations
|
|
35
|
-
|
|
36
|
-
def _get_configuration_details(self, type: str):
|
|
37
|
-
label = f'dyngle-{type}'
|
|
38
|
-
details = {}
|
|
39
|
-
for conf in self._imported_configrations:
|
|
40
|
-
if (imported_details := conf.get(label)):
|
|
41
|
-
details |= imported_details
|
|
42
|
-
configured_details = self.config.get(label)
|
|
43
|
-
if configured_details:
|
|
44
|
-
details |= configured_details
|
|
45
|
-
return details
|
|
46
|
-
|
|
47
|
-
@cached_property
|
|
48
|
-
def operations(self):
|
|
49
|
-
operations_configs = self._get_configuration_details('operations')
|
|
50
|
-
if not operations_configs:
|
|
51
|
-
raise DyngleError("No operations defined in configuration")
|
|
52
|
-
operations = {}
|
|
53
|
-
for key, config in operations_configs.items():
|
|
54
|
-
if isinstance(config, list):
|
|
55
|
-
operation = Operation({}, config)
|
|
56
|
-
elif isinstance(config, dict):
|
|
57
|
-
expr_texts = config.get('expressions') or {}
|
|
58
|
-
expressions = _expressions_from_texts(expr_texts)
|
|
59
|
-
values = config.get('values') or {}
|
|
60
|
-
steps = config.get('steps') or []
|
|
61
|
-
operation = Operation(expressions | values, steps)
|
|
62
|
-
else:
|
|
63
|
-
raise DyngleError(f"Invalid operation configuration for {key}")
|
|
64
|
-
operations[key] = operation
|
|
65
|
-
return operations
|
|
66
|
-
|
|
67
|
-
@cached_property
|
|
68
|
-
def globals(self):
|
|
69
|
-
expr_texts = self._get_configuration_details('expressions')
|
|
70
|
-
expressions = _expressions_from_texts(expr_texts)
|
|
71
|
-
values = self._get_configuration_details('values')
|
|
72
|
-
return expressions | (values if values else {})
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def _expressions_from_texts(expr_texts):
|
|
76
|
-
if expr_texts:
|
|
77
|
-
return {k: expression(t) for k, t in expr_texts.items()}
|
|
78
|
-
else:
|
|
79
|
-
return {}
|
|
57
|
+
return confs
|
dyngle/command/__init__.py
CHANGED
dyngle/command/run_command.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from functools import cached_property
|
|
1
2
|
import shlex
|
|
2
3
|
import subprocess
|
|
3
4
|
from wizlib.parser import WizParser
|
|
@@ -17,31 +18,25 @@ class RunCommand(DyngleCommand):
|
|
|
17
18
|
@classmethod
|
|
18
19
|
def add_args(cls, parser: WizParser):
|
|
19
20
|
super().add_args(parser)
|
|
20
|
-
parser.add_argument(
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
'operation', help='Operation name to run', nargs='?')
|
|
21
23
|
parser.add_argument(
|
|
22
24
|
'args', nargs='*', help='Optional operation arguments')
|
|
23
25
|
|
|
24
26
|
def handle_vals(self):
|
|
25
27
|
super().handle_vals()
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
f"Available operations: {available_operations}")
|
|
28
|
+
keys = self.app.dyngleverse.operations.keys()
|
|
29
|
+
if not self.provided('operation'):
|
|
30
|
+
self.operation = self.app.ui.get_text('Operation: ', sorted(keys))
|
|
31
|
+
if not self.operation:
|
|
32
|
+
raise DyngleError(f"Operation required.")
|
|
33
|
+
if self.operation not in keys:
|
|
34
|
+
raise DyngleError(f"Invalid operation {self.operation}.")
|
|
34
35
|
|
|
35
36
|
@DyngleCommand.wrap
|
|
36
37
|
def execute(self):
|
|
37
38
|
data_string = self.app.stream.text
|
|
38
39
|
data = safe_load(data_string) or {}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
operations = self.app.operations
|
|
42
|
-
self._validate_operation_exists(operations)
|
|
43
|
-
operation = operations[self.operation]
|
|
44
|
-
|
|
45
|
-
operation.run(data, self.app.globals)
|
|
46
|
-
|
|
40
|
+
operation = self.app.dyngleverse.operations[self.operation]
|
|
41
|
+
operation.run(data, self.args)
|
|
47
42
|
return f'Operation "{self.operation}" completed successfully'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from functools import cached_property
|
|
2
|
+
|
|
3
|
+
from dyngle.model.expression import expression
|
|
4
|
+
from dyngle.model.live_data import LiveData
|
|
5
|
+
from dyngle.model.operation import Operation
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Dyngleverse:
|
|
9
|
+
"""Represents the entire immutable set of definitions for operations,
|
|
10
|
+
expresssions, and values. Operates as a sort of index/database."""
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self.operations = {}
|
|
14
|
+
self.all_globals = {}
|
|
15
|
+
|
|
16
|
+
def load_config(self, config: dict):
|
|
17
|
+
"""
|
|
18
|
+
Load additional configuration, which will always take higher precedence
|
|
19
|
+
than previously loaded configuration.
|
|
20
|
+
"""
|
|
21
|
+
ops_defs = config.get('operations') or {}
|
|
22
|
+
for key, op_def in ops_defs.items():
|
|
23
|
+
operation = Operation(self, op_def, key)
|
|
24
|
+
self.operations[key] = operation
|
|
25
|
+
self.all_globals |= Dyngleverse.parse_constants(config)
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def parse_constants(definition: dict):
|
|
29
|
+
"""
|
|
30
|
+
At either the global (dyngleverse) or local (within an operation)
|
|
31
|
+
level, we might find values and expressions.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
expr_texts = definition.get('expressions') or {}
|
|
35
|
+
expressions = {k: expression(t) for k, t in expr_texts.items()}
|
|
36
|
+
values = definition.get('values') or {}
|
|
37
|
+
return expressions | values
|
dyngle/model/expression.py
CHANGED
|
@@ -130,8 +130,11 @@ def expression(text: str) -> Callable[[dict], str]:
|
|
|
130
130
|
def definition(live_data: LiveData | dict | None = None) -> str:
|
|
131
131
|
"""The expression function itself"""
|
|
132
132
|
|
|
133
|
-
#
|
|
134
|
-
|
|
133
|
+
# We only work if passed some data to use - also we don't know our name
|
|
134
|
+
# so can't report it.
|
|
135
|
+
|
|
136
|
+
if live_data is None:
|
|
137
|
+
raise DyngleError('Expression called with no argument')
|
|
135
138
|
|
|
136
139
|
# Translate names to underscore-separated instead of hyphen-separated
|
|
137
140
|
# so they work within the Python namespace.
|
|
@@ -140,11 +143,17 @@ def expression(text: str) -> Callable[[dict], str]:
|
|
|
140
143
|
locals = LiveData({k.replace('-', '_'): v for k, v in items})
|
|
141
144
|
|
|
142
145
|
# Create a resolve function which allows references using the hyphen
|
|
143
|
-
# syntax too
|
|
146
|
+
# syntax too - note it relies on the original live_data object (not the
|
|
147
|
+
# locals with the key replacement). We're converting it to LiveData in
|
|
148
|
+
# case for some reason we were passed a raw dict.
|
|
149
|
+
|
|
150
|
+
live_data = LiveData(live_data)
|
|
144
151
|
|
|
145
152
|
def resolve(key):
|
|
146
153
|
return live_data.resolve(key, str_only=False)
|
|
147
|
-
|
|
154
|
+
|
|
155
|
+
# Passing the live_data in again allows function(data) in expressions
|
|
156
|
+
locals = locals | {'resolve': resolve, 'data': live_data}
|
|
148
157
|
|
|
149
158
|
# Perform the Python eval, expanded above
|
|
150
159
|
return _evaluate(text, locals)
|
dyngle/model/operation.py
CHANGED
|
@@ -9,42 +9,84 @@ from dyngle.model.live_data import LiveData
|
|
|
9
9
|
from dyngle.model.template import Template
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
@dataclass
|
|
13
12
|
class Operation:
|
|
13
|
+
"""A named operation defined in configuration. Can be called from a Dyngle
|
|
14
|
+
command (i.e. `dyngle run`) or as a sub-operation."""
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
locals: dict
|
|
16
|
+
all_locals = {}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
def __init__(self, dyngleverse, definition: dict | list, key: str):
|
|
19
|
+
"""
|
|
20
|
+
definition: Either a dict containing steps and local
|
|
21
|
+
expressions/values, or a list containing only steps
|
|
22
|
+
"""
|
|
23
|
+
self.dyngleverse = dyngleverse
|
|
24
|
+
if isinstance(definition, list):
|
|
25
|
+
steps_def = definition
|
|
26
|
+
elif isinstance(definition, dict):
|
|
27
|
+
steps_def = definition.get('steps') or []
|
|
28
|
+
self.all_locals = dyngleverse.parse_constants(definition)
|
|
29
|
+
self.sequence = Sequence(dyngleverse, self, steps_def)
|
|
19
30
|
|
|
20
|
-
def run(self, data: dict,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
def run(self, data: dict | LiveData, args: list):
|
|
32
|
+
"""
|
|
33
|
+
data - The main set of data going into the operation
|
|
34
|
+
|
|
35
|
+
args - Arguments to the operation
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
# The tye of data tells us the run condition - if already a LiveData
|
|
39
|
+
# object then we don't recreate it (i.e. sub-operation)
|
|
25
40
|
|
|
41
|
+
if not isinstance(data, LiveData):
|
|
42
|
+
live_data = LiveData(data) | self.dyngleverse.all_globals
|
|
43
|
+
else:
|
|
44
|
+
live_data = data
|
|
45
|
+
live_data |= self.all_locals | {'args': args}
|
|
46
|
+
self.sequence.run(live_data)
|
|
26
47
|
|
|
27
|
-
STEP_PATTERN = re.compile(
|
|
28
|
-
r'^\s*(?:([\w.-]+)\s+->\s+)?(.+?)(?:\s+=>\s+([\w.-]+))?\s*$')
|
|
29
48
|
|
|
49
|
+
class Sequence:
|
|
50
|
+
"""We allow for the possibility that a sequence of steps might run at other
|
|
51
|
+
levels than the operation itself, for example in a conditional block."""
|
|
30
52
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
raise DyngleError(f"Invalid step markup {{markup}}")
|
|
53
|
+
def __init__(self, dyngleverse, operation: Operation, steps_def: list):
|
|
54
|
+
self.steps = [Step.parse_def(dyngleverse, d) for d in steps_def]
|
|
55
|
+
|
|
56
|
+
def run(self, live_data: LiveData):
|
|
57
|
+
for step in self.steps:
|
|
58
|
+
step.run(live_data)
|
|
38
59
|
|
|
39
60
|
|
|
40
|
-
@dataclass
|
|
41
61
|
class Step:
|
|
42
62
|
|
|
43
|
-
|
|
63
|
+
@staticmethod
|
|
64
|
+
def parse_def(dyngleverse, definition: dict | str):
|
|
65
|
+
for step_type in [CommandStep, SubOperationStep]:
|
|
66
|
+
if step_type.fits(definition):
|
|
67
|
+
return step_type(dyngleverse, definition)
|
|
68
|
+
raise DyngleError(f"Unknown step definition\n{definition}")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# Ideally these would be subclasses in a ClassFamily (or use an ABC)
|
|
72
|
+
|
|
73
|
+
class CommandStep:
|
|
44
74
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
75
|
+
PATTERN = re.compile(
|
|
76
|
+
r'^\s*(?:([\w.-]+)\s+->\s+)?(.+?)(?:\s+=>\s+([\w.-]+))?\s*$')
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def fits(cls, definition: dict | str):
|
|
80
|
+
return isinstance(definition, str)
|
|
81
|
+
|
|
82
|
+
def __init__(self, dyngleverse, markup: str):
|
|
83
|
+
self.markup = markup
|
|
84
|
+
if match := self.PATTERN.match(markup):
|
|
85
|
+
self.input, command_text, self.output = match.groups()
|
|
86
|
+
command_template = shlex.split(command_text.strip())
|
|
87
|
+
self.command_template = command_template
|
|
88
|
+
else:
|
|
89
|
+
raise DyngleError(f"Invalid step markup {{markup}}")
|
|
48
90
|
|
|
49
91
|
def run(self, live_data: LiveData):
|
|
50
92
|
command = [Template(word).render(live_data).strip()
|
|
@@ -60,3 +102,26 @@ class Step:
|
|
|
60
102
|
f'Step failed with code {result.returncode}: {self.markup}')
|
|
61
103
|
if self.output:
|
|
62
104
|
live_data[self.output] = result.stdout.rstrip()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class SubOperationStep:
|
|
108
|
+
"""Instead of calling a system command, call another operation in the same
|
|
109
|
+
Dyngleverse"""
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def fits(cls, definition: dict | str):
|
|
113
|
+
return isinstance(definition, dict) and 'sub' in definition
|
|
114
|
+
|
|
115
|
+
def __init__(self, dyngleverse, definition: dict):
|
|
116
|
+
self.dyngleverse = dyngleverse
|
|
117
|
+
self.operation_key = definition['sub']
|
|
118
|
+
self.args_template = definition.get('args') or ''
|
|
119
|
+
|
|
120
|
+
def run(self, live_data: LiveData):
|
|
121
|
+
# Resolve the operation at runtime, not at init time
|
|
122
|
+
operation = self.dyngleverse.operations.get(self.operation_key)
|
|
123
|
+
if not operation:
|
|
124
|
+
raise DyngleError(f"Unknown operation {self.operation_key}")
|
|
125
|
+
args = [Template(word).render(live_data).strip()
|
|
126
|
+
for word in self.args_template]
|
|
127
|
+
operation.run(live_data, args)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dyngle
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: Run lightweight local workflows
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Steampunk Wizard
|
|
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.14
|
|
13
13
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
14
|
-
Requires-Dist: wizlib (>=3.3.
|
|
14
|
+
Requires-Dist: wizlib (>=3.3.11,<3.4.0)
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
|
|
17
17
|
# Dyngle
|
|
@@ -245,6 +245,45 @@ dyngle:
|
|
|
245
245
|
|
|
246
246
|
If names overlap, data items populated using the data assignment operator take precedence over expressions and data in the original input from the beginning of the Operation.
|
|
247
247
|
|
|
248
|
+
## Sub-operations
|
|
249
|
+
|
|
250
|
+
Operations can call other operations as steps using the `sub:` key. This allows for composability and reuse of operation logic.
|
|
251
|
+
|
|
252
|
+
Basic example:
|
|
253
|
+
|
|
254
|
+
```yaml
|
|
255
|
+
dyngle:
|
|
256
|
+
operations:
|
|
257
|
+
greet:
|
|
258
|
+
- echo "Hello!"
|
|
259
|
+
|
|
260
|
+
greet-twice:
|
|
261
|
+
steps:
|
|
262
|
+
- sub: greet
|
|
263
|
+
- sub: greet
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Sub-operations can accept arguments using the `args:` key. The called operation can access these via the `args` array in expressions:
|
|
267
|
+
|
|
268
|
+
```yaml
|
|
269
|
+
dyngle:
|
|
270
|
+
operations:
|
|
271
|
+
greet-person:
|
|
272
|
+
expressions:
|
|
273
|
+
person: "args[0]"
|
|
274
|
+
steps:
|
|
275
|
+
- echo "Hello, {{person}}!"
|
|
276
|
+
|
|
277
|
+
greet-team:
|
|
278
|
+
steps:
|
|
279
|
+
- sub: greet-person
|
|
280
|
+
args: ['Alice']
|
|
281
|
+
- sub: greet-person
|
|
282
|
+
args: ['Bob']
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Sub-operations share the same Live Data context, so data assignments and expressions from the parent operation are available to the sub-operation, and any data populated by the sub-operation is available to subsequent steps in the parent.
|
|
286
|
+
|
|
248
287
|
## Lifecycle
|
|
249
288
|
|
|
250
289
|
The lifecycle of an operation is:
|
|
@@ -275,4 +314,3 @@ In the event of item name conflicts, expressions and operations are loaded from
|
|
|
275
314
|
|
|
276
315
|
Commands are executed using Python's `subprocess.run()` with arguments split in a shell-like fashion. The shell is not used, which reduces the likelihood of shell injection attacks. However, note that Dyngle is not robust to malicious configuration. Use with caution.
|
|
277
316
|
|
|
278
|
-
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
dyngle/__init__.py,sha256=BxgXnQ_cyEuZiMpkv-zkDCTRs9UP8vZsKX2kWeZj_Ck,2336
|
|
2
|
+
dyngle/__main__.py,sha256=pYRIwzix_AL8CdJaDDis_8yMBBWO2N72NNwkroo1dQo,95
|
|
3
|
+
dyngle/command/__init__.py,sha256=ngNOb_k9COcXOs7It3HoFJRW0hzBDpAzxXcGUy6hhko,95
|
|
4
|
+
dyngle/command/null_command.py,sha256=OX1u0z4zjlquxuV0_yu7uE1_K2Lk523WydJu-0Z82QE,96
|
|
5
|
+
dyngle/command/run_command.py,sha256=YOYuTzR1l2t24G1Z2uLjl1Ya1unvE4lHWpaOopMO1Tg,1441
|
|
6
|
+
dyngle/error.py,sha256=CGcTa8L4O1qsHEYnzp_JBbkvntJTv2Qz46wj_TI8NLk,39
|
|
7
|
+
dyngle/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
dyngle/model/dyngleverse.py,sha256=tFzx4AhPalODknPqbuFcR4G7QF1VOPlAAy2VDPfRmTA,1301
|
|
9
|
+
dyngle/model/expression.py,sha256=XvHlWqnN-4gkN4ck5iTuwP3OqXXbRzTwIRTX0lzJAdY,4889
|
|
10
|
+
dyngle/model/live_data.py,sha256=FxbMjfaiBIUorEbhRx5I0o-WAFFWdjYaqzw_zhFq86w,1251
|
|
11
|
+
dyngle/model/operation.py,sha256=IrLx6iDZ2_D7384qKsjpS7VBrHqTsSmsOWw_lJFWimI,4465
|
|
12
|
+
dyngle/model/safe_path.py,sha256=Hk2AhP6e3yKGh3kKrLLwhvAlMNx-j2jObBYJL-_doAU,3339
|
|
13
|
+
dyngle/model/template.py,sha256=MeXu--ZNtj_ujABU1GjjcQ1Ea_o_M-50LocuXFeOLRE,887
|
|
14
|
+
dyngle-1.5.1.dist-info/METADATA,sha256=kdyZXIVC7aEXcVvN9gMLweEfpqvh3nlkB2LVSGX-QmQ,10681
|
|
15
|
+
dyngle-1.5.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
16
|
+
dyngle-1.5.1.dist-info/entry_points.txt,sha256=rekiGhtweiHKm9g1jdGb3FhzqDrk1kigJDeSNollZSA,48
|
|
17
|
+
dyngle-1.5.1.dist-info/RECORD,,
|
dyngle-1.3.0.dist-info/RECORD
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
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=FxbMjfaiBIUorEbhRx5I0o-WAFFWdjYaqzw_zhFq86w,1251
|
|
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.3.0.dist-info/METADATA,sha256=LcfQLPcClIK9_TOWRUHGJ4nt7GN8SMtvqkQSqxDQaFg,9710
|
|
13
|
-
dyngle-1.3.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
14
|
-
dyngle-1.3.0.dist-info/entry_points.txt,sha256=rekiGhtweiHKm9g1jdGb3FhzqDrk1kigJDeSNollZSA,48
|
|
15
|
-
dyngle-1.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|