siliconcompiler 0.35.0__py3-none-any.whl → 0.35.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/_common.py +3 -2
  3. siliconcompiler/apps/sc_dashboard.py +3 -1
  4. siliconcompiler/apps/sc_install.py +149 -37
  5. siliconcompiler/apps/smake.py +9 -3
  6. siliconcompiler/checklist.py +3 -3
  7. siliconcompiler/data/demo_fpga/z1000_yosys_config.json +24 -0
  8. siliconcompiler/design.py +51 -45
  9. siliconcompiler/flowgraph.py +2 -2
  10. siliconcompiler/library.py +23 -12
  11. siliconcompiler/package/__init__.py +77 -49
  12. siliconcompiler/package/git.py +11 -6
  13. siliconcompiler/package/github.py +11 -6
  14. siliconcompiler/package/https.py +6 -4
  15. siliconcompiler/pdk.py +23 -16
  16. siliconcompiler/scheduler/scheduler.py +30 -22
  17. siliconcompiler/scheduler/schedulernode.py +60 -50
  18. siliconcompiler/scheduler/taskscheduler.py +52 -32
  19. siliconcompiler/schema/baseschema.py +88 -69
  20. siliconcompiler/schema/docs/schemagen.py +4 -3
  21. siliconcompiler/schema/editableschema.py +5 -5
  22. siliconcompiler/schema/journal.py +19 -13
  23. siliconcompiler/schema/namedschema.py +16 -10
  24. siliconcompiler/schema/parameter.py +64 -37
  25. siliconcompiler/schema/parametervalue.py +126 -80
  26. siliconcompiler/schema/safeschema.py +16 -7
  27. siliconcompiler/schema/utils.py +3 -1
  28. siliconcompiler/schema_support/cmdlineschema.py +9 -9
  29. siliconcompiler/schema_support/dependencyschema.py +12 -7
  30. siliconcompiler/schema_support/filesetschema.py +15 -10
  31. siliconcompiler/schema_support/metric.py +29 -17
  32. siliconcompiler/schema_support/packageschema.py +2 -2
  33. siliconcompiler/schema_support/pathschema.py +30 -18
  34. siliconcompiler/schema_support/record.py +30 -23
  35. siliconcompiler/tool.py +265 -210
  36. siliconcompiler/tools/opensta/timing.py +13 -0
  37. siliconcompiler/tools/yosys/syn_fpga.py +3 -2
  38. siliconcompiler/toolscripts/_tools.json +3 -3
  39. siliconcompiler/utils/__init__.py +23 -16
  40. siliconcompiler/utils/curation.py +11 -5
  41. siliconcompiler/utils/multiprocessing.py +16 -14
  42. siliconcompiler/utils/paths.py +24 -12
  43. siliconcompiler/utils/units.py +16 -12
  44. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/METADATA +3 -4
  45. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/RECORD +49 -48
  46. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/entry_points.txt +4 -3
  47. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/WHEEL +0 -0
  48. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/licenses/LICENSE +0 -0
  49. {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/top_level.txt +0 -0
@@ -5,6 +5,8 @@ import pathlib
5
5
 
6
6
  import os.path
7
7
 
8
+ from typing import Dict, List, Tuple, Union, Optional
9
+
8
10
  from .parametertype import NodeType
9
11
 
10
12
  try:
@@ -23,11 +25,11 @@ class NodeListValue:
23
25
  base (:class:`NodeValue`): base type for this list.
24
26
  '''
25
27
 
26
- def __init__(self, base):
28
+ def __init__(self, base: Union["NodeValue", "FileNodeValue", "DirectoryNodeValue"]):
27
29
  self.__base = base
28
30
  self.__values = []
29
31
 
30
- def getdict(self):
32
+ def getdict(self) -> Dict:
31
33
  """
32
34
  Returns a schema dictionary.
33
35
 
@@ -51,7 +53,10 @@ class NodeListValue:
51
53
  manifest[field] = tmplist
52
54
  return manifest
53
55
 
54
- def _from_dict(self, manifest, keypath, version):
56
+ def _from_dict(self,
57
+ manifest: Dict,
58
+ keypath: Tuple[str, ...],
59
+ version: Optional[Tuple[int, ...]]) -> None:
55
60
  '''
56
61
  Create a new value based on the provided dictionary.
57
62
 
@@ -75,7 +80,7 @@ class NodeListValue:
75
80
  continue
76
81
  param.set(manifest[field][n], field=field)
77
82
 
78
- def get(self, field='value'):
83
+ def get(self, field: Optional[str] = 'value'):
79
84
  """
80
85
  Returns the value in the specified field
81
86
 
@@ -93,7 +98,7 @@ class NodeListValue:
93
98
 
94
99
  return [self.__base.get(field=field)]
95
100
 
96
- def gettcl(self):
101
+ def gettcl(self) -> str:
97
102
  """
98
103
  Returns the tcl representation for the value
99
104
 
@@ -102,7 +107,8 @@ class NodeListValue:
102
107
  """
103
108
  return NodeType.to_tcl(self.get(), self.type)
104
109
 
105
- def set(self, value, field='value'):
110
+ def set(self, value, field: str = 'value') \
111
+ -> Tuple[Union["NodeValue", "FileNodeValue", "DirectoryNodeValue"], ...]:
106
112
  """
107
113
  Sets the value in a specific field and ensures it has been normalized.
108
114
 
@@ -130,7 +136,8 @@ class NodeListValue:
130
136
  modified.append(self.__values[n])
131
137
  return tuple(modified)
132
138
 
133
- def add(self, value, field='value'):
139
+ def add(self, value, field: str = 'value') \
140
+ -> Tuple[Union["NodeValue", "FileNodeValue", "DirectoryNodeValue"], ...]:
134
141
  """
135
142
  Adds the value in a specific field and ensures it has been normalized.
136
143
 
@@ -157,14 +164,14 @@ class NodeListValue:
157
164
  return tuple(modified)
158
165
 
159
166
  @property
160
- def fields(self):
167
+ def fields(self) -> Tuple[Optional[str], ...]:
161
168
  """
162
169
  Returns a list of valid fields for this value
163
170
  """
164
171
  return self.__base.fields
165
172
 
166
173
  @property
167
- def has_value(self):
174
+ def has_value(self) -> bool:
168
175
  """
169
176
  Returns true if this node has a value.
170
177
  """
@@ -174,20 +181,20 @@ class NodeListValue:
174
181
  return self.__base.has_value
175
182
 
176
183
  @property
177
- def values(self):
184
+ def values(self) -> List[Union["NodeValue", "FileNodeValue", "DirectoryNodeValue"]]:
178
185
  '''
179
186
  Returns a copy of the values stored in the list
180
187
  '''
181
188
  return self.__values.copy()
182
189
 
183
- def copy(self):
190
+ def copy(self) -> "NodeListValue":
184
191
  """
185
192
  Returns a copy of this value.
186
193
  """
187
194
 
188
195
  return copy.deepcopy(self)
189
196
 
190
- def _set_type(self, sctype):
197
+ def _set_type(self, sctype) -> None:
191
198
  sctype = NodeType.parse(sctype)[0]
192
199
  self.__base._set_type(sctype)
193
200
  for val in self.__values:
@@ -209,11 +216,11 @@ class NodeSetValue:
209
216
  base (:class:`NodeValue`): base type for this set.
210
217
  '''
211
218
 
212
- def __init__(self, base):
219
+ def __init__(self, base: Union["NodeValue", "FileNodeValue", "DirectoryNodeValue"]):
213
220
  self.__base = base
214
221
  self.__values = []
215
222
 
216
- def getdict(self):
223
+ def getdict(self) -> Dict:
217
224
  """
218
225
  Returns a schema dictionary.
219
226
 
@@ -237,7 +244,10 @@ class NodeSetValue:
237
244
  manifest[field] = tmplist
238
245
  return manifest
239
246
 
240
- def _from_dict(self, manifest, keypath, version):
247
+ def _from_dict(self,
248
+ manifest: Dict,
249
+ keypath: Tuple[str, ...],
250
+ version: Optional[Tuple[int, ...]]) -> None:
241
251
  '''
242
252
  Create a new value based on the provided dictionary.
243
253
 
@@ -261,7 +271,7 @@ class NodeSetValue:
261
271
  continue
262
272
  param.set(manifest[field][n], field=field)
263
273
 
264
- def get(self, field='value'):
274
+ def get(self, field: Optional[str] = 'value'):
265
275
  """
266
276
  Returns the value in the specified field
267
277
 
@@ -281,7 +291,7 @@ class NodeSetValue:
281
291
 
282
292
  return vals
283
293
 
284
- def gettcl(self):
294
+ def gettcl(self) -> str:
285
295
  """
286
296
  Returns the tcl representation for the value
287
297
 
@@ -290,7 +300,8 @@ class NodeSetValue:
290
300
  """
291
301
  return NodeType.to_tcl(self.get(), [self.__base.type])
292
302
 
293
- def set(self, value, field='value'):
303
+ def set(self, value, field: str = 'value') \
304
+ -> Tuple[Union["NodeValue", "FileNodeValue", "DirectoryNodeValue"], ...]:
294
305
  value = NodeType.normalize(value, [self.__base.type])
295
306
 
296
307
  if field == 'value':
@@ -317,7 +328,8 @@ class NodeSetValue:
317
328
  m += 1
318
329
  return tuple(modified)
319
330
 
320
- def add(self, value, field='value'):
331
+ def add(self, value, field: str = 'value') \
332
+ -> Tuple[Union["NodeValue", "FileNodeValue", "DirectoryNodeValue"], ...]:
321
333
  """
322
334
  Adds the value in a specific field and ensures it has been normalized.
323
335
 
@@ -352,7 +364,7 @@ class NodeSetValue:
352
364
  return tuple(modified)
353
365
 
354
366
  @property
355
- def has_value(self):
367
+ def has_value(self) -> bool:
356
368
  """
357
369
  Returns true if this node has a value.
358
370
  """
@@ -362,20 +374,20 @@ class NodeSetValue:
362
374
  return self.__base.has_value
363
375
 
364
376
  @property
365
- def fields(self):
377
+ def fields(self) -> Tuple[Optional[str], ...]:
366
378
  """
367
379
  Returns a list of valid fields for this value
368
380
  """
369
381
  return self.__base.fields
370
382
 
371
383
  @property
372
- def values(self):
384
+ def values(self) -> List[Union["NodeValue", "FileNodeValue", "DirectoryNodeValue"]]:
373
385
  '''
374
386
  Returns a copy of the values stored in the list
375
387
  '''
376
388
  return self.__values.copy()
377
389
 
378
- def copy(self):
390
+ def copy(self) -> "NodeSetValue":
379
391
  """
380
392
  Returns a copy of this value.
381
393
  """
@@ -411,7 +423,11 @@ class NodeValue:
411
423
  self.__signature = None
412
424
 
413
425
  @classmethod
414
- def from_dict(cls, manifest, keypath, version, sctype):
426
+ def from_dict(cls,
427
+ manifest: Dict,
428
+ keypath: Tuple[str, ...],
429
+ version: Optional[Tuple[int, ...]],
430
+ sctype):
415
431
  '''
416
432
  Create a new value based on the provided dictionary.
417
433
 
@@ -427,7 +443,7 @@ class NodeValue:
427
443
  nodeval._from_dict(manifest, keypath, version)
428
444
  return nodeval
429
445
 
430
- def getdict(self):
446
+ def getdict(self) -> Dict:
431
447
  """
432
448
  Returns a schema dictionary.
433
449
 
@@ -441,7 +457,10 @@ class NodeValue:
441
457
  "signature": self.get(field="signature")
442
458
  }
443
459
 
444
- def _from_dict(self, manifest, keypath, version):
460
+ def _from_dict(self,
461
+ manifest: Dict,
462
+ keypath: Tuple[str, ...],
463
+ version: Optional[Tuple[int, ...]]) -> None:
445
464
  '''
446
465
  Copies the information from the manifest into this value.
447
466
 
@@ -454,7 +473,7 @@ class NodeValue:
454
473
  self.set(manifest["value"], field="value")
455
474
  self.set(manifest["signature"], field="signature")
456
475
 
457
- def get(self, field='value'):
476
+ def get(self, field: Optional[str] = 'value'):
458
477
  """
459
478
  Returns the value in the specified field
460
479
 
@@ -469,7 +488,7 @@ class NodeValue:
469
488
  return self.__signature
470
489
  raise ValueError(f"{field} is not a valid field")
471
490
 
472
- def gettcl(self):
491
+ def gettcl(self) -> str:
473
492
  """
474
493
  Returns the tcl representation for the value
475
494
 
@@ -478,7 +497,7 @@ class NodeValue:
478
497
  """
479
498
  return NodeType.to_tcl(self.get(), self.__type)
480
499
 
481
- def set(self, value, field='value'):
500
+ def set(self, value, field: str = 'value') -> "NodeValue":
482
501
  """
483
502
  Sets the value in a specific field and ensures it has been normalized.
484
503
 
@@ -497,14 +516,14 @@ class NodeValue:
497
516
  return self
498
517
  raise ValueError(f"{field} is not a valid field")
499
518
 
500
- def add(self, value, field='value'):
519
+ def add(self, value, field: str = 'value') -> "NodeValue":
501
520
  """
502
521
  Not valid for this datatype, will raise a ValueError
503
522
  """
504
523
  raise ValueError(f"cannot add to {field} field")
505
524
 
506
525
  @property
507
- def has_value(self):
526
+ def has_value(self) -> bool:
508
527
  """
509
528
  Returns true if this node has a value.
510
529
  """
@@ -517,23 +536,23 @@ class NodeValue:
517
536
  return False
518
537
 
519
538
  @property
520
- def fields(self):
539
+ def fields(self) -> Tuple[Optional[str], ...]:
521
540
  """
522
541
  Returns a list of valid fields for this value
523
542
  """
524
543
  return (None, "value", "signature")
525
544
 
526
- def copy(self):
545
+ def copy(self) -> "NodeValue":
527
546
  """
528
547
  Returns a copy of this value.
529
548
  """
530
549
 
531
550
  return copy.deepcopy(self)
532
551
 
533
- def _set_type(self, sctype):
552
+ def _set_type(self, sctype) -> None:
534
553
  self.__type = NodeType.parse(sctype)
535
554
 
536
- def __compute_signature(self, person, key, salt):
555
+ def __compute_signature(self, person: bytes, key: bytes, salt: bytes) -> str:
537
556
  h = blake2b(key=key, salt=salt, person=person)
538
557
  for field in self.fields:
539
558
  if field is None:
@@ -544,7 +563,7 @@ class NodeValue:
544
563
  h.update(str(self.get(field=field)).encode("utf-8"))
545
564
  return h.hexdigest()
546
565
 
547
- def sign(self, person, key, salt=None):
566
+ def sign(self, person: str, key: str, salt: Optional[str] = None) -> None:
548
567
  """
549
568
  Generate a signature for this value.
550
569
 
@@ -556,19 +575,19 @@ class NodeValue:
556
575
  if not _has_sign:
557
576
  raise RuntimeError("encoding not available")
558
577
 
559
- person = person.encode("utf-8")
560
- key = key.encode("utf-8")
578
+ bperson = person.encode("utf-8")
579
+ bkey = key.encode("utf-8")
561
580
  if not salt:
562
- salt = os.urandom(blake2b.SALT_SIZE)
581
+ bsalt = os.urandom(blake2b.SALT_SIZE)
563
582
  else:
564
- salt = salt.encode("utf-8")
583
+ bsalt = salt.encode("utf-8")
565
584
 
566
- digest = self.__compute_signature(person=person, key=key, salt=salt)
567
- encode_person = b64encode(person).decode("utf-8")
568
- encode_salt = b64encode(salt).decode("utf-8")
585
+ digest = self.__compute_signature(person=bperson, key=bkey, salt=bsalt)
586
+ encode_person = b64encode(bperson).decode("utf-8")
587
+ encode_salt = b64encode(bsalt).decode("utf-8")
569
588
  self.__signature = f"{encode_person}:{encode_salt}:{digest}"
570
589
 
571
- def verify_signature(self, person, key):
590
+ def verify_signature(self, person: str, key: str) -> bool:
572
591
  """
573
592
  Verify the signature of this value.
574
593
 
@@ -582,17 +601,17 @@ class NodeValue:
582
601
  if not _has_sign:
583
602
  raise RuntimeError("encoding not available")
584
603
 
585
- key = key.encode("utf-8")
586
- person = person.encode("utf-8")
604
+ bkey = key.encode("utf-8")
605
+ bperson = person.encode("utf-8")
587
606
  encode_person, encode_salt, digest = self.__signature.split(":")
588
- check_person = b64encode(person).decode("utf-8")
607
+ check_person = b64encode(bperson).decode("utf-8")
589
608
 
590
609
  if check_person != encode_person:
591
- raise ValueError(f"{person.decode('utf-8')} does not match signing "
610
+ raise ValueError(f"{person} does not match signing "
592
611
  f"person: {b64decode(encode_person).decode('utf-8')}")
593
612
 
594
613
  decode_salt = b64decode(encode_salt)
595
- check_digest = self.__compute_signature(person=person, key=key, salt=decode_salt)
614
+ check_digest = self.__compute_signature(person=bperson, key=bkey, salt=decode_salt)
596
615
 
597
616
  if check_digest == digest:
598
617
  return True
@@ -615,32 +634,36 @@ class PathNodeValue(NodeValue):
615
634
  value (any): default value for this parameter
616
635
  '''
617
636
 
618
- def __init__(self, type, value=None, dataroot=None):
637
+ def __init__(self, type, value: Optional[Union[str, pathlib.Path]] = None,
638
+ dataroot: Optional[str] = None):
619
639
  super().__init__(type, value=value)
620
640
  self.__filehash = None
621
641
  self.__dataroot = dataroot
622
642
 
623
- def getdict(self):
643
+ def getdict(self) -> Dict:
624
644
  return {
625
645
  **super().getdict(),
626
646
  "filehash": self.get(field="filehash"),
627
647
  "dataroot": self.get(field="dataroot")
628
648
  }
629
649
 
630
- def _from_dict(self, manifest, keypath, version):
650
+ def _from_dict(self,
651
+ manifest: Dict,
652
+ keypath: Tuple[str, ...],
653
+ version: Optional[Tuple[int, ...]]) -> None:
631
654
  super()._from_dict(manifest, keypath, version)
632
655
 
633
656
  self.set(manifest["filehash"], field="filehash")
634
657
  self.set(manifest["dataroot"], field="dataroot")
635
658
 
636
- def get(self, field='value'):
659
+ def get(self, field: Optional[str] = 'value'):
637
660
  if field == 'filehash':
638
661
  return self.__filehash
639
662
  if field == 'dataroot':
640
663
  return self.__dataroot
641
664
  return super().get(field=field)
642
665
 
643
- def set(self, value, field='value'):
666
+ def set(self, value, field: str = 'value') -> "PathNodeValue":
644
667
  if field == 'filehash':
645
668
  self.__filehash = NodeType.normalize(value, "str")
646
669
  return self
@@ -649,7 +672,8 @@ class PathNodeValue(NodeValue):
649
672
  return self
650
673
  return super().set(value, field=field)
651
674
 
652
- def __resolve_collection_path(self, path, collection_dir):
675
+ def __resolve_collection_path(self, path: Union[str, pathlib.Path],
676
+ collection_dir: str) -> Optional[str]:
653
677
  try:
654
678
  collected_paths = os.listdir(collection_dir)
655
679
  if not collected_paths:
@@ -679,7 +703,8 @@ class PathNodeValue(NodeValue):
679
703
 
680
704
  return None
681
705
 
682
- def resolve_path(self, search=None, collection_dir=None) -> str:
706
+ def resolve_path(self, search: Optional[List[str]] = None,
707
+ collection_dir: Optional[str] = None) -> Optional[str]:
683
708
  """
684
709
  Resolve the path of this value.
685
710
 
@@ -689,7 +714,7 @@ class PathNodeValue(NodeValue):
689
714
  search (list of paths): list of paths to search to check for the path.
690
715
  collection_dir (path): path to collection directory.
691
716
  """
692
- value = self.get()
717
+ value: Optional[Union[str, pathlib.Path]] = self.get()
693
718
  if value is None:
694
719
  return None
695
720
 
@@ -715,7 +740,8 @@ class PathNodeValue(NodeValue):
715
740
  raise FileNotFoundError(value)
716
741
 
717
742
  @staticmethod
718
- def generate_hashed_path(path, dataroot):
743
+ def generate_hashed_path(path: Optional[Union[str, pathlib.Path]],
744
+ dataroot: Optional[str]) -> Optional[str]:
719
745
  '''
720
746
  Utility to map file to an unambiguous name based on its path.
721
747
 
@@ -726,11 +752,14 @@ class PathNodeValue(NodeValue):
726
752
  path (str): path to directory or file
727
753
  dataroot (str): name of dataroot this file belongs to
728
754
  '''
729
- path = pathlib.PurePosixPath(path)
730
- ext = ''.join(path.suffixes)
755
+ if path is None:
756
+ return None
757
+
758
+ pure_path = pathlib.PurePosixPath(path)
759
+ ext = ''.join(pure_path.suffixes)
731
760
 
732
761
  # strip off all file suffixes to get just the bare name
733
- barepath = path
762
+ barepath = pure_path
734
763
  while barepath.suffix:
735
764
  barepath = pathlib.PurePosixPath(barepath.stem)
736
765
  filename = str(barepath.parts[-1])
@@ -740,13 +769,13 @@ class PathNodeValue(NodeValue):
740
769
  else:
741
770
  dataroot = f'{dataroot}:'
742
771
 
743
- path_to_hash = f'{dataroot}{str(path.parent)}'
772
+ path_to_hash = f'{dataroot}{str(pure_path.parent)}'
744
773
 
745
774
  pathhash = hashlib.sha1(path_to_hash.encode('utf-8')).hexdigest()
746
775
 
747
776
  return f'{filename}_{pathhash}{ext}'
748
777
 
749
- def get_hashed_filename(self):
778
+ def get_hashed_filename(self) -> Optional[str]:
750
779
  '''
751
780
  Utility to map file to an unambiguous name based on its path.
752
781
 
@@ -755,7 +784,7 @@ class PathNodeValue(NodeValue):
755
784
  '''
756
785
  return PathNodeValue.generate_hashed_path(self.get(), self.__dataroot)
757
786
 
758
- def hash(self, function, **kwargs):
787
+ def hash(self, function: str, **kwargs) -> Optional[str]:
759
788
  """
760
789
  Compute the hash for this path.
761
790
 
@@ -767,7 +796,9 @@ class PathNodeValue(NodeValue):
767
796
  raise NotImplementedError
768
797
 
769
798
  @staticmethod
770
- def hash_directory(dirname, hashobj=None, hashfunction=None):
799
+ def hash_directory(dirname: Optional[Union[str, pathlib.Path]],
800
+ hashobj=None,
801
+ hashfunction: Optional[str] = None) -> Optional[str]:
771
802
  """
772
803
  Compute the hash for this directory.
773
804
 
@@ -781,6 +812,9 @@ class PathNodeValue(NodeValue):
781
812
  return None
782
813
 
783
814
  if not hashobj:
815
+ if hashfunction is None:
816
+ raise ValueError("hashfunction must be a string")
817
+
784
818
  hashfunc = getattr(hashlib, hashfunction, None)
785
819
  if not hashfunc:
786
820
  raise RuntimeError("Unable to hash directory due to missing "
@@ -801,7 +835,9 @@ class PathNodeValue(NodeValue):
801
835
  return dirhash
802
836
 
803
837
  @staticmethod
804
- def hash_file(filename, hashobj=None, hashfunction=None):
838
+ def hash_file(filename: Optional[Union[str, pathlib.Path]],
839
+ hashobj=None,
840
+ hashfunction: Optional[str] = None) -> Optional[str]:
805
841
  """
806
842
  Compute the hash for this file.
807
843
 
@@ -815,6 +851,9 @@ class PathNodeValue(NodeValue):
815
851
  return None
816
852
 
817
853
  if not hashobj:
854
+ if hashfunction is None:
855
+ raise ValueError("hashfunction must be a string")
856
+
818
857
  hashfunc = getattr(hashlib, hashfunction, None)
819
858
  if not hashfunc:
820
859
  raise RuntimeError("Unable to hash file due to missing "
@@ -827,11 +866,11 @@ class PathNodeValue(NodeValue):
827
866
  return hashobj.hexdigest()
828
867
 
829
868
  @property
830
- def fields(self):
869
+ def fields(self) -> Tuple[Optional[str], ...]:
831
870
  return (*super().fields, "filehash", "dataroot")
832
871
 
833
872
  @property
834
- def type(self):
873
+ def type(self) -> str:
835
874
  raise NotImplementedError
836
875
 
837
876
 
@@ -843,10 +882,12 @@ class DirectoryNodeValue(PathNodeValue):
843
882
  value (any): default value for this parameter
844
883
  '''
845
884
 
846
- def __init__(self, value=None, dataroot=None):
885
+ def __init__(self,
886
+ value: Optional[Union[str, pathlib.Path]] = None,
887
+ dataroot: Optional[str] = None):
847
888
  super().__init__("dir", value=value, dataroot=dataroot)
848
889
 
849
- def hash(self, function, **kwargs):
890
+ def hash(self, function: str, **kwargs) -> Optional[str]:
850
891
  """
851
892
  Compute the hash for this directory.
852
893
 
@@ -859,7 +900,7 @@ class DirectoryNodeValue(PathNodeValue):
859
900
  self.resolve_path(**kwargs), hashfunction=function)
860
901
 
861
902
  @property
862
- def type(self):
903
+ def type(self) -> str:
863
904
  return "dir"
864
905
 
865
906
 
@@ -871,32 +912,37 @@ class FileNodeValue(PathNodeValue):
871
912
  value (any): default value for this parameter
872
913
  '''
873
914
 
874
- def __init__(self, value=None, dataroot=None):
915
+ def __init__(self,
916
+ value: Optional[Union[str, pathlib.Path]] = None,
917
+ dataroot: Optional[str] = None):
875
918
  super().__init__("file", value=value, dataroot=dataroot)
876
919
  self.__date = None
877
920
  self.__author = []
878
921
 
879
- def getdict(self):
922
+ def getdict(self) -> Dict:
880
923
  return {
881
924
  **super().getdict(),
882
925
  "date": self.get(field="date"),
883
926
  "author": self.get(field="author")
884
927
  }
885
928
 
886
- def _from_dict(self, manifest, keypath, version):
929
+ def _from_dict(self,
930
+ manifest: Dict,
931
+ keypath: Tuple[str, ...],
932
+ version: Optional[Tuple[int, ...]]) -> None:
887
933
  super()._from_dict(manifest, keypath, version)
888
934
 
889
935
  self.set(manifest["date"], field="date")
890
936
  self.set(manifest["author"], field="author")
891
937
 
892
- def get(self, field='value'):
938
+ def get(self, field: Optional[str] = 'value'):
893
939
  if field == 'date':
894
940
  return self.__date
895
941
  if field == 'author':
896
942
  return self.__author.copy()
897
943
  return super().get(field=field)
898
944
 
899
- def set(self, value, field='value'):
945
+ def set(self, value, field: str = 'value') -> "FileNodeValue":
900
946
  if field == 'date':
901
947
  self.__date = NodeType.normalize(value, "str")
902
948
  return self
@@ -905,7 +951,7 @@ class FileNodeValue(PathNodeValue):
905
951
  return self
906
952
  return super().set(value, field=field)
907
953
 
908
- def add(self, value, field='value'):
954
+ def add(self, value, field: str = 'value') -> "FileNodeValue":
909
955
  """
910
956
  Adds the value in a specific field and ensures it has been normalized.
911
957
 
@@ -922,7 +968,7 @@ class FileNodeValue(PathNodeValue):
922
968
  return self
923
969
  return super().add(value, field=field)
924
970
 
925
- def hash(self, function, **kwargs):
971
+ def hash(self, function: str, **kwargs) -> Optional[str]:
926
972
  """
927
973
  Compute the hash for this file.
928
974
 
@@ -935,9 +981,9 @@ class FileNodeValue(PathNodeValue):
935
981
  self.resolve_path(**kwargs), hashfunction=function)
936
982
 
937
983
  @property
938
- def fields(self):
984
+ def fields(self) -> Tuple[Optional[str], ...]:
939
985
  return (*super().fields, "date", "author")
940
986
 
941
987
  @property
942
- def type(self):
988
+ def type(self) -> str:
943
989
  return "file"