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.
Files changed (46) hide show
  1. siliconcompiler/__init__.py +14 -2
  2. siliconcompiler/_metadata.py +1 -1
  3. siliconcompiler/apps/sc_show.py +1 -1
  4. siliconcompiler/constraints/__init__.py +17 -0
  5. siliconcompiler/constraints/asic_component.py +378 -0
  6. siliconcompiler/constraints/asic_floorplan.py +449 -0
  7. siliconcompiler/constraints/asic_pins.py +489 -0
  8. siliconcompiler/constraints/asic_timing.py +517 -0
  9. siliconcompiler/core.py +3 -3
  10. siliconcompiler/dependencyschema.py +10 -174
  11. siliconcompiler/design.py +235 -118
  12. siliconcompiler/flowgraph.py +27 -14
  13. siliconcompiler/library.py +133 -0
  14. siliconcompiler/metric.py +94 -72
  15. siliconcompiler/metrics/__init__.py +7 -0
  16. siliconcompiler/metrics/asic.py +245 -0
  17. siliconcompiler/metrics/fpga.py +220 -0
  18. siliconcompiler/package/__init__.py +138 -35
  19. siliconcompiler/package/github.py +6 -10
  20. siliconcompiler/packageschema.py +256 -12
  21. siliconcompiler/pathschema.py +226 -0
  22. siliconcompiler/project.py +459 -0
  23. siliconcompiler/scheduler/docker.py +2 -3
  24. siliconcompiler/scheduler/run_node.py +2 -1
  25. siliconcompiler/scheduler/scheduler.py +4 -13
  26. siliconcompiler/scheduler/schedulernode.py +25 -17
  27. siliconcompiler/scheduler/taskscheduler.py +2 -1
  28. siliconcompiler/schema/__init__.py +0 -2
  29. siliconcompiler/schema/baseschema.py +147 -24
  30. siliconcompiler/schema/editableschema.py +14 -6
  31. siliconcompiler/schema/journal.py +23 -15
  32. siliconcompiler/schema/namedschema.py +6 -4
  33. siliconcompiler/schema/parameter.py +34 -19
  34. siliconcompiler/schema/parametertype.py +2 -0
  35. siliconcompiler/schema/parametervalue.py +198 -15
  36. siliconcompiler/schema/schema_cfg.py +18 -14
  37. siliconcompiler/schema_obj.py +5 -3
  38. siliconcompiler/tool.py +199 -10
  39. siliconcompiler/toolscripts/_tools.json +4 -4
  40. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/METADATA +3 -3
  41. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/RECORD +45 -35
  42. siliconcompiler/schema/packageschema.py +0 -101
  43. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/WHEEL +0 -0
  44. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/entry_points.txt +0 -0
  45. {siliconcompiler-0.34.1.dist-info → siliconcompiler-0.34.2.dist-info}/licenses/LICENSE +0 -0
  46. {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=False,
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"[{','.join(keypath)}] is a complete keypath")
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"[{','.join(keypath)}] is not a valid keypath")
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 [{','.join(keypath)}]: {e.args[0]}"
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"[{','.join(keypath)}] is not a valid keypath")
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 [{','.join(keypath)}]: {e.args[0]}"
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"[{','.join(keypath)}] is not a valid keypath")
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 [{','.join(keypath)}]: {e.args[0]}"
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"[{','.join(keypath)}] is not a valid keypath")
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 [{','.join(keypath)}]: {e.args[0]}"
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"[{','.join(keypath)}] is not a valid keypath")
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"[{','.join(keypath)}] is not a valid keypath")
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
- param = self.get(*keypath, field=None)
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(f'Cannot find files on [{",".join(keypath)}], must be a path type')
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} [{",".join(keypath)}]')
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()}" [{",".join(keypath)}]')
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 [{','.join(keypath)}]{node_indicator} path "
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, keypath, value, fullkey, clobber):
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
- return self.__parent.__record_types.add(value)
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, record_type, key, value=None, field=None, step=None, index=None):
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.__name = name
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: