siliconcompiler 0.35.2__py3-none-any.whl → 0.35.3__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.
Files changed (33) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/smake.py +106 -100
  3. siliconcompiler/flowgraph.py +418 -129
  4. siliconcompiler/library.py +5 -4
  5. siliconcompiler/package/https.py +10 -5
  6. siliconcompiler/project.py +83 -32
  7. siliconcompiler/remote/client.py +17 -6
  8. siliconcompiler/scheduler/scheduler.py +204 -55
  9. siliconcompiler/scheduler/schedulernode.py +63 -70
  10. siliconcompiler/schema/__init__.py +3 -2
  11. siliconcompiler/schema/_metadata.py +1 -1
  12. siliconcompiler/schema/baseschema.py +205 -93
  13. siliconcompiler/schema/namedschema.py +21 -13
  14. siliconcompiler/schema/safeschema.py +18 -7
  15. siliconcompiler/schema_support/dependencyschema.py +4 -3
  16. siliconcompiler/schema_support/pathschema.py +7 -2
  17. siliconcompiler/schema_support/record.py +5 -4
  18. siliconcompiler/targets/asap7_demo.py +4 -1
  19. siliconcompiler/tool.py +9 -4
  20. siliconcompiler/tools/builtin/__init__.py +2 -0
  21. siliconcompiler/tools/builtin/filter.py +8 -1
  22. siliconcompiler/tools/builtin/importfiles.py +2 -0
  23. siliconcompiler/tools/klayout/scripts/klayout_show.py +1 -1
  24. siliconcompiler/tools/klayout/show.py +17 -5
  25. siliconcompiler/tools/yosys/prepareLib.py +7 -2
  26. siliconcompiler/tools/yosys/syn_asic.py +20 -2
  27. siliconcompiler/toolscripts/_tools.json +4 -4
  28. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.3.dist-info}/METADATA +2 -2
  29. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.3.dist-info}/RECORD +33 -33
  30. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.3.dist-info}/WHEEL +0 -0
  31. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.3.dist-info}/entry_points.txt +0 -0
  32. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.3.dist-info}/licenses/LICENSE +0 -0
  33. {siliconcompiler-0.35.2.dist-info → siliconcompiler-0.35.3.dist-info}/top_level.txt +0 -0
@@ -24,14 +24,42 @@ except ModuleNotFoundError:
24
24
 
25
25
  import os.path
26
26
 
27
+ from enum import Enum, auto
27
28
  from functools import cache
28
- from typing import Dict, Type, Tuple, Union, Set, Callable, List, Optional, TextIO, Iterable
29
+ from typing import Dict, Type, Tuple, Union, Set, Callable, List, Optional, TextIO, Iterable, Any
29
30
 
30
31
  from .parameter import Parameter, NodeValue
31
32
  from .journal import Journal
32
33
  from ._metadata import version
33
34
 
34
35
 
36
+ class LazyLoad(Enum):
37
+ """
38
+ Controls manifest loading
39
+ """
40
+ OFF = auto() # load entire schema immediately
41
+ ON = auto() # store schema but do not load it
42
+ FORWARD = auto() # load the current section but do not load children
43
+
44
+ @property
45
+ def next(self) -> "LazyLoad":
46
+ """
47
+ Returns the next state for lazy loading
48
+ """
49
+ if self == LazyLoad.ON:
50
+ return LazyLoad.ON
51
+ if self == LazyLoad.FORWARD:
52
+ return LazyLoad.ON
53
+ return LazyLoad.OFF
54
+
55
+ @property
56
+ def is_enforced(self) -> bool:
57
+ """
58
+ Returns true when the current section should not be loaded.
59
+ """
60
+ return self == LazyLoad.ON
61
+
62
+
35
63
  class BaseSchema:
36
64
  '''
37
65
  This class maintains the access and file IO operations for the schema.
@@ -42,21 +70,38 @@ class BaseSchema:
42
70
  __version = tuple([int(v) for v in version.split('.')])
43
71
 
44
72
  def __init__(self):
45
- self.__manifest = {}
46
- self.__default = None
47
- self.__journal = Journal()
48
- self.__parent = self
49
- self.__active = None
50
- self.__key = None
73
+ self.__manifest: Dict[str, Union["BaseSchema", Parameter]] = {}
74
+ self.__default: Optional[Union["BaseSchema", Parameter]] = None
75
+ self.__journal: Journal = Journal()
76
+ self.__parent: Optional["BaseSchema"] = None
77
+ self.__active: Optional[Dict] = None
78
+ self.__key: Optional[str] = None
79
+ self.__lazy: Optional[Tuple[Optional[Tuple[int, ...]], Dict]] = None
80
+
81
+ @property
82
+ def __is_root(self) -> bool:
83
+ '''
84
+ Returns true if the object is the root of the schema
85
+ '''
86
+ try:
87
+ return self.__parent is None
88
+ except AttributeError:
89
+ return True
51
90
 
52
91
  @property
53
92
  def _keypath(self) -> Tuple[str, ...]:
54
93
  '''
55
94
  Returns the key to the current section of the schema
56
95
  '''
57
- if self.__parent is self:
96
+ if self.__is_root:
97
+ return tuple()
98
+ try:
99
+ parentpath = self.__parent._keypath
100
+ key = self.__key
101
+ except AttributeError:
102
+ # Guard against partially setup parents during serialization
58
103
  return tuple()
59
- return tuple([*self.__parent._keypath, self.__key])
104
+ return tuple([*parentpath, key])
60
105
 
61
106
  @staticmethod
62
107
  @cache
@@ -146,13 +191,25 @@ class BaseSchema:
146
191
  def __extractversion(manifest: Dict) -> Optional[Tuple[int, ...]]:
147
192
  schema_version = manifest.get(BaseSchema._version_key, None)
148
193
  if schema_version:
149
- param = Parameter.from_dict(schema_version, [BaseSchema._version_key], None)
194
+ param = Parameter.from_dict(schema_version,
195
+ tuple([BaseSchema._version_key]),
196
+ None)
150
197
  return tuple([int(v) for v in param.get().split('.')])
151
198
  return None
152
199
 
200
+ def __ensure_lazy_elab(self):
201
+ if not self.__lazy:
202
+ return
203
+
204
+ version, manifest = self.__lazy
205
+ self.__lazy = None
206
+
207
+ self._from_dict(manifest, self._keypath, version=version, lazyload=LazyLoad.FORWARD)
208
+
153
209
  def _from_dict(self, manifest: Dict,
154
210
  keypath: Union[List[str], Tuple[str, ...]],
155
- version: Optional[Tuple[int, ...]] = None) \
211
+ version: Optional[Tuple[int, ...]] = None,
212
+ lazyload: LazyLoad = LazyLoad.ON) \
156
213
  -> Tuple[Set[Tuple[str, ...]], Set[Tuple[str, ...]]]:
157
214
  '''
158
215
  Decodes a dictionary into a schema object
@@ -174,26 +231,35 @@ class BaseSchema:
174
231
 
175
232
  if "__journal__" in manifest:
176
233
  self.__journal.from_dict(manifest["__journal__"])
177
- del manifest["__journal__"]
234
+ if lazyload != LazyLoad.ON:
235
+ del manifest["__journal__"]
236
+
237
+ if lazyload == LazyLoad.ON:
238
+ self.__lazy = (version, manifest)
239
+ return set(), set()
178
240
 
179
241
  if "__meta__" in manifest:
180
242
  del manifest["__meta__"]
181
243
 
182
244
  if self.__default:
183
- data = manifest.get("default", None)
245
+ data = manifest.pop("default", None)
184
246
  if data:
185
- del manifest["default"]
186
- self.__default._from_dict(data, list(keypath) + ["default"], version=version)
247
+ if isinstance(self.__default, BaseSchema):
248
+ self.__default._from_dict(data, tuple([*keypath, "default"]), version=version,
249
+ lazyload=lazyload.next)
250
+ else:
251
+ self.__default._from_dict(data, tuple([*keypath, "default"]), version=version)
187
252
  handled.add("default")
188
253
 
189
254
  for key, data in manifest.items():
255
+ data_keypath = tuple([*keypath, key])
190
256
  obj = self.__manifest.get(key, None)
191
257
  if not obj and isinstance(data, dict) and "__meta__" in data:
192
258
  # Lookup object, use class first, then type
193
259
  cls = BaseSchema.__process_meta_section(data["__meta__"])
194
260
  if cls is BaseSchema and self.__default:
195
261
  # Use default when BaseSchema is the class
196
- obj = self.__default.copy(key=list(keypath) + [key])
262
+ obj = self.__default.copy(key=data_keypath)
197
263
  self.__manifest[key] = obj
198
264
  elif cls:
199
265
  # Create object and connect to schema
@@ -204,11 +270,14 @@ class BaseSchema:
204
270
 
205
271
  # Use default if it is available
206
272
  if not obj and self.__default:
207
- obj = self.__default.copy(key=list(keypath) + [key])
273
+ obj = self.__default.copy(key=data_keypath)
208
274
  self.__manifest[key] = obj
209
275
 
210
276
  if obj:
211
- obj._from_dict(data, list(keypath) + [key], version=version)
277
+ if isinstance(obj, BaseSchema):
278
+ obj._from_dict(data, data_keypath, version=version, lazyload=lazyload.next)
279
+ else:
280
+ obj._from_dict(data, data_keypath, version=version)
212
281
  handled.add(key)
213
282
  else:
214
283
  missing.add(key)
@@ -219,7 +288,8 @@ class BaseSchema:
219
288
  @classmethod
220
289
  def from_manifest(cls,
221
290
  filepath: Union[None, str] = None,
222
- cfg: Union[None, Dict] = None) -> "BaseSchema":
291
+ cfg: Union[None, Dict] = None,
292
+ lazyload: bool = True) -> "BaseSchema":
223
293
  '''
224
294
  Create a new schema based on the provided source files.
225
295
 
@@ -245,7 +315,12 @@ class BaseSchema:
245
315
  else:
246
316
  schema = cls()
247
317
 
248
- schema._from_dict(cfg, tuple())
318
+ if lazyload:
319
+ do_lazyload = LazyLoad.ON
320
+ else:
321
+ do_lazyload = LazyLoad.OFF
322
+
323
+ schema._from_dict(cfg, tuple(), lazyload=do_lazyload)
249
324
 
250
325
  return schema
251
326
 
@@ -321,13 +396,19 @@ class BaseSchema:
321
396
  insert_defaults: bool = False,
322
397
  use_default: bool = False,
323
398
  require_leaf: bool = True,
324
- complete_path: Optional[List[str]] = None) -> Union["BaseSchema", Parameter]:
399
+ complete_path: Optional[List[str]] = None,
400
+ elaborate_leaf: bool = True) -> Union["BaseSchema", Parameter]:
401
+
325
402
  if len(keypath) == 0:
326
403
  if require_leaf:
327
404
  raise KeyError
328
405
  else:
406
+ if elaborate_leaf:
407
+ self.__ensure_lazy_elab()
329
408
  return self
330
409
 
410
+ self.__ensure_lazy_elab()
411
+
331
412
  if complete_path is None:
332
413
  complete_path = []
333
414
  complete_path.append(keypath[0])
@@ -351,6 +432,8 @@ class BaseSchema:
351
432
  if require_leaf:
352
433
  raise KeyError
353
434
  else:
435
+ if elaborate_leaf:
436
+ key_param.__ensure_lazy_elab()
354
437
  return key_param
355
438
  return key_param.__search(*keypath[1:],
356
439
  insert_defaults=insert_defaults,
@@ -637,16 +720,13 @@ class BaseSchema:
637
720
  >>> keylist = schema.getkeys('pdk')
638
721
  Returns all keys for the [pdk] keypath.
639
722
  """
723
+ try:
724
+ key_param = self.__search(*keypath, require_leaf=False)
725
+ except KeyError:
726
+ raise KeyError(f"{self.__format_key(*keypath)} is not a valid keypath")
640
727
 
641
- if keypath:
642
- try:
643
- key_param = self.__search(*keypath, require_leaf=False)
644
- except KeyError:
645
- raise KeyError(f"{self.__format_key(*keypath)} is not a valid keypath")
646
- if isinstance(key_param, Parameter):
647
- return tuple()
648
- else:
649
- key_param = self
728
+ if isinstance(key_param, Parameter):
729
+ return tuple()
650
730
 
651
731
  return tuple(sorted(key_param.__manifest.keys()))
652
732
 
@@ -658,14 +738,17 @@ class BaseSchema:
658
738
  keypath (list of str): Keypath prefix to search under. The
659
739
  returned keypaths do not include the prefix.
660
740
  '''
741
+ try:
742
+ key_param = self.__search(*keypath, require_leaf=False)
743
+ except KeyError:
744
+ return set()
661
745
 
662
- if keypath:
663
- key_param = self.__manifest.get(keypath[0], None)
664
- if not key_param or isinstance(key_param, Parameter):
665
- return set()
666
- return key_param.allkeys(*keypath[1:], include_default=include_default)
746
+ if isinstance(key_param, Parameter):
747
+ return set()
667
748
 
668
- def add(keys, key, item):
749
+ def add(keys: List[Tuple[str, ...]],
750
+ key: str,
751
+ item: Union["BaseSchema", Parameter]) -> None:
669
752
  if isinstance(item, Parameter):
670
753
  keys.append((key,))
671
754
  else:
@@ -673,9 +756,9 @@ class BaseSchema:
673
756
  keys.append((key, *subkeypath))
674
757
 
675
758
  keys = []
676
- if include_default and self.__default:
677
- add(keys, "default", self.__default)
678
- for key, item in self.__manifest.items():
759
+ if include_default and key_param.__default:
760
+ add(keys, "default", key_param.__default)
761
+ for key, item in key_param.__manifest.items():
679
762
  add(keys, key, item)
680
763
  return set(keys)
681
764
 
@@ -714,42 +797,52 @@ class BaseSchema:
714
797
  >>> pdk = schema.getdict('pdk')
715
798
  Returns the complete dictionary found for the keypath [pdk]
716
799
  """
800
+ try:
801
+ if not values_only and include_default:
802
+ key_param = self.__search(*keypath, require_leaf=False, elaborate_leaf=False)
717
803
 
718
- if keypath:
719
- key_param = self.__manifest.get(keypath[0], None)
720
- if not key_param:
721
- return {}
722
- return key_param.getdict(*keypath[1:],
723
- include_default=include_default,
724
- values_only=values_only)
804
+ if isinstance(key_param, Parameter):
805
+ return key_param.getdict(include_default=include_default,
806
+ values_only=values_only)
807
+
808
+ if key_param.__lazy:
809
+ return key_param.__lazy[1]
810
+ else:
811
+ key_param = self.__search(*keypath, require_leaf=False)
812
+ except KeyError:
813
+ return {}
814
+
815
+ if isinstance(key_param, Parameter):
816
+ return key_param.getdict(include_default=include_default, values_only=values_only)
725
817
 
726
818
  manifest = {}
727
- if include_default and self.__default:
728
- manifest_dict = self.__default.getdict(include_default=include_default,
729
- values_only=values_only)
819
+ if include_default and key_param.__default:
820
+ manifest_dict = key_param.__default.getdict(include_default=include_default,
821
+ values_only=values_only)
730
822
  if manifest_dict or not values_only:
731
823
  manifest["default"] = manifest_dict
732
- for key, item in self.__manifest.items():
824
+ for key, item in key_param.__manifest.items():
733
825
  manifest_dict = item.getdict(include_default=include_default,
734
826
  values_only=values_only)
735
827
  if manifest_dict or not values_only:
736
828
  manifest[key] = manifest_dict
737
829
 
738
- if not values_only and self.__journal.has_journaling():
739
- manifest["__journal__"] = self.__journal.get()
830
+ if not values_only and key_param.__journal.has_journaling():
831
+ manifest["__journal__"] = key_param.__journal.get()
740
832
 
741
- if not values_only and self.__class__ is not BaseSchema:
833
+ if not values_only and key_param.__class__ is not BaseSchema:
742
834
  manifest["__meta__"] = {}
743
835
 
744
836
  try:
745
- cls_meta = self._getdict_meta()
837
+ cls_meta = key_param._getdict_meta()
746
838
  manifest["__meta__"].update(cls_meta)
747
839
  except NotImplementedError:
748
840
  pass
749
841
 
750
- manifest["__meta__"]["class"] = f"{self.__class__.__module__}/{self.__class__.__name__}"
842
+ manifest["__meta__"]["class"] = \
843
+ f"{key_param.__class__.__module__}/{key_param.__class__.__name__}"
751
844
  try:
752
- manifest["__meta__"]["sctype"] = self._getdict_type()
845
+ manifest["__meta__"]["sctype"] = key_param._getdict_type()
753
846
  except NotImplementedError:
754
847
  pass
755
848
 
@@ -768,11 +861,7 @@ class BaseSchema:
768
861
  self.__parent = None
769
862
  schema_copy = copy.deepcopy(self)
770
863
  self.__parent = parent
771
-
772
- if self is not self.__parent:
773
- schema_copy.__parent = self.__parent
774
- else:
775
- schema_copy.__parent = schema_copy
864
+ schema_copy.__parent = self.__parent
776
865
 
777
866
  if key:
778
867
  schema_copy.__key = key[-1]
@@ -792,16 +881,20 @@ class BaseSchema:
792
881
  """
793
882
  return []
794
883
 
795
- def _find_files_dataroot_resolvers(self) -> Dict[str, Union[str, Callable]]:
884
+ def _find_files_dataroot_resolvers(self, resolvers: bool = False) \
885
+ -> Dict[str, Union[str, Callable]]:
796
886
  """
797
887
  Returns a dictionary of path resolvers data directory handling for find_files
798
888
 
889
+ Args:
890
+ resolvers (bool, optional): Returns the resolvers instead of callables
891
+
799
892
  Returns:
800
893
  dictionary of str to resolver mapping
801
894
  """
802
- if self.__parent is self:
895
+ if self.__is_root:
803
896
  return {}
804
- return self.__parent._find_files_dataroot_resolvers()
897
+ return self.__parent._find_files_dataroot_resolvers(resolvers=resolvers)
805
898
 
806
899
  def _find_files(self, *keypath: str, missing_ok: bool = False,
807
900
  step: Optional[str] = None, index: Optional[Union[int, str]] = None,
@@ -927,6 +1020,7 @@ class BaseSchema:
927
1020
  search_paths = root_search_paths.copy()
928
1021
 
929
1022
  dataroot: Optional[str] = path.get(field="dataroot")
1023
+ dataroot_except: Optional[Exception] = None
930
1024
  if dataroot:
931
1025
  if dataroot not in dataroots:
932
1026
  raise ValueError(f"Resolver for {dataroot} not provided: "
@@ -935,7 +1029,10 @@ class BaseSchema:
935
1029
  if isinstance(dataroot_path, str):
936
1030
  search_paths.append(os.path.abspath(dataroot_path))
937
1031
  elif callable(dataroot_path):
938
- search_paths.append(dataroot_path())
1032
+ try:
1033
+ search_paths.append(dataroot_path())
1034
+ except Exception as e:
1035
+ dataroot_except = e
939
1036
  else:
940
1037
  raise TypeError(f"Resolver for {dataroot} is not a recognized type: "
941
1038
  f"{self.__format_key(*keypath)}")
@@ -956,6 +1053,10 @@ class BaseSchema:
956
1053
  if not missing_ok:
957
1054
  report_paths = ", ".join(search_paths)
958
1055
  if dataroot:
1056
+ if dataroot_except:
1057
+ raise FileNotFoundError(
1058
+ f"Dataroot {dataroot} not found: {dataroot_except}") \
1059
+ from dataroot_except
959
1060
  raise FileNotFoundError(
960
1061
  f'Could not find "{path.get()}" in {dataroot} '
961
1062
  f'{self.__format_key(*keypath)}: {report_paths}')
@@ -1036,7 +1137,7 @@ class BaseSchema:
1036
1137
  node_indicator = f" ({step}/{index})"
1037
1138
 
1038
1139
  name = ""
1039
- if self.__parent is self and hasattr(self, "name"):
1140
+ if hasattr(self, "name"):
1040
1141
  name = f"({self.name}) "
1041
1142
 
1042
1143
  logger.error(f"Parameter {name}"
@@ -1101,10 +1202,11 @@ class BaseSchema:
1101
1202
  Args:
1102
1203
  root (bool): if true, returns the root of the schemas.
1103
1204
  '''
1205
+ if self.__is_root:
1206
+ return self
1207
+
1104
1208
  if not root:
1105
1209
  return self.__parent
1106
- if self.__parent is self:
1107
- return self
1108
1210
  return self.__parent._parent(root=root)
1109
1211
 
1110
1212
  @contextlib.contextmanager
@@ -1122,30 +1224,18 @@ class BaseSchema:
1122
1224
  Sets the file to top.v and associates lambdalib as the dataroot.
1123
1225
  '''
1124
1226
 
1125
- # Collect child schemas
1126
- subkeys = set()
1127
- for key in self.allkeys():
1128
- for n in range(len(key)):
1129
- subkeys.add(key[:n])
1130
- subschemas = set()
1131
- subschemas.add(self)
1132
- for key in subkeys:
1133
- subschemas.add(self.get(*key, field="schema"))
1134
-
1135
- orig_active = {}
1136
- for schema in subschemas:
1137
- if schema.__active:
1138
- orig_active[schema] = schema.__active.copy()
1139
- else:
1140
- orig_active[schema] = None
1141
- schema.__active = {}
1142
- schema.__active.update(kwargs)
1227
+ if self.__active is None:
1228
+ orig_active = None
1229
+ self.__active = {}
1230
+ else:
1231
+ orig_active = self.__active.copy()
1232
+
1233
+ self.__active.update(kwargs)
1143
1234
 
1144
1235
  try:
1145
1236
  yield
1146
1237
  finally:
1147
- for schema, orig in orig_active.items():
1148
- schema.__active = orig
1238
+ self.__active = orig_active
1149
1239
 
1150
1240
  def _get_active(self, field: str, defvalue=None):
1151
1241
  '''
@@ -1156,20 +1246,42 @@ class BaseSchema:
1156
1246
  otherwise the value, if the field is not present, defvalue is returned.
1157
1247
  defvalue (any): value to return if the field is not present.
1158
1248
  '''
1159
- if self.__active is None:
1249
+ actives = self.__get_active()
1250
+ if actives is None:
1160
1251
  return defvalue
1161
1252
 
1162
1253
  if field is None:
1163
- return self.__active.copy()
1254
+ return actives
1255
+
1256
+ return actives.get(field, defvalue)
1257
+
1258
+ def __get_active(self) -> Optional[Dict[str, Any]]:
1259
+ '''
1260
+ Get the actives this point in the schema
1261
+ '''
1262
+ schemas: List["BaseSchema"] = [self]
1263
+
1264
+ root = self._parent(root=True)
1265
+ curr = schemas[-1]
1266
+ while curr is not root:
1267
+ schemas.append(curr._parent())
1268
+ curr = schemas[-1]
1164
1269
 
1165
- return self.__active.get(field, defvalue)
1270
+ active = {}
1271
+ for schema in reversed(schemas):
1272
+ if schema.__active:
1273
+ active.update(schema.__active)
1274
+ if not active:
1275
+ return None
1276
+ return active
1166
1277
 
1167
1278
  def __process_active(self, param: Parameter,
1168
1279
  nodevalues: Optional[Union[List[NodeValue],
1169
1280
  Set[NodeValue],
1170
1281
  Tuple[NodeValue, ...],
1171
1282
  NodeValue]]) -> None:
1172
- if not self.__active:
1283
+ actives = self.__get_active()
1284
+ if actives is None:
1173
1285
  return
1174
1286
 
1175
1287
  if not isinstance(nodevalues, (list, set, tuple)):
@@ -1184,7 +1296,7 @@ class BaseSchema:
1184
1296
 
1185
1297
  key_fields = ("copy", "lock")
1186
1298
 
1187
- for field, value in self.__active.items():
1299
+ for field, value in actives.items():
1188
1300
  if field in key_fields:
1189
1301
  param.set(value, field=field)
1190
1302
  continue
@@ -6,7 +6,7 @@
6
6
 
7
7
  from typing import Dict, Tuple, Optional, Set, Union, List
8
8
 
9
- from .baseschema import BaseSchema
9
+ from .baseschema import BaseSchema, LazyLoad
10
10
 
11
11
 
12
12
  class NamedSchema(BaseSchema):
@@ -71,10 +71,17 @@ class NamedSchema(BaseSchema):
71
71
  info["name"] = self.name
72
72
  return info
73
73
 
74
+ @staticmethod
75
+ def __get_meta_name(cfg: Optional[Dict]) -> Optional[str]:
76
+ if not cfg:
77
+ return None
78
+ return cfg.get("__meta__", {}).get("name", None)
79
+
74
80
  @classmethod
75
81
  def from_manifest(cls,
76
82
  filepath: Union[None, str] = None,
77
83
  cfg: Union[None, Dict] = None,
84
+ lazyload: bool = True,
78
85
  name: Optional[str] = None):
79
86
  '''
80
87
  Create a new schema based on the provided source files.
@@ -86,28 +93,29 @@ class NamedSchema(BaseSchema):
86
93
  cfg (dict): Initial configuration dictionary.
87
94
  name (str): name of the schema.
88
95
  '''
96
+ if filepath and not cfg:
97
+ cfg = BaseSchema._read_manifest(filepath)
89
98
 
90
- if not filepath and cfg is None:
91
- raise RuntimeError("filepath or dictionary is required")
99
+ meta_name = NamedSchema.__get_meta_name(cfg)
100
+ schema = super().from_manifest(filepath=None, cfg=cfg, lazyload=lazyload)
101
+ if name:
102
+ schema.__name = name
103
+ elif meta_name:
104
+ schema.__name = meta_name
92
105
 
93
- schema = cls()
94
- schema.set_name(name)
95
- if filepath:
96
- schema.read_manifest(filepath)
97
- if cfg:
98
- schema._from_dict(cfg, tuple())
99
106
  return schema
100
107
 
101
108
  def _from_dict(self, manifest: Dict,
102
109
  keypath: Union[List[str], Tuple[str, ...]],
103
- version: Optional[Tuple[int, ...]] = None) \
110
+ version: Optional[Tuple[int, ...]] = None,
111
+ lazyload: LazyLoad = LazyLoad.ON) \
104
112
  -> Tuple[Set[Tuple[str, ...]], Set[Tuple[str, ...]]]:
105
113
  if keypath:
106
114
  self.__name = keypath[-1]
107
- elif not self.__name and "__meta__" in manifest and "name" in manifest["__meta__"]:
108
- self.__name = manifest["__meta__"]["name"]
115
+ elif not self.__name:
116
+ self.__name = NamedSchema.__get_meta_name(manifest)
109
117
 
110
- return super()._from_dict(manifest, keypath, version=version)
118
+ return super()._from_dict(manifest, keypath, version=version, lazyload=lazyload)
111
119
 
112
120
  def copy(self, key: Optional[Tuple[str, ...]] = None) -> "NamedSchema":
113
121
  copy: NamedSchema = super().copy(key=key)
@@ -7,7 +7,7 @@
7
7
  from typing import Dict, Tuple, Optional, Union, List, Set
8
8
 
9
9
  from .parameter import Parameter
10
- from .baseschema import BaseSchema
10
+ from .baseschema import BaseSchema, LazyLoad
11
11
 
12
12
 
13
13
  class SafeSchema(BaseSchema):
@@ -35,7 +35,8 @@ class SafeSchema(BaseSchema):
35
35
 
36
36
  def _from_dict(self, manifest: Dict,
37
37
  keypath: Union[List[str], Tuple[str, ...]],
38
- version: Optional[Tuple[int, ...]] = None) \
38
+ version: Optional[Tuple[int, ...]] = None,
39
+ lazyload: LazyLoad = LazyLoad.OFF) \
39
40
  -> Tuple[Set[Tuple[str, ...]], Set[Tuple[str, ...]]]:
40
41
  if not isinstance(manifest, dict):
41
42
  return set(), set()
@@ -43,11 +44,13 @@ class SafeSchema(BaseSchema):
43
44
  if "__meta__" in manifest:
44
45
  del manifest["__meta__"]
45
46
 
47
+ lazyload = LazyLoad.OFF
48
+
46
49
  for key, data in manifest.items():
47
50
  obj = SafeSchema.__is_dict_leaf(data, list(keypath) + [key], version)
48
51
  if not obj:
49
52
  obj = SafeSchema()
50
- obj._from_dict(data, list(keypath) + [key], version)
53
+ obj._from_dict(data, list(keypath) + [key], version=version, lazyload=lazyload)
51
54
 
52
55
  if key == "default":
53
56
  self._BaseSchema__default = obj
@@ -59,11 +62,19 @@ class SafeSchema(BaseSchema):
59
62
  @classmethod
60
63
  def from_manifest(cls,
61
64
  filepath: Union[None, str] = None,
62
- cfg: Union[None, Dict] = None) -> "SafeSchema":
65
+ cfg: Union[None, Dict] = None,
66
+ lazyload: bool = False) -> "SafeSchema":
63
67
  if filepath:
64
68
  cfg = BaseSchema._read_manifest(filepath)
65
69
 
66
- if cfg and "__meta__" in cfg:
67
- del cfg["__meta__"]
70
+ def rm_meta(manifest):
71
+ if not isinstance(manifest, dict):
72
+ return
73
+ if manifest and "__meta__" in manifest:
74
+ del manifest["__meta__"]
75
+ for section in manifest.values():
76
+ rm_meta(section)
77
+
78
+ rm_meta(cfg)
68
79
 
69
- return super().from_manifest(filepath=None, cfg=cfg)
80
+ return super().from_manifest(filepath=None, cfg=cfg, lazyload=False)