siliconcompiler 0.34.1__py3-none-any.whl → 0.34.2__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.
- siliconcompiler/__init__.py +14 -2
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/sc_show.py +1 -1
- siliconcompiler/constraints/__init__.py +17 -0
- siliconcompiler/constraints/asic_component.py +378 -0
- siliconcompiler/constraints/asic_floorplan.py +449 -0
- siliconcompiler/constraints/asic_pins.py +489 -0
- siliconcompiler/constraints/asic_timing.py +517 -0
- siliconcompiler/core.py +3 -3
- siliconcompiler/dependencyschema.py +10 -174
- siliconcompiler/design.py +235 -118
- siliconcompiler/flowgraph.py +27 -14
- siliconcompiler/library.py +133 -0
- siliconcompiler/metric.py +94 -72
- siliconcompiler/metrics/__init__.py +7 -0
- siliconcompiler/metrics/asic.py +245 -0
- siliconcompiler/metrics/fpga.py +220 -0
- siliconcompiler/package/__init__.py +138 -35
- siliconcompiler/package/github.py +6 -10
- siliconcompiler/packageschema.py +256 -12
- siliconcompiler/pathschema.py +226 -0
- siliconcompiler/project.py +459 -0
- siliconcompiler/scheduler/docker.py +2 -3
- siliconcompiler/scheduler/run_node.py +2 -1
- siliconcompiler/scheduler/scheduler.py +4 -13
- siliconcompiler/scheduler/schedulernode.py +25 -17
- siliconcompiler/scheduler/taskscheduler.py +2 -1
- siliconcompiler/schema/__init__.py +0 -2
- siliconcompiler/schema/baseschema.py +147 -24
- siliconcompiler/schema/editableschema.py +14 -6
- siliconcompiler/schema/journal.py +23 -15
- siliconcompiler/schema/namedschema.py +6 -4
- siliconcompiler/schema/parameter.py +34 -19
- siliconcompiler/schema/parametertype.py +2 -0
- siliconcompiler/schema/parametervalue.py +198 -15
- siliconcompiler/schema/schema_cfg.py +18 -14
- siliconcompiler/schema_obj.py +5 -3
- siliconcompiler/tool.py +199 -10
- siliconcompiler/toolscripts/_tools.json +4 -4
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/METADATA +3 -3
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/RECORD +45 -35
- siliconcompiler/schema/packageschema.py +0 -101
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/entry_points.txt +0 -0
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/licenses/LICENSE +0 -0
- {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/top_level.txt +0 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# SC dependencies outside of its directory, since it may be used by tool drivers
|
|
5
5
|
# that have isolated Python environments.
|
|
6
6
|
|
|
7
|
+
import contextlib
|
|
7
8
|
import copy
|
|
8
9
|
|
|
9
10
|
try:
|
|
@@ -21,7 +22,7 @@ except ModuleNotFoundError:
|
|
|
21
22
|
|
|
22
23
|
import os.path
|
|
23
24
|
|
|
24
|
-
from .parameter import Parameter
|
|
25
|
+
from .parameter import Parameter, NodeValue
|
|
25
26
|
from .journal import Journal
|
|
26
27
|
|
|
27
28
|
|
|
@@ -36,6 +37,17 @@ class BaseSchema:
|
|
|
36
37
|
self.__default = None
|
|
37
38
|
self.__journal = Journal()
|
|
38
39
|
self.__parent = self
|
|
40
|
+
self.__active = None
|
|
41
|
+
self.__key = None
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def _keypath(self):
|
|
45
|
+
'''
|
|
46
|
+
Returns the key to the current section of the schema
|
|
47
|
+
'''
|
|
48
|
+
if self.__parent is self:
|
|
49
|
+
return tuple()
|
|
50
|
+
return tuple([*self.__parent._keypath, self.__key])
|
|
39
51
|
|
|
40
52
|
def _from_dict(self, manifest, keypath, version=None):
|
|
41
53
|
'''
|
|
@@ -105,6 +117,9 @@ class BaseSchema:
|
|
|
105
117
|
return gzip.open(filepath, mode="rt" if is_read else "wt", encoding="utf-8")
|
|
106
118
|
return open(filepath, mode="r" if is_read else "w", encoding="utf-8")
|
|
107
119
|
|
|
120
|
+
def __format_key(self, *key):
|
|
121
|
+
return f"[{','.join([*self._keypath, *key])}]"
|
|
122
|
+
|
|
108
123
|
def read_manifest(self, filepath):
|
|
109
124
|
"""
|
|
110
125
|
Reads a manifest from disk and replaces the current data with the data in the file.
|
|
@@ -216,21 +231,23 @@ class BaseSchema:
|
|
|
216
231
|
|
|
217
232
|
try:
|
|
218
233
|
require_leaf = True
|
|
234
|
+
insert_defaults = False
|
|
219
235
|
if field == 'schema':
|
|
220
236
|
require_leaf = False
|
|
237
|
+
insert_defaults = True
|
|
221
238
|
param = self.__search(
|
|
222
239
|
*keypath,
|
|
223
|
-
insert_defaults=
|
|
240
|
+
insert_defaults=insert_defaults,
|
|
224
241
|
use_default=True,
|
|
225
242
|
require_leaf=require_leaf)
|
|
226
243
|
if field == 'schema':
|
|
227
244
|
if isinstance(param, Parameter):
|
|
228
|
-
raise ValueError(f"
|
|
245
|
+
raise ValueError(f"{self.__format_key(*keypath)} is a complete keypath")
|
|
229
246
|
self.__journal.record("get", keypath, field=field, step=step, index=index)
|
|
230
247
|
param.__journal = self.__journal.get_child(*keypath)
|
|
231
248
|
return param
|
|
232
249
|
except KeyError:
|
|
233
|
-
raise KeyError(f"
|
|
250
|
+
raise KeyError(f"{self.__format_key(*keypath)} is not a valid keypath")
|
|
234
251
|
if field is None:
|
|
235
252
|
return param
|
|
236
253
|
|
|
@@ -239,7 +256,7 @@ class BaseSchema:
|
|
|
239
256
|
self.__journal.record("get", keypath, field=field, step=step, index=index)
|
|
240
257
|
return get_ret
|
|
241
258
|
except Exception as e:
|
|
242
|
-
new_msg = f"error while accessing
|
|
259
|
+
new_msg = f"error while accessing {self.__format_key(*keypath)}: {e.args[0]}"
|
|
243
260
|
e.args = (new_msg, *e.args[1:])
|
|
244
261
|
raise e
|
|
245
262
|
|
|
@@ -273,7 +290,7 @@ class BaseSchema:
|
|
|
273
290
|
try:
|
|
274
291
|
param = self.__search(*keypath, insert_defaults=True)
|
|
275
292
|
except KeyError:
|
|
276
|
-
raise KeyError(f"
|
|
293
|
+
raise KeyError(f"{self.__format_key(*keypath)} is not a valid keypath")
|
|
277
294
|
|
|
278
295
|
try:
|
|
279
296
|
set_ret = param.set(value, field=field, clobber=clobber,
|
|
@@ -281,9 +298,10 @@ class BaseSchema:
|
|
|
281
298
|
if set_ret:
|
|
282
299
|
self.__journal.record("set", keypath, value=value, field=field,
|
|
283
300
|
step=step, index=index)
|
|
301
|
+
self.__process_active(param, set_ret)
|
|
284
302
|
return set_ret
|
|
285
303
|
except Exception as e:
|
|
286
|
-
new_msg = f"error while setting
|
|
304
|
+
new_msg = f"error while setting {self.__format_key(*keypath)}: {e.args[0]}"
|
|
287
305
|
e.args = (new_msg, *e.args[1:])
|
|
288
306
|
raise e
|
|
289
307
|
|
|
@@ -316,16 +334,17 @@ class BaseSchema:
|
|
|
316
334
|
try:
|
|
317
335
|
param = self.__search(*keypath, insert_defaults=True)
|
|
318
336
|
except KeyError:
|
|
319
|
-
raise KeyError(f"
|
|
337
|
+
raise KeyError(f"{self.__format_key(*keypath)} is not a valid keypath")
|
|
320
338
|
|
|
321
339
|
try:
|
|
322
340
|
add_ret = param.add(value, field=field, step=step, index=index)
|
|
323
341
|
if add_ret:
|
|
324
342
|
self.__journal.record("add", keypath, value=value, field=field,
|
|
325
343
|
step=step, index=index)
|
|
344
|
+
self.__process_active(param, add_ret)
|
|
326
345
|
return add_ret
|
|
327
346
|
except Exception as e:
|
|
328
|
-
new_msg = f"error while adding to
|
|
347
|
+
new_msg = f"error while adding to {self.__format_key(*keypath)}: {e.args[0]}"
|
|
329
348
|
e.args = (new_msg, *e.args[1:])
|
|
330
349
|
raise e
|
|
331
350
|
|
|
@@ -358,13 +377,13 @@ class BaseSchema:
|
|
|
358
377
|
try:
|
|
359
378
|
param = self.__search(*keypath, use_default=True)
|
|
360
379
|
except KeyError:
|
|
361
|
-
raise KeyError(f"
|
|
380
|
+
raise KeyError(f"{self.__format_key(*keypath)} is not a valid keypath")
|
|
362
381
|
|
|
363
382
|
try:
|
|
364
383
|
param.unset(step=step, index=index)
|
|
365
384
|
self.__journal.record("unset", keypath, step=step, index=index)
|
|
366
385
|
except Exception as e:
|
|
367
|
-
new_msg = f"error while unsetting
|
|
386
|
+
new_msg = f"error while unsetting {self.__format_key(*keypath)}: {e.args[0]}"
|
|
368
387
|
e.args = (new_msg, *e.args[1:])
|
|
369
388
|
raise e
|
|
370
389
|
|
|
@@ -384,7 +403,7 @@ class BaseSchema:
|
|
|
384
403
|
try:
|
|
385
404
|
key_param = self.__search(*search_path, require_leaf=False)
|
|
386
405
|
except KeyError:
|
|
387
|
-
raise KeyError(f"
|
|
406
|
+
raise KeyError(f"{self.__format_key(*keypath)} is not a valid keypath")
|
|
388
407
|
|
|
389
408
|
if removal_key not in key_param.__manifest:
|
|
390
409
|
return
|
|
@@ -454,13 +473,13 @@ class BaseSchema:
|
|
|
454
473
|
try:
|
|
455
474
|
key_param = self.__search(*keypath, require_leaf=False)
|
|
456
475
|
except KeyError:
|
|
457
|
-
raise KeyError(f"
|
|
476
|
+
raise KeyError(f"{self.__format_key(*keypath)} is not a valid keypath")
|
|
458
477
|
if isinstance(key_param, Parameter):
|
|
459
478
|
return tuple()
|
|
460
479
|
else:
|
|
461
480
|
key_param = self
|
|
462
481
|
|
|
463
|
-
return tuple(key_param.__manifest.keys())
|
|
482
|
+
return tuple(sorted(key_param.__manifest.keys()))
|
|
464
483
|
|
|
465
484
|
def allkeys(self, *keypath, include_default=True):
|
|
466
485
|
'''
|
|
@@ -555,8 +574,33 @@ class BaseSchema:
|
|
|
555
574
|
else:
|
|
556
575
|
schema_copy.__parent = schema_copy
|
|
557
576
|
|
|
577
|
+
if key:
|
|
578
|
+
schema_copy.__key = key[-1]
|
|
579
|
+
|
|
558
580
|
return schema_copy
|
|
559
581
|
|
|
582
|
+
def _find_files_search_paths(self, keypath, step, index):
|
|
583
|
+
"""
|
|
584
|
+
Returns a list of paths to search during find files.
|
|
585
|
+
|
|
586
|
+
Args:
|
|
587
|
+
keypath (str): final component of keypath
|
|
588
|
+
step (str): Step name.
|
|
589
|
+
index (str): Index name.
|
|
590
|
+
"""
|
|
591
|
+
return []
|
|
592
|
+
|
|
593
|
+
def _find_files_dataroot_resolvers(self):
|
|
594
|
+
"""
|
|
595
|
+
Returns a dictionary of path resolevrs data directory handling for find_files
|
|
596
|
+
|
|
597
|
+
Returns:
|
|
598
|
+
dictionary of str to resolver mapping
|
|
599
|
+
"""
|
|
600
|
+
if self.__parent is self:
|
|
601
|
+
return {}
|
|
602
|
+
return self.__parent._find_files_dataroot_resolvers()
|
|
603
|
+
|
|
560
604
|
def find_files(self, *keypath, missing_ok=False, step=None, index=None,
|
|
561
605
|
packages=None, collection_dir=None, cwd=None):
|
|
562
606
|
"""
|
|
@@ -592,10 +636,13 @@ class BaseSchema:
|
|
|
592
636
|
the schema.
|
|
593
637
|
"""
|
|
594
638
|
|
|
595
|
-
|
|
639
|
+
base_schema = self.get(*keypath[0:-1], field="schema")
|
|
640
|
+
|
|
641
|
+
param = base_schema.get(keypath[-1], field=None)
|
|
596
642
|
paramtype = param.get(field='type')
|
|
597
643
|
if 'file' not in paramtype and 'dir' not in paramtype:
|
|
598
|
-
raise TypeError(
|
|
644
|
+
raise TypeError(
|
|
645
|
+
f'Cannot find files on {self.__format_key(*keypath)}, must be a path type')
|
|
599
646
|
|
|
600
647
|
paths = param.get(field=None, step=step, index=index)
|
|
601
648
|
|
|
@@ -615,23 +662,26 @@ class BaseSchema:
|
|
|
615
662
|
cwd = os.getcwd()
|
|
616
663
|
|
|
617
664
|
if packages is None:
|
|
618
|
-
packages =
|
|
665
|
+
packages = base_schema._find_files_dataroot_resolvers()
|
|
619
666
|
|
|
620
667
|
resolved_paths = []
|
|
668
|
+
root_search_paths = base_schema._find_files_search_paths(keypath[-1], step, index)
|
|
621
669
|
for path in paths:
|
|
622
|
-
search_paths =
|
|
670
|
+
search_paths = root_search_paths.copy()
|
|
623
671
|
|
|
624
672
|
package = path.get(field="package")
|
|
625
673
|
if package:
|
|
626
674
|
if package not in packages:
|
|
627
|
-
raise ValueError(f"Resolver for {package} not provided"
|
|
675
|
+
raise ValueError(f"Resolver for {package} not provided: "
|
|
676
|
+
f"{self.__format_key(*keypath)}")
|
|
628
677
|
package_path = packages[package]
|
|
629
678
|
if isinstance(package_path, str):
|
|
630
679
|
search_paths.append(os.path.abspath(package_path))
|
|
631
680
|
elif callable(package_path):
|
|
632
681
|
search_paths.append(package_path())
|
|
633
682
|
else:
|
|
634
|
-
raise TypeError(f"Resolver for {package} is not a recognized type"
|
|
683
|
+
raise TypeError(f"Resolver for {package} is not a recognized type: "
|
|
684
|
+
f"{self.__format_key(*keypath)}")
|
|
635
685
|
else:
|
|
636
686
|
if cwd:
|
|
637
687
|
search_paths.append(os.path.abspath(cwd))
|
|
@@ -644,10 +694,11 @@ class BaseSchema:
|
|
|
644
694
|
if not missing_ok:
|
|
645
695
|
if package:
|
|
646
696
|
raise FileNotFoundError(
|
|
647
|
-
f'Could not find "{path.get()}" in {package}
|
|
697
|
+
f'Could not find "{path.get()}" in {package} '
|
|
698
|
+
f'{self.__format_key(*keypath)}')
|
|
648
699
|
else:
|
|
649
700
|
raise FileNotFoundError(
|
|
650
|
-
f'Could not find "{path.get()}"
|
|
701
|
+
f'Could not find "{path.get()}" {self.__format_key(*keypath)}')
|
|
651
702
|
resolved_paths.append(resolved_path)
|
|
652
703
|
|
|
653
704
|
if not is_list:
|
|
@@ -717,8 +768,8 @@ class BaseSchema:
|
|
|
717
768
|
else:
|
|
718
769
|
node_indicator = f" ({step}/{index})"
|
|
719
770
|
|
|
720
|
-
logger.error(f"Parameter
|
|
721
|
-
f"{check_file} is invalid")
|
|
771
|
+
logger.error(f"Parameter {self.__format_key(*keypath)}{node_indicator} "
|
|
772
|
+
f"path {check_file} is invalid")
|
|
722
773
|
|
|
723
774
|
return not error
|
|
724
775
|
|
|
@@ -735,3 +786,75 @@ class BaseSchema:
|
|
|
735
786
|
if self.__parent is self:
|
|
736
787
|
return self
|
|
737
788
|
return self.__parent._parent(root=root)
|
|
789
|
+
|
|
790
|
+
@contextlib.contextmanager
|
|
791
|
+
def _active(self, **kwargs):
|
|
792
|
+
'''
|
|
793
|
+
Use this context to temporarily set additional fields in :meth:`.set` and :meth:`.add`.
|
|
794
|
+
Additional fields can be specified which can be accessed by :meth:`._get_active`.
|
|
795
|
+
|
|
796
|
+
Args:
|
|
797
|
+
kwargs (dict of str): keyword arguments that are used for setting values
|
|
798
|
+
|
|
799
|
+
Example:
|
|
800
|
+
>>> with schema._active(package="lambdalib"):
|
|
801
|
+
... schema.set("file", "top.v")
|
|
802
|
+
Sets the file to top.v and associates lambdalib as the package.
|
|
803
|
+
'''
|
|
804
|
+
if self.__active:
|
|
805
|
+
orig_active = self.__active.copy()
|
|
806
|
+
else:
|
|
807
|
+
orig_active = None
|
|
808
|
+
|
|
809
|
+
if self.__active is None:
|
|
810
|
+
self.__active = {}
|
|
811
|
+
|
|
812
|
+
self.__active.update(kwargs)
|
|
813
|
+
try:
|
|
814
|
+
yield
|
|
815
|
+
finally:
|
|
816
|
+
self.__active = orig_active
|
|
817
|
+
|
|
818
|
+
def _get_active(self, field, defvalue=None):
|
|
819
|
+
'''
|
|
820
|
+
Get the value of a specific field.
|
|
821
|
+
|
|
822
|
+
Args:
|
|
823
|
+
field (str): if None, return the current active dictionary,
|
|
824
|
+
otherwise the value, if the field is not present, defvalue is returned.
|
|
825
|
+
defvalue (any): value to return if the field is not present.
|
|
826
|
+
'''
|
|
827
|
+
if self.__active is None:
|
|
828
|
+
return defvalue
|
|
829
|
+
|
|
830
|
+
if field is None:
|
|
831
|
+
return self.__active.copy()
|
|
832
|
+
|
|
833
|
+
return self.__active.get(field, defvalue)
|
|
834
|
+
|
|
835
|
+
def __process_active(self, param, nodevalues):
|
|
836
|
+
if not self.__active:
|
|
837
|
+
return
|
|
838
|
+
|
|
839
|
+
if not isinstance(nodevalues, (list, set, tuple)):
|
|
840
|
+
# Make everything a list
|
|
841
|
+
nodevalues = [nodevalues]
|
|
842
|
+
|
|
843
|
+
if not all([isinstance(v, NodeValue) for v in nodevalues]):
|
|
844
|
+
nodevalues = []
|
|
845
|
+
nodevalues_fields = []
|
|
846
|
+
else:
|
|
847
|
+
nodevalues_fields = nodevalues[0].fields
|
|
848
|
+
|
|
849
|
+
key_fields = ("copy", "lock")
|
|
850
|
+
|
|
851
|
+
for field, value in self.__active.items():
|
|
852
|
+
if field in key_fields:
|
|
853
|
+
param.set(value, field=field)
|
|
854
|
+
continue
|
|
855
|
+
|
|
856
|
+
if field not in nodevalues_fields:
|
|
857
|
+
continue
|
|
858
|
+
|
|
859
|
+
for param in nodevalues:
|
|
860
|
+
param.set(value, field=field)
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
from .parameter import Parameter
|
|
8
8
|
from .baseschema import BaseSchema
|
|
9
9
|
|
|
10
|
+
from typing import Union, Tuple
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
class EditableSchema:
|
|
12
14
|
'''
|
|
@@ -17,11 +19,15 @@ class EditableSchema:
|
|
|
17
19
|
schema (:class:`BaseSchema`): schema to modify
|
|
18
20
|
'''
|
|
19
21
|
|
|
20
|
-
def __init__(self, schema):
|
|
22
|
+
def __init__(self, schema: BaseSchema):
|
|
21
23
|
# Grab manifest from base class
|
|
22
24
|
self.__schema = schema
|
|
23
25
|
|
|
24
|
-
def __insert(self,
|
|
26
|
+
def __insert(self,
|
|
27
|
+
keypath: Tuple[str],
|
|
28
|
+
value: Union[BaseSchema, Parameter],
|
|
29
|
+
fullkey: Tuple[str],
|
|
30
|
+
clobber: bool) -> None:
|
|
25
31
|
key = keypath[0]
|
|
26
32
|
keypath = keypath[1:]
|
|
27
33
|
|
|
@@ -31,6 +37,7 @@ class EditableSchema:
|
|
|
31
37
|
|
|
32
38
|
if isinstance(value, BaseSchema):
|
|
33
39
|
value._BaseSchema__parent = self.__schema
|
|
40
|
+
value._BaseSchema__key = key
|
|
34
41
|
|
|
35
42
|
if key == "default":
|
|
36
43
|
self.__schema._BaseSchema__default = value
|
|
@@ -47,9 +54,10 @@ class EditableSchema:
|
|
|
47
54
|
self.__schema._BaseSchema__default = new_schema
|
|
48
55
|
else:
|
|
49
56
|
new_schema = self.__schema._BaseSchema__manifest.setdefault(key, new_schema)
|
|
57
|
+
new_schema._BaseSchema__key = key
|
|
50
58
|
EditableSchema(new_schema).__insert(keypath, value, fullkey, clobber)
|
|
51
59
|
|
|
52
|
-
def __remove(self, keypath, fullkey):
|
|
60
|
+
def __remove(self, keypath: Tuple[str], fullkey: Tuple[str]) -> None:
|
|
53
61
|
key = keypath[0]
|
|
54
62
|
keypath = keypath[1:]
|
|
55
63
|
|
|
@@ -69,7 +77,7 @@ class EditableSchema:
|
|
|
69
77
|
else:
|
|
70
78
|
EditableSchema(next_param).__remove(keypath, fullkey)
|
|
71
79
|
|
|
72
|
-
def insert(self, *args, clobber=False):
|
|
80
|
+
def insert(self, *args, clobber: bool = False) -> None:
|
|
73
81
|
'''
|
|
74
82
|
Inserts a :class:`Parameter` or a :class:`BaseSchema` to the schema,
|
|
75
83
|
based on the keypath and value provided in the ``*args``.
|
|
@@ -98,7 +106,7 @@ class EditableSchema:
|
|
|
98
106
|
|
|
99
107
|
self.__insert(keypath, value, keypath, clobber=clobber)
|
|
100
108
|
|
|
101
|
-
def remove(self, *keypath):
|
|
109
|
+
def remove(self, *keypath: str) -> None:
|
|
102
110
|
'''
|
|
103
111
|
Removes a keypath from the schema.
|
|
104
112
|
|
|
@@ -118,7 +126,7 @@ class EditableSchema:
|
|
|
118
126
|
|
|
119
127
|
self.__remove(keypath, keypath)
|
|
120
128
|
|
|
121
|
-
def search(self, *keypath):
|
|
129
|
+
def search(self, *keypath: str) -> Union[BaseSchema, Parameter]:
|
|
122
130
|
'''
|
|
123
131
|
Finds an item in the schema. This will raise a KeyError if
|
|
124
132
|
the path is not found.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import json
|
|
3
3
|
|
|
4
|
+
from typing import Tuple, Set
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
class Journal:
|
|
6
8
|
"""
|
|
@@ -12,7 +14,7 @@ class Journal:
|
|
|
12
14
|
keyprefix (list of str): keypath to prefix on to recorded path
|
|
13
15
|
"""
|
|
14
16
|
|
|
15
|
-
def __init__(self, keyprefix=None):
|
|
17
|
+
def __init__(self, keyprefix: Tuple[str] = None):
|
|
16
18
|
if not keyprefix:
|
|
17
19
|
self.__keyprefix = tuple()
|
|
18
20
|
else:
|
|
@@ -24,14 +26,14 @@ class Journal:
|
|
|
24
26
|
self.stop()
|
|
25
27
|
|
|
26
28
|
@property
|
|
27
|
-
def keypath(self):
|
|
29
|
+
def keypath(self) -> Tuple[str]:
|
|
28
30
|
'''
|
|
29
31
|
Returns the reference key path for this journal
|
|
30
32
|
'''
|
|
31
33
|
|
|
32
34
|
return self.__keyprefix
|
|
33
35
|
|
|
34
|
-
def get_child(self, *keypath):
|
|
36
|
+
def get_child(self, *keypath: Tuple[str]):
|
|
35
37
|
'''
|
|
36
38
|
Get a child journal based on a new keypath
|
|
37
39
|
|
|
@@ -60,26 +62,26 @@ class Journal:
|
|
|
60
62
|
|
|
61
63
|
return copy.deepcopy(self.__parent.__journal)
|
|
62
64
|
|
|
63
|
-
def has_journaling(self):
|
|
65
|
+
def has_journaling(self) -> bool:
|
|
64
66
|
"""
|
|
65
67
|
Returns true if the schema is currently setup and is the root of the journal and has data
|
|
66
68
|
"""
|
|
67
69
|
return self is self.__parent and bool(self.__journal)
|
|
68
70
|
|
|
69
|
-
def is_journaling(self):
|
|
71
|
+
def is_journaling(self) -> bool:
|
|
70
72
|
"""
|
|
71
73
|
Returns true if the schema is currently setup for journaling
|
|
72
74
|
"""
|
|
73
75
|
return self.__parent.__journal is not None
|
|
74
76
|
|
|
75
|
-
def get_types(self):
|
|
77
|
+
def get_types(self) -> Set[str]:
|
|
76
78
|
"""
|
|
77
79
|
Returns the current schema accesses that are being recorded
|
|
78
80
|
"""
|
|
79
81
|
|
|
80
82
|
return self.__parent.__record_types.copy()
|
|
81
83
|
|
|
82
|
-
def add_type(self, value):
|
|
84
|
+
def add_type(self, value: str) -> None:
|
|
83
85
|
"""
|
|
84
86
|
Adds a new access type to the journal record.
|
|
85
87
|
|
|
@@ -90,9 +92,9 @@ class Journal:
|
|
|
90
92
|
if value not in ("set", "add", "remove", "unset", "get"):
|
|
91
93
|
raise ValueError(f"{value} is not a valid type")
|
|
92
94
|
|
|
93
|
-
|
|
95
|
+
self.__parent.__record_types.add(value)
|
|
94
96
|
|
|
95
|
-
def remove_type(self, value):
|
|
97
|
+
def remove_type(self, value: str) -> None:
|
|
96
98
|
"""
|
|
97
99
|
Removes a new access type to the journal record.
|
|
98
100
|
|
|
@@ -105,7 +107,13 @@ class Journal:
|
|
|
105
107
|
except KeyError:
|
|
106
108
|
pass
|
|
107
109
|
|
|
108
|
-
def record(self,
|
|
110
|
+
def record(self,
|
|
111
|
+
record_type: str,
|
|
112
|
+
key: Tuple[str],
|
|
113
|
+
value=None,
|
|
114
|
+
field: str = None,
|
|
115
|
+
step: str = None,
|
|
116
|
+
index: str = None) -> None:
|
|
109
117
|
'''
|
|
110
118
|
Record the schema transaction
|
|
111
119
|
'''
|
|
@@ -125,7 +133,7 @@ class Journal:
|
|
|
125
133
|
"index": index
|
|
126
134
|
})
|
|
127
135
|
|
|
128
|
-
def start(self):
|
|
136
|
+
def start(self) -> None:
|
|
129
137
|
'''
|
|
130
138
|
Start journaling the schema transactions
|
|
131
139
|
'''
|
|
@@ -135,7 +143,7 @@ class Journal:
|
|
|
135
143
|
self.add_type("remove")
|
|
136
144
|
self.add_type("unset")
|
|
137
145
|
|
|
138
|
-
def stop(self):
|
|
146
|
+
def stop(self) -> None:
|
|
139
147
|
'''
|
|
140
148
|
Stop journaling the schema transactions
|
|
141
149
|
'''
|
|
@@ -143,7 +151,7 @@ class Journal:
|
|
|
143
151
|
self.__parent.__record_types.clear()
|
|
144
152
|
|
|
145
153
|
@staticmethod
|
|
146
|
-
def replay_file(schema, filepath):
|
|
154
|
+
def replay_file(schema, filepath: str) -> None:
|
|
147
155
|
'''
|
|
148
156
|
Replay a journal into a schema from a manifest
|
|
149
157
|
|
|
@@ -160,7 +168,7 @@ class Journal:
|
|
|
160
168
|
journal.from_dict(data["__journal__"])
|
|
161
169
|
journal.replay(schema)
|
|
162
170
|
|
|
163
|
-
def replay(self, schema):
|
|
171
|
+
def replay(self, schema) -> None:
|
|
164
172
|
'''
|
|
165
173
|
Replay journal into a schema
|
|
166
174
|
|
|
@@ -196,7 +204,7 @@ class Journal:
|
|
|
196
204
|
raise ValueError(f'Unknown record type {record_type}')
|
|
197
205
|
|
|
198
206
|
@staticmethod
|
|
199
|
-
def access(schema):
|
|
207
|
+
def access(schema) -> None:
|
|
200
208
|
'''
|
|
201
209
|
Access a journal from a schema
|
|
202
210
|
|
|
@@ -15,12 +15,12 @@ class NamedSchema(BaseSchema):
|
|
|
15
15
|
name (str): name of the schema
|
|
16
16
|
'''
|
|
17
17
|
|
|
18
|
-
def __init__(self, name=None):
|
|
18
|
+
def __init__(self, name: str = None):
|
|
19
19
|
super().__init__()
|
|
20
20
|
|
|
21
|
-
self.
|
|
21
|
+
self.set_name(name)
|
|
22
22
|
|
|
23
|
-
def name(self):
|
|
23
|
+
def name(self) -> str:
|
|
24
24
|
'''
|
|
25
25
|
Returns the name of the schema
|
|
26
26
|
'''
|
|
@@ -29,7 +29,7 @@ class NamedSchema(BaseSchema):
|
|
|
29
29
|
except AttributeError:
|
|
30
30
|
return None
|
|
31
31
|
|
|
32
|
-
def set_name(self, name):
|
|
32
|
+
def set_name(self, name: str) -> None:
|
|
33
33
|
"""
|
|
34
34
|
Set the name of this object
|
|
35
35
|
|
|
@@ -42,6 +42,8 @@ class NamedSchema(BaseSchema):
|
|
|
42
42
|
|
|
43
43
|
if self.name() is not None:
|
|
44
44
|
raise RuntimeError("Cannot call set_name more than once.")
|
|
45
|
+
if name is not None and "." in name:
|
|
46
|
+
raise ValueError("Named schema object cannot contains: .")
|
|
45
47
|
self.__name = name
|
|
46
48
|
|
|
47
49
|
def _reset(self) -> None:
|