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.
- siliconcompiler/_metadata.py +1 -1
- siliconcompiler/apps/_common.py +3 -2
- siliconcompiler/apps/sc_dashboard.py +3 -1
- siliconcompiler/apps/sc_install.py +149 -37
- siliconcompiler/apps/smake.py +9 -3
- siliconcompiler/checklist.py +3 -3
- siliconcompiler/data/demo_fpga/z1000_yosys_config.json +24 -0
- siliconcompiler/design.py +51 -45
- siliconcompiler/flowgraph.py +2 -2
- siliconcompiler/library.py +23 -12
- siliconcompiler/package/__init__.py +77 -49
- siliconcompiler/package/git.py +11 -6
- siliconcompiler/package/github.py +11 -6
- siliconcompiler/package/https.py +6 -4
- siliconcompiler/pdk.py +23 -16
- siliconcompiler/scheduler/scheduler.py +30 -22
- siliconcompiler/scheduler/schedulernode.py +60 -50
- siliconcompiler/scheduler/taskscheduler.py +52 -32
- siliconcompiler/schema/baseschema.py +88 -69
- siliconcompiler/schema/docs/schemagen.py +4 -3
- siliconcompiler/schema/editableschema.py +5 -5
- siliconcompiler/schema/journal.py +19 -13
- siliconcompiler/schema/namedschema.py +16 -10
- siliconcompiler/schema/parameter.py +64 -37
- siliconcompiler/schema/parametervalue.py +126 -80
- siliconcompiler/schema/safeschema.py +16 -7
- siliconcompiler/schema/utils.py +3 -1
- siliconcompiler/schema_support/cmdlineschema.py +9 -9
- siliconcompiler/schema_support/dependencyschema.py +12 -7
- siliconcompiler/schema_support/filesetschema.py +15 -10
- siliconcompiler/schema_support/metric.py +29 -17
- siliconcompiler/schema_support/packageschema.py +2 -2
- siliconcompiler/schema_support/pathschema.py +30 -18
- siliconcompiler/schema_support/record.py +30 -23
- siliconcompiler/tool.py +265 -210
- siliconcompiler/tools/opensta/timing.py +13 -0
- siliconcompiler/tools/yosys/syn_fpga.py +3 -2
- siliconcompiler/toolscripts/_tools.json +3 -3
- siliconcompiler/utils/__init__.py +23 -16
- siliconcompiler/utils/curation.py +11 -5
- siliconcompiler/utils/multiprocessing.py +16 -14
- siliconcompiler/utils/paths.py +24 -12
- siliconcompiler/utils/units.py +16 -12
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/METADATA +3 -4
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/RECORD +49 -48
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/entry_points.txt +4 -3
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/WHEEL +0 -0
- {siliconcompiler-0.35.0.dist-info → siliconcompiler-0.35.1.dist-info}/licenses/LICENSE +0 -0
- {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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
560
|
-
|
|
578
|
+
bperson = person.encode("utf-8")
|
|
579
|
+
bkey = key.encode("utf-8")
|
|
561
580
|
if not salt:
|
|
562
|
-
|
|
581
|
+
bsalt = os.urandom(blake2b.SALT_SIZE)
|
|
563
582
|
else:
|
|
564
|
-
|
|
583
|
+
bsalt = salt.encode("utf-8")
|
|
565
584
|
|
|
566
|
-
digest = self.__compute_signature(person=
|
|
567
|
-
encode_person = b64encode(
|
|
568
|
-
encode_salt = b64encode(
|
|
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
|
-
|
|
586
|
-
|
|
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(
|
|
607
|
+
check_person = b64encode(bperson).decode("utf-8")
|
|
589
608
|
|
|
590
609
|
if check_person != encode_person:
|
|
591
|
-
raise ValueError(f"{person
|
|
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=
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
730
|
-
|
|
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 =
|
|
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(
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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"
|