ato 2.0.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.
- ato/__init__.py +1 -0
- ato/adict.py +582 -0
- ato/db_routers/__init__.py +8 -0
- ato/db_routers/sql/__init__.py +0 -0
- ato/db_routers/sql/manager.py +188 -0
- ato/db_routers/sql/schema.py +83 -0
- ato/hyperopt/__init__.py +0 -0
- ato/hyperopt/base.py +144 -0
- ato/hyperopt/hyperband.py +103 -0
- ato/parser.py +103 -0
- ato/scope.py +492 -0
- ato/utils.py +55 -0
- ato/xyz.py +234 -0
- ato-2.0.4.dist-info/METADATA +978 -0
- ato-2.0.4.dist-info/RECORD +18 -0
- ato-2.0.4.dist-info/WHEEL +5 -0
- ato-2.0.4.dist-info/licenses/LICENSE +21 -0
- ato-2.0.4.dist-info/top_level.txt +1 -0
ato/scope.py
ADDED
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import hashlib
|
|
3
|
+
import inspect
|
|
4
|
+
import pickle
|
|
5
|
+
import sys
|
|
6
|
+
import uuid
|
|
7
|
+
import warnings
|
|
8
|
+
from contextlib import contextmanager
|
|
9
|
+
from functools import wraps
|
|
10
|
+
|
|
11
|
+
from ato.adict import ADict
|
|
12
|
+
from inspect import currentframe, getframeinfo
|
|
13
|
+
|
|
14
|
+
from ato.parser import parse_command
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# safe compile
|
|
18
|
+
def exec_with_no_permissions(code, __locals):
|
|
19
|
+
exec(compile(code, '<string>', 'single'), {'__builtins__': None}, __locals)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def parse_args_pythonic():
|
|
23
|
+
if Scope.stored_arguments is not None:
|
|
24
|
+
_pythonic_vars = Scope.stored_arguments
|
|
25
|
+
else:
|
|
26
|
+
_pythonic_vars = sys.argv[1:]
|
|
27
|
+
joined = ' '.join(_pythonic_vars)
|
|
28
|
+
_pythonic_vars = parse_command(joined)
|
|
29
|
+
pythonic_vars = []
|
|
30
|
+
for literal in _pythonic_vars:
|
|
31
|
+
if '=' not in literal:
|
|
32
|
+
pythonic_vars.extend(literal.split())
|
|
33
|
+
else:
|
|
34
|
+
name, *values = literal.split('=')
|
|
35
|
+
value = '='.join(values)
|
|
36
|
+
if value.startswith('%') and value.endswith('%'):
|
|
37
|
+
value = f'"{value[1:-1]}"'.replace('%', '\"')
|
|
38
|
+
pythonic_vars.append(f'{name}={value}')
|
|
39
|
+
default_prefix = ''
|
|
40
|
+
if len(Scope.registry) == 1:
|
|
41
|
+
scope_name = list(Scope.registry.keys())[0]
|
|
42
|
+
default_prefix += f'{scope_name}.'
|
|
43
|
+
for literal in pythonic_vars:
|
|
44
|
+
literal = default_prefix+literal
|
|
45
|
+
scope_name = literal.split('.')[0]
|
|
46
|
+
scope = Scope.registry.get(scope_name)
|
|
47
|
+
if scope is not None:
|
|
48
|
+
literal = literal[len(f'{scope_name}.'):]
|
|
49
|
+
if literal in scope.views or '=' in literal:
|
|
50
|
+
scope.assign(literal)
|
|
51
|
+
Scope.parsed = True
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _add_func_to_scope(scope, func, field=None, priority=0, lazy=False, default=False, chain_with=None):
|
|
55
|
+
field = field or func.__name__
|
|
56
|
+
chain_with = chain_with or []
|
|
57
|
+
if isinstance(chain_with, str):
|
|
58
|
+
chain_with = [chain_with]
|
|
59
|
+
scope.views[field] = {
|
|
60
|
+
"view_type": 'function',
|
|
61
|
+
"priority": priority,
|
|
62
|
+
"lazy": lazy,
|
|
63
|
+
"fn": func,
|
|
64
|
+
"chain_with": chain_with,
|
|
65
|
+
"default": default
|
|
66
|
+
}
|
|
67
|
+
if default:
|
|
68
|
+
scope.assign(field)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def add_func_to_scope(scope, field=None, priority=0, lazy=False, default=False, chain_with=None):
|
|
72
|
+
def decorator(func):
|
|
73
|
+
_add_func_to_scope(scope, func, field, priority, lazy, default, chain_with)
|
|
74
|
+
return func
|
|
75
|
+
return decorator
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def add_config_to_scope(scope, field=None, config=None, priority=0, lazy=False, default=False, chain_with=None):
|
|
79
|
+
if field is None:
|
|
80
|
+
raise ValueError(f'A name of config must be specified to assign config directly.')
|
|
81
|
+
config = config or ADict()
|
|
82
|
+
view = ADict()
|
|
83
|
+
view.view_type = 'config'
|
|
84
|
+
view.config = config
|
|
85
|
+
view.priority = priority
|
|
86
|
+
view.lazy = lazy
|
|
87
|
+
chain_with = chain_with or []
|
|
88
|
+
if isinstance(chain_with, str):
|
|
89
|
+
chain_with = [chain_with]
|
|
90
|
+
view.chain_with = chain_with
|
|
91
|
+
view.default = default
|
|
92
|
+
scope.views[field] = view
|
|
93
|
+
if default:
|
|
94
|
+
scope.assign(field)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def add_func_to_multi_scope(scopes, field=None, priority=0, lazy=False, default=False, chain_with=None):
|
|
98
|
+
def decorator(func):
|
|
99
|
+
for scope in scopes:
|
|
100
|
+
_add_func_to_scope(scope, func, field, priority, lazy, default, chain_with)
|
|
101
|
+
return func
|
|
102
|
+
return decorator
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def add_config_to_multi_scope(scopes, field=None, config=None, priority=0, lazy=False, default=False, chain_with=None):
|
|
106
|
+
for scope in scopes:
|
|
107
|
+
add_config_to_scope(scope, field, config, priority, lazy, default, chain_with)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def patch_parsing_method(func, unknown_external_literals='error'):
|
|
111
|
+
modes = {'merge', 'ignore', 'error'}
|
|
112
|
+
if unknown_external_literals not in {'merge', 'ignore', 'error'}:
|
|
113
|
+
raise ValueError(
|
|
114
|
+
f'Unexpected unknown_external_literals="{unknown_external_literals}"; '
|
|
115
|
+
f'Choose the one from {modes}.'
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
@wraps(func)
|
|
119
|
+
def capture(*args, **kwargs):
|
|
120
|
+
parser = args[0]
|
|
121
|
+
if len(sys.argv) >= 2:
|
|
122
|
+
if sys.argv[1] in ('--help', '-h'):
|
|
123
|
+
warnings.warn(f'Scope does not support "--help" option. Use "manual" instead.', DeprecationWarning)
|
|
124
|
+
if sys.argv[1] in ('--help', '-h', 'manual'):
|
|
125
|
+
print('[External Parser]')
|
|
126
|
+
parser.print_help()
|
|
127
|
+
Scope.logging_manual()
|
|
128
|
+
sys.exit(0)
|
|
129
|
+
known, unknown = func(*args, **kwargs)
|
|
130
|
+
defaults = vars(func(args[0], [])[0])
|
|
131
|
+
non_defaults = ADict(vars(known)).clone()
|
|
132
|
+
non_defaults.filter(lambda k, v: k not in defaults or v != defaults[k])
|
|
133
|
+
stored_arguments = []
|
|
134
|
+
while unknown:
|
|
135
|
+
literal = unknown.pop(0)
|
|
136
|
+
if literal.startswith('--'):
|
|
137
|
+
if unknown_external_literals == 'error':
|
|
138
|
+
raise RuntimeError(f'Unexpected external literal: {literal}')
|
|
139
|
+
value = unknown.pop(0)
|
|
140
|
+
key = literal[2:].replace('-', '_')
|
|
141
|
+
if unknown_external_literals == 'merge':
|
|
142
|
+
exec_with_no_permissions(
|
|
143
|
+
compile(f'non_defaults["{key}"] = {value}', '<string>', 'single'),
|
|
144
|
+
__locals={'non_defaults': non_defaults}
|
|
145
|
+
)
|
|
146
|
+
else:
|
|
147
|
+
stored_arguments.append(literal)
|
|
148
|
+
Scope.stored_arguments = stored_arguments
|
|
149
|
+
for scope in Scope.registry.values():
|
|
150
|
+
if scope.use_external_parser:
|
|
151
|
+
scope.observe('_argparse', defaults, scope.external_priority, lazy=False)
|
|
152
|
+
scope.assign('_argparse')
|
|
153
|
+
scope.observe('_argparse_literals', non_defaults, scope.external_priority, lazy=True)
|
|
154
|
+
scope.assign('_argparse_literals')
|
|
155
|
+
parse_args_pythonic()
|
|
156
|
+
release()
|
|
157
|
+
return known, unknown
|
|
158
|
+
|
|
159
|
+
return capture
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def release():
|
|
163
|
+
if hasattr(_parser, 'stored_methods'):
|
|
164
|
+
_parser.parse_args, _parser.parse_known_args = _parser.stored_methods
|
|
165
|
+
del _parser.stored_methods
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
_parser = argparse.ArgumentParser
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _print_config(config):
|
|
172
|
+
print(config.to_xyz())
|
|
173
|
+
sys.exit(0)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _get_func_trace_id(func):
|
|
177
|
+
return f'{func.__module__}.{func.__qualname__}'
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _generate_func_fingerprint(func, trace_id=None):
|
|
181
|
+
code_obj = func.__code__
|
|
182
|
+
code_info = (
|
|
183
|
+
code_obj.co_code,
|
|
184
|
+
code_obj.co_consts,
|
|
185
|
+
code_obj.co_names,
|
|
186
|
+
code_obj.co_varnames,
|
|
187
|
+
code_obj.co_filename,
|
|
188
|
+
code_obj.co_name,
|
|
189
|
+
code_obj.co_firstlineno
|
|
190
|
+
)
|
|
191
|
+
trace_id = _get_func_trace_id(func) if trace_id is None else trace_id
|
|
192
|
+
code_hash = hashlib.sha256(repr(code_info).encode()).hexdigest()
|
|
193
|
+
return ADict(**{trace_id: code_hash})
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class Scope:
|
|
197
|
+
registry = ADict()
|
|
198
|
+
parsed = False
|
|
199
|
+
stored_arguments = None
|
|
200
|
+
current_scope = None
|
|
201
|
+
unknown_external_literals = 'ignore'
|
|
202
|
+
|
|
203
|
+
def __init__(
|
|
204
|
+
self,
|
|
205
|
+
config=None,
|
|
206
|
+
name='config',
|
|
207
|
+
use_external_parser=False,
|
|
208
|
+
external_priority=-2,
|
|
209
|
+
enable_override=False
|
|
210
|
+
):
|
|
211
|
+
self.config = ADict() if config is None else config
|
|
212
|
+
self.name = name
|
|
213
|
+
self.use_external_parser = use_external_parser
|
|
214
|
+
self.enable_override = enable_override
|
|
215
|
+
self.register()
|
|
216
|
+
self.views = ADict()
|
|
217
|
+
self.manuals = ADict()
|
|
218
|
+
self.observe('_default', config, priority=-1, lazy=False)
|
|
219
|
+
add_func_to_scope(self, 'print', priority=1280, lazy=True, default=False)(_print_config)
|
|
220
|
+
self.screen = ADict(views=[], literals=[], lazy_views=[])
|
|
221
|
+
self.external_priority = external_priority
|
|
222
|
+
self.compute = False
|
|
223
|
+
self.config_in_compute = None
|
|
224
|
+
self.mode = 'ON'
|
|
225
|
+
self.is_applied = False
|
|
226
|
+
self._traced_data = ADict(fingerprints=ADict())
|
|
227
|
+
|
|
228
|
+
def activate(self):
|
|
229
|
+
self.mode = 'ON'
|
|
230
|
+
|
|
231
|
+
def deactivate(self):
|
|
232
|
+
self.mode = 'OFF'
|
|
233
|
+
|
|
234
|
+
@contextmanager
|
|
235
|
+
def pause(self):
|
|
236
|
+
self.deactivate()
|
|
237
|
+
yield
|
|
238
|
+
self.activate()
|
|
239
|
+
|
|
240
|
+
def trace(self, trace_id=None):
|
|
241
|
+
def decorator(func):
|
|
242
|
+
self._traced_data.fingerprints.update(_generate_func_fingerprint(func, trace_id=trace_id))
|
|
243
|
+
return self(func)
|
|
244
|
+
return decorator
|
|
245
|
+
|
|
246
|
+
def runtime_trace(self, init_fn=None, inspect_fn=None, trace_id=None):
|
|
247
|
+
def decorator(func):
|
|
248
|
+
def inner(*args, **kwargs):
|
|
249
|
+
nonlocal trace_id
|
|
250
|
+
if init_fn is not None:
|
|
251
|
+
init_fn()
|
|
252
|
+
results = inspect_results = self(func)(*args, **kwargs)
|
|
253
|
+
if inspect_fn is not None:
|
|
254
|
+
inspect_results = inspect_fn(results)
|
|
255
|
+
trace_id = _get_func_trace_id(func) if trace_id is not None else trace_id
|
|
256
|
+
inspect_hash = hashlib.sha256(pickle.dumps(inspect_results)).hexdigest()
|
|
257
|
+
self._traced_data.fingerprints.update({trace_id: inspect_hash})
|
|
258
|
+
return inner
|
|
259
|
+
return decorator
|
|
260
|
+
|
|
261
|
+
def register(self):
|
|
262
|
+
registry = self.__class__.registry
|
|
263
|
+
if len(registry) == 0:
|
|
264
|
+
_parser.stored_methods = [_parser.parse_args, _parser.parse_known_args]
|
|
265
|
+
_parser.parse_args = _parser.parse_known_args = patch_parsing_method(
|
|
266
|
+
_parser.parse_known_args,
|
|
267
|
+
self.__class__.unknown_external_literals
|
|
268
|
+
)
|
|
269
|
+
if self.name in registry and not self.enable_override:
|
|
270
|
+
raise ValueError(
|
|
271
|
+
f'{self.name} is already used by another scope. '
|
|
272
|
+
f'The name of scope must not be duplicated.'
|
|
273
|
+
)
|
|
274
|
+
self.__class__.registry[self.name] = self
|
|
275
|
+
|
|
276
|
+
@classmethod
|
|
277
|
+
def initialize_registry(cls):
|
|
278
|
+
cls.registry.clear()
|
|
279
|
+
|
|
280
|
+
@classmethod
|
|
281
|
+
def override(cls, scope):
|
|
282
|
+
cls.registry[scope.name] = scope
|
|
283
|
+
|
|
284
|
+
def add_to_screen(self, field=None, config=None, priority=0, lazy=False, default=False, chain_with=None):
|
|
285
|
+
if config is not None:
|
|
286
|
+
add_config_to_scope(self, field, config, priority, lazy, default, chain_with)
|
|
287
|
+
else:
|
|
288
|
+
return add_func_to_scope(self, field, priority, lazy, default, chain_with)
|
|
289
|
+
|
|
290
|
+
def observe(self, field=None, config=None, priority=0, lazy=False, default=False, chain_with=None):
|
|
291
|
+
# to enable replace from external codes
|
|
292
|
+
return self.__class__.registry[self.name].add_to_screen(field, config, priority, lazy, default, chain_with)
|
|
293
|
+
|
|
294
|
+
def manual(self, field=None, manual=None):
|
|
295
|
+
if manual is not None:
|
|
296
|
+
self.manuals.update(manual)
|
|
297
|
+
else:
|
|
298
|
+
field(self.manuals)
|
|
299
|
+
return field
|
|
300
|
+
|
|
301
|
+
@classmethod
|
|
302
|
+
def logging_manual(cls):
|
|
303
|
+
for scope_name, scope in cls.registry.items():
|
|
304
|
+
print('-'*50)
|
|
305
|
+
print(f'[Scope "{scope_name}"]')
|
|
306
|
+
print('(The Applying Order of Views)')
|
|
307
|
+
view_names = list([key for key, view in scope.views.items() if not view.lazy])
|
|
308
|
+
lazy_view_names = list([key for key, view in scope.views.items() if view.lazy])
|
|
309
|
+
view_names.sort(key=lambda x: scope.views[x].priority)
|
|
310
|
+
lazy_view_names.sort(key=lambda x: scope.views[x].priority)
|
|
311
|
+
print(' → '.join(view_names+['(CLI Inputs)']+lazy_view_names))
|
|
312
|
+
print('(User Manuals)')
|
|
313
|
+
manuals = scope.manuals
|
|
314
|
+
if len(cls.registry) > 1:
|
|
315
|
+
manuals = manuals.clone()
|
|
316
|
+
for key, value in scope.manuals.items():
|
|
317
|
+
manuals[f'{scope.name}.{key}'] = manuals.pop(key)
|
|
318
|
+
print(manuals.to_xyz())
|
|
319
|
+
print('-'*50)
|
|
320
|
+
sys.exit(0)
|
|
321
|
+
|
|
322
|
+
def get_assigned_views(self):
|
|
323
|
+
default_views = [view for view in self.screen.views if self.views[view].default]
|
|
324
|
+
views = [view for view in self.screen.views if view not in default_views]
|
|
325
|
+
default_lazy_views = [lazy_view for lazy_view in self.screen.lazy_views if self.views[lazy_view].default]
|
|
326
|
+
lazy_views = [lazy_view for lazy_view in self.screen.lazy_views if lazy_view not in default_lazy_views]
|
|
327
|
+
return ADict(
|
|
328
|
+
default_views=default_views,
|
|
329
|
+
default_lazy_views=default_lazy_views,
|
|
330
|
+
views=views,
|
|
331
|
+
lazy_views=lazy_views,
|
|
332
|
+
literals=self.screen.literals
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
def assign(self, literals):
|
|
336
|
+
if not isinstance(literals, (list, tuple)) or isinstance(literals, str):
|
|
337
|
+
literals = [literals]
|
|
338
|
+
for literal in literals:
|
|
339
|
+
if literal in self.views:
|
|
340
|
+
view_info = self.views[literal]
|
|
341
|
+
if view_info.lazy and literal not in self.screen.lazy_views:
|
|
342
|
+
if view_info.chain_with is not None:
|
|
343
|
+
self.assign(view_info.chain_with)
|
|
344
|
+
self.screen.lazy_views.append(literal)
|
|
345
|
+
elif not view_info.lazy and literal not in self.screen.views:
|
|
346
|
+
if view_info.chain_with is not None:
|
|
347
|
+
self.assign(view_info.chain_with)
|
|
348
|
+
self.screen.views.append(literal)
|
|
349
|
+
else:
|
|
350
|
+
self.screen.literals.append(literal)
|
|
351
|
+
|
|
352
|
+
def apply(self):
|
|
353
|
+
if len(sys.argv) >= 2:
|
|
354
|
+
if sys.argv[1] in ('--help', '-h'):
|
|
355
|
+
warnings.warn(f'Scope does not support "--help" option. Use "manual" instead.', DeprecationWarning)
|
|
356
|
+
if sys.argv[1] in ('--help', '-h', 'manual'):
|
|
357
|
+
Scope.logging_manual()
|
|
358
|
+
self.__class__.current_scope = self
|
|
359
|
+
self.screen.views.sort(key=lambda x: self.views[x].priority)
|
|
360
|
+
self.screen.lazy_views.sort(key=lambda x: self.views[x].priority)
|
|
361
|
+
for field in self.screen.views:
|
|
362
|
+
view = self.views[field]
|
|
363
|
+
if view.view_type == 'config':
|
|
364
|
+
self.config.update(view.config)
|
|
365
|
+
else:
|
|
366
|
+
view.fn(self.config)
|
|
367
|
+
for literal in self.screen.literals:
|
|
368
|
+
if isinstance(literal, str):
|
|
369
|
+
exec_with_no_permissions(f'config.{literal}', __locals={'config': self.config})
|
|
370
|
+
else:
|
|
371
|
+
self.config.update(literal)
|
|
372
|
+
self.compute = True
|
|
373
|
+
self.config.freeze()
|
|
374
|
+
for field in self.screen.views:
|
|
375
|
+
view = self.views[field]
|
|
376
|
+
if view.view_type != 'config':
|
|
377
|
+
view.fn(self.config)
|
|
378
|
+
self.compute = False
|
|
379
|
+
self.config.defrost()
|
|
380
|
+
for field in self.screen.lazy_views:
|
|
381
|
+
view = self.views[field]
|
|
382
|
+
if view.view_type == 'config':
|
|
383
|
+
self.config.update(view.config)
|
|
384
|
+
else:
|
|
385
|
+
view.fn(self.config)
|
|
386
|
+
self.is_applied = True
|
|
387
|
+
|
|
388
|
+
def __enter__(self):
|
|
389
|
+
if not Scope.parsed:
|
|
390
|
+
parse_args_pythonic()
|
|
391
|
+
if not self.is_applied:
|
|
392
|
+
self.apply()
|
|
393
|
+
|
|
394
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
395
|
+
pass
|
|
396
|
+
|
|
397
|
+
def _recreate_context(self):
|
|
398
|
+
return self
|
|
399
|
+
|
|
400
|
+
def _is_config_at_positional(self, func, *args, **kwargs):
|
|
401
|
+
if self.name in kwargs:
|
|
402
|
+
return True
|
|
403
|
+
full_arguments = inspect.getfullargspec(func)[0]
|
|
404
|
+
index = full_arguments.index(self.name)
|
|
405
|
+
return {'positional': index+1 < len(args) or len(full_arguments) > len(args), 'index': index}
|
|
406
|
+
|
|
407
|
+
def get_config_updated_arguments(self, func, *args, **kwargs):
|
|
408
|
+
pos_info = self._is_config_at_positional(func, *args, **kwargs)
|
|
409
|
+
if pos_info['positional']:
|
|
410
|
+
args = list(args)
|
|
411
|
+
args.insert(pos_info['index'], self.config)
|
|
412
|
+
else:
|
|
413
|
+
kwargs.update({self.name: self.config})
|
|
414
|
+
return args, kwargs
|
|
415
|
+
|
|
416
|
+
def exec(self, func):
|
|
417
|
+
@wraps(func)
|
|
418
|
+
def inner(*args, **kwargs):
|
|
419
|
+
with self._recreate_context():
|
|
420
|
+
if self.mode == 'ON':
|
|
421
|
+
args, kwargs = self.get_config_updated_arguments(func, *args, **kwargs)
|
|
422
|
+
return func(*args, **kwargs)
|
|
423
|
+
return inner
|
|
424
|
+
|
|
425
|
+
def __call__(self, func):
|
|
426
|
+
return self.exec(func)
|
|
427
|
+
|
|
428
|
+
def reset_user_inputs(self):
|
|
429
|
+
self.screen = ADict(views=[], literals=[], lazy_views=[])
|
|
430
|
+
|
|
431
|
+
def convert_argparse_to_scope(self):
|
|
432
|
+
args = self.views['_argparse'].config
|
|
433
|
+
code = f"def argparse({self.name}):\n"
|
|
434
|
+
code += '\n'.join([
|
|
435
|
+
f' {self.name}.{key} = '+(f"'{value}'" if isinstance(value, str) else f'{value}')
|
|
436
|
+
for key, value in args.items()
|
|
437
|
+
])
|
|
438
|
+
return code
|
|
439
|
+
|
|
440
|
+
@classmethod
|
|
441
|
+
@contextmanager
|
|
442
|
+
def lazy(cls, with_compile=False, priority=1):
|
|
443
|
+
scope = cls.current_scope
|
|
444
|
+
if scope.compute and not with_compile:
|
|
445
|
+
scope.config.defrost()
|
|
446
|
+
yield
|
|
447
|
+
scope.config.freeze()
|
|
448
|
+
else:
|
|
449
|
+
scope.config.freeze()
|
|
450
|
+
try:
|
|
451
|
+
yield
|
|
452
|
+
except (KeyError, AttributeError):
|
|
453
|
+
pass
|
|
454
|
+
scope.config.defrost()
|
|
455
|
+
if with_compile and not scope.compute:
|
|
456
|
+
frame = currentframe().f_back.f_back
|
|
457
|
+
frame_info = getframeinfo(frame)
|
|
458
|
+
file_name = frame_info.filename
|
|
459
|
+
start = frame_info.positions.lineno
|
|
460
|
+
end = frame_info.positions.end_lineno
|
|
461
|
+
with open(file_name, 'r') as f:
|
|
462
|
+
inner_ctx_lines = list(f.readlines())[start:end]
|
|
463
|
+
ctx_name = f"_lazy_context_{str(uuid.uuid4()).replace('-', '_')}"
|
|
464
|
+
inner_ctx_lines = [f'def {ctx_name}({scope.name}):']+inner_ctx_lines
|
|
465
|
+
global_vars = frame.f_globals
|
|
466
|
+
local_vars = frame.f_locals
|
|
467
|
+
exec(compile('\n'.join(inner_ctx_lines), '<string>', 'exec'), global_vars, local_vars)
|
|
468
|
+
scope.observe(default=True, lazy=True, priority=priority)(local_vars[ctx_name])
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
class MultiScope:
|
|
472
|
+
def __init__(self, *scopes):
|
|
473
|
+
self.scopes = scopes
|
|
474
|
+
self.register_all()
|
|
475
|
+
|
|
476
|
+
def register_all(self):
|
|
477
|
+
Scope.registry.clear()
|
|
478
|
+
for scope in self.scopes:
|
|
479
|
+
Scope.registry[scope.name] = scope
|
|
480
|
+
|
|
481
|
+
def __call__(self, func):
|
|
482
|
+
def decorator(*args, **kwargs):
|
|
483
|
+
# if not Scope.parsed:
|
|
484
|
+
parse_args_pythonic()
|
|
485
|
+
arguments = inspect.getfullargspec(func)
|
|
486
|
+
name_spaces = set(arguments.args+arguments.kwonlyargs)
|
|
487
|
+
for scope in self.scopes:
|
|
488
|
+
if scope.name in name_spaces or arguments.varkw is not None:
|
|
489
|
+
args, kwargs = scope.get_config_updated_arguments(func, *args, **kwargs)
|
|
490
|
+
scope.apply()
|
|
491
|
+
return func(*args, **kwargs)
|
|
492
|
+
return decorator
|
ato/utils.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from typing import Iterable, Union, Sequence, Optional, Dict
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def is_seq(x):
|
|
5
|
+
return isinstance(x, Iterable) and not isinstance(x, str)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_all(iterable, key):
|
|
9
|
+
return map(lambda x: x[key], iterable)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _to_ord(s):
|
|
13
|
+
if s is not None and len(s) >= 1:
|
|
14
|
+
return ord(s)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def replace_all(
|
|
18
|
+
string: str,
|
|
19
|
+
sources: Union[Sequence[str], str],
|
|
20
|
+
mappings: Optional[Union[Dict[str, str], Sequence[str], str]] = None
|
|
21
|
+
):
|
|
22
|
+
if mappings is None:
|
|
23
|
+
mappings = {}
|
|
24
|
+
elif not isinstance(mappings, dict):
|
|
25
|
+
assert len(sources) == len(mappings), 'sources and mappings must have same length.'
|
|
26
|
+
mappings = {source: target for source, target in zip(sources, mappings)}
|
|
27
|
+
mappings = {ord(source): _to_ord(mappings.get(source, None)) for source in sources}
|
|
28
|
+
return string.translate(mappings)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def remove_all(string, targets):
|
|
32
|
+
for target in targets:
|
|
33
|
+
string = string.replace(target, '')
|
|
34
|
+
return string
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def convert_string_to_value(value):
|
|
38
|
+
if not isinstance(value, str):
|
|
39
|
+
return value
|
|
40
|
+
if value.lower() == 'none':
|
|
41
|
+
return None
|
|
42
|
+
elif value.lower() == 'true':
|
|
43
|
+
return True
|
|
44
|
+
elif value.lower() == 'false':
|
|
45
|
+
return False
|
|
46
|
+
elif value == '[Empty Sequence]':
|
|
47
|
+
return []
|
|
48
|
+
elif value == '[Empty Mapping]':
|
|
49
|
+
return dict()
|
|
50
|
+
elif value.isdecimal():
|
|
51
|
+
return int(value)
|
|
52
|
+
elif remove_all(value.lower(), ('.', 'e+', 'e-')).isnumeric():
|
|
53
|
+
return float(value)
|
|
54
|
+
else:
|
|
55
|
+
return value
|