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
@@ -6,6 +6,8 @@ from siliconcompiler import sc_open
6
6
 
7
7
  from siliconcompiler.tools.opensta import OpenSTATask
8
8
 
9
+ from siliconcompiler import TaskSkip
10
+
9
11
 
10
12
  class TimingTaskBase(OpenSTATask):
11
13
  '''
@@ -251,3 +253,14 @@ class FPGATimingTask(TimingTaskBase):
251
253
 
252
254
  self.add_input_file(ext="sdc")
253
255
  self.add_input_file(ext="typical.sdf")
256
+
257
+ def pre_process(self):
258
+ """
259
+ Skip this node if no non-empty sdc files in inputs
260
+ """
261
+ file_path = f"inputs/{self.design_topmodule}.sdc"
262
+
263
+ if os.path.getsize(file_path) == 0:
264
+ raise TaskSkip(f"an empty {self.design_topmodule}.sdc file")
265
+
266
+ super().pre_process()
@@ -17,12 +17,13 @@ class FPGASynthesis(YosysTask):
17
17
  self.add_parameter(
18
18
  "synth_opt_mode",
19
19
  "<none,delay,area>",
20
- "blah",
20
+ "optimization mode: 'none' for a balanced optimization, 'delay' to"
21
+ " prioritize path delay, 'area' to prioritize utilization",
21
22
  "none")
22
23
  self.add_parameter(
23
24
  "synth_insert_buffers",
24
25
  "bool",
25
- "blah",
26
+ "perform buffer insertion",
26
27
  True)
27
28
 
28
29
  def task(self):
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "openroad": {
3
3
  "git-url": "https://github.com/The-OpenROAD-Project/OpenROAD.git",
4
- "git-commit": "0150a2f6ec5cba3046ab28c943897e34e4ec7415",
4
+ "git-commit": "dee927a657e719812a07799b87934328d1e31657",
5
5
  "docker-cmds": [
6
6
  "# Remove OR-Tools files",
7
7
  "RUN rm -f $SC_PREFIX/Makefile $SC_PREFIX/README.md",
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "opensta": {
19
19
  "git-url": "https://github.com/parallaxsw/OpenSTA.git",
20
- "git-commit": "c11bb38f58c34d4f804fd6f05debf644b733ce87",
20
+ "git-commit": "8f8f397610cebc9e647531914a6c071bcccd2757",
21
21
  "auto-update": true
22
22
  },
23
23
  "netgen": {
@@ -157,7 +157,7 @@
157
157
  },
158
158
  "yosys-wildebeest": {
159
159
  "git-url": "https://github.com/zeroasiccorp/wildebeest.git",
160
- "git-commit": "99151b62c6a5d10012d1099bc7ec10674bb0cc7d",
160
+ "git-commit": "d79f06403b500b95b4cb33288f520e4e24fb9c47",
161
161
  "docker-depends": "yosys",
162
162
  "auto-update": true
163
163
  },
@@ -1,4 +1,5 @@
1
1
  import contextlib
2
+ import logging
2
3
  import re
3
4
  import pathlib
4
5
  import psutil
@@ -10,9 +11,9 @@ import os.path
10
11
 
11
12
  from io import StringIO
12
13
  from pathlib import Path
13
- from jinja2 import Environment, FileSystemLoader
14
+ from jinja2 import Environment, FileSystemLoader, Template
14
15
 
15
- from typing import Dict
16
+ from typing import Dict, Optional, Union, Callable, List, TYPE_CHECKING
16
17
 
17
18
  import sys
18
19
  if sys.version_info < (3, 10):
@@ -22,6 +23,9 @@ else:
22
23
 
23
24
  from siliconcompiler.utils.paths import builddir
24
25
 
26
+ if TYPE_CHECKING:
27
+ from siliconcompiler.project import Project
28
+
25
29
 
26
30
  def link_symlink_copy(srcfile, dstfile):
27
31
  # first try hard linking, then symbolic linking,
@@ -191,7 +195,7 @@ def default_email_credentials_file() -> str:
191
195
 
192
196
 
193
197
  @contextlib.contextmanager
194
- def sc_open(path, *args, **kwargs):
198
+ def sc_open(path: str, *args, **kwargs):
195
199
  if 'errors' not in kwargs:
196
200
  kwargs['errors'] = 'ignore'
197
201
  kwargs["newline"] = "\n"
@@ -203,12 +207,12 @@ def sc_open(path, *args, **kwargs):
203
207
  pass
204
208
 
205
209
 
206
- def get_file_template(path,
207
- root=os.path.join(
210
+ def get_file_template(path: str,
211
+ root: str = os.path.join(
208
212
  os.path.dirname(
209
213
  os.path.dirname(os.path.abspath(__file__))),
210
214
  'data',
211
- 'templates')):
215
+ 'templates')) -> Template:
212
216
  if os.path.isabs(path):
213
217
  root = os.path.dirname(path)
214
218
  path = os.path.basename(path)
@@ -221,7 +225,7 @@ def get_file_template(path,
221
225
 
222
226
 
223
227
  #######################################
224
- def safecompare(value, op, goal):
228
+ def safecompare(value: Union[int, float], op: str, goal: Union[int, float]) -> bool:
225
229
  # supported relational operations
226
230
  # >, >=, <=, <. ==, !=
227
231
  if op == ">":
@@ -241,7 +245,7 @@ def safecompare(value, op, goal):
241
245
 
242
246
 
243
247
  ###########################################################################
244
- def grep(project, args, line):
248
+ def grep(project: "Project", args: str, line: str) -> Union[None, str]:
245
249
  """
246
250
  Emulates the Unix grep command on a string.
247
251
 
@@ -275,6 +279,9 @@ def grep(project, args, line):
275
279
  # Split into repeating switches and everything else
276
280
  match = re.match(r'\s*((?:\-\w\s)*)(.*)', args)
277
281
 
282
+ if not match:
283
+ return None
284
+
278
285
  pattern = match.group(2)
279
286
 
280
287
  # Split space separated switch string into list
@@ -302,7 +309,7 @@ def grep(project, args, line):
302
309
  return line
303
310
 
304
311
 
305
- def get_plugins(system, name=None):
312
+ def get_plugins(system: str, name: Optional[str] = None) -> List[Callable]:
306
313
  '''
307
314
  Search for python modules with a specific function
308
315
  '''
@@ -319,7 +326,7 @@ def get_plugins(system, name=None):
319
326
  return plugins
320
327
 
321
328
 
322
- def truncate_text(text, width):
329
+ def truncate_text(text: str, width: int) -> str:
323
330
  width = max(width, 5)
324
331
 
325
332
  if len(text) <= width:
@@ -338,7 +345,7 @@ def truncate_text(text, width):
338
345
  return text
339
346
 
340
347
 
341
- def get_cores(physical=False):
348
+ def get_cores(physical: bool = False) -> int:
342
349
  '''
343
350
  Get max number of cores for this machine.
344
351
 
@@ -360,7 +367,7 @@ def get_cores(physical=False):
360
367
  return cores
361
368
 
362
369
 
363
- def print_traceback(logger, exception):
370
+ def print_traceback(logger: logging.Logger, exception: Exception):
364
371
  logger.error(f'{exception}')
365
372
  trace = StringIO()
366
373
  traceback.print_tb(exception.__traceback__, file=trace)
@@ -370,21 +377,21 @@ def print_traceback(logger, exception):
370
377
 
371
378
 
372
379
  class FilterDirectories:
373
- def __init__(self, project):
380
+ def __init__(self, project: "Project"):
374
381
  self.file_count = 0
375
382
  self.directory_file_limit = None
376
383
  self.abspath = None
377
384
  self.project = project
378
385
 
379
386
  @property
380
- def logger(self):
387
+ def logger(self) -> logging.Logger:
381
388
  return self.project.logger
382
389
 
383
390
  @property
384
- def builddir(self):
391
+ def builddir(self) -> str:
385
392
  return builddir(self.project)
386
393
 
387
- def filter(self, path, files):
394
+ def filter(self, path: str, files: List[str]) -> List[str]:
388
395
  if pathlib.Path(path) == pathlib.Path.home():
389
396
  # refuse to collect home directory
390
397
  self.logger.error(f'Cannot collect user home directory: {path}')
@@ -3,7 +3,7 @@ import tarfile
3
3
 
4
4
  import os.path
5
5
 
6
- from typing import List
6
+ from typing import List, Optional, TYPE_CHECKING
7
7
 
8
8
  from siliconcompiler.schema.parametervalue import NodeListValue, NodeSetValue
9
9
  from siliconcompiler.utils import FilterDirectories
@@ -11,11 +11,14 @@ from siliconcompiler.utils.paths import collectiondir
11
11
  from siliconcompiler.scheduler import SchedulerNode
12
12
  from siliconcompiler.flowgraph import RuntimeFlowgraph
13
13
 
14
+ if TYPE_CHECKING:
15
+ from siliconcompiler.project import Project
14
16
 
15
- def collect(project,
16
- directory: str = None,
17
+
18
+ def collect(project: "Project",
19
+ directory: Optional[str] = None,
17
20
  verbose: bool = True,
18
- whitelist: List[str] = None):
21
+ whitelist: Optional[List[str]] = None) -> None:
19
22
  '''
20
23
  Collects files and directories specified in the schema and places
21
24
  them in a collection directory. The function only copies items that have
@@ -165,7 +168,10 @@ def collect(project,
165
168
  shutil.copy2(abs_path, import_path)
166
169
 
167
170
 
168
- def archive(project, jobname: str = None, include: List[str] = None, archive_name: str = None):
171
+ def archive(project: "Project",
172
+ jobname: Optional[str] = None,
173
+ include: Optional[List[str]] = None,
174
+ archive_name: Optional[str] = None) -> None:
169
175
  '''Archive a job directory into a compressed tarball.
170
176
 
171
177
  Creates a single compressed archive (.tgz) based on the specified job.
@@ -5,6 +5,8 @@ import tempfile
5
5
 
6
6
  import os.path
7
7
 
8
+ from typing import Union, Optional
9
+
8
10
  from datetime import datetime
9
11
  from multiprocessing.managers import SyncManager
10
12
 
@@ -29,7 +31,7 @@ class _ManagerSingleton(type):
29
31
  _lock = multiprocessing.Lock()
30
32
 
31
33
  @staticmethod
32
- def has_cls(cls):
34
+ def has_cls(mcls):
33
35
  """
34
36
  Checks if a singleton instance exists for the given class.
35
37
 
@@ -39,10 +41,10 @@ class _ManagerSingleton(type):
39
41
  Returns:
40
42
  bool: True if an instance exists, False otherwise.
41
43
  """
42
- return cls in _ManagerSingleton._instances
44
+ return mcls in _ManagerSingleton._instances
43
45
 
44
46
  @staticmethod
45
- def remove_cls(cls):
47
+ def remove_cls(mcls):
46
48
  """
47
49
  Removes a class's singleton instance from the registry.
48
50
 
@@ -52,12 +54,12 @@ class _ManagerSingleton(type):
52
54
  Args:
53
55
  cls (type): The class whose instance should be removed.
54
56
  """
55
- if not _ManagerSingleton.has_cls(cls):
57
+ if not _ManagerSingleton.has_cls(mcls):
56
58
  return
57
59
 
58
60
  with _ManagerSingleton._lock:
59
- if cls in _ManagerSingleton._instances:
60
- del _ManagerSingleton._instances[cls]
61
+ if mcls in _ManagerSingleton._instances:
62
+ del _ManagerSingleton._instances[mcls]
61
63
 
62
64
  def __call__(cls, *args, **kwargs):
63
65
  """
@@ -86,7 +88,7 @@ class MPManager(metaclass=_ManagerSingleton):
86
88
  It is designed to be instantiated once and accessed globally.
87
89
  """
88
90
  __ENABLE_LOGGER: bool = True
89
- __address: str = None
91
+ __address: Union[None, str] = None
90
92
  __authkey: bytes = b'siliconcompiler-manager-authkey' # arbitrary authkey value
91
93
 
92
94
  def __init__(self):
@@ -98,7 +100,7 @@ class MPManager(metaclass=_ManagerSingleton):
98
100
  """
99
101
  pass
100
102
 
101
- def _init_singleton(self):
103
+ def _init_singleton(self) -> None:
102
104
  """
103
105
  Performs the one-time initialization of the singleton instance.
104
106
 
@@ -140,7 +142,7 @@ class MPManager(metaclass=_ManagerSingleton):
140
142
  # Register cleanup function to run at exit
141
143
  atexit.register(MPManager.stop)
142
144
 
143
- def _init_logger(self):
145
+ def _init_logger(self) -> None:
144
146
  """
145
147
  Initializes the logging configuration for SiliconCompiler.
146
148
 
@@ -175,7 +177,7 @@ class MPManager(metaclass=_ManagerSingleton):
175
177
  pass
176
178
 
177
179
  @staticmethod
178
- def stop():
180
+ def stop() -> None:
179
181
  """
180
182
  Cleans up all managed resources as a static method.
181
183
 
@@ -220,7 +222,7 @@ class MPManager(metaclass=_ManagerSingleton):
220
222
  _ManagerSingleton.remove_cls(MPManager)
221
223
 
222
224
  @staticmethod
223
- def error(msg: str = None):
225
+ def error(msg: Optional[str] = None):
224
226
  """
225
227
  Logs an error and flags the session as having an error.
226
228
 
@@ -238,7 +240,7 @@ class MPManager(metaclass=_ManagerSingleton):
238
240
  manager.__error = True
239
241
 
240
242
  @staticmethod
241
- def get_manager():
243
+ def get_manager() -> SyncManager:
242
244
  """
243
245
  Provides access to the shared multiprocessing.Manager instance.
244
246
 
@@ -277,7 +279,7 @@ class MPManager(metaclass=_ManagerSingleton):
277
279
  return MPManager().__logger
278
280
 
279
281
  @staticmethod
280
- def _set_manager_address(address: str):
282
+ def _set_manager_address(address: str) -> None:
281
283
  """
282
284
  Set the address of the manager
283
285
  """
@@ -285,7 +287,7 @@ class MPManager(metaclass=_ManagerSingleton):
285
287
  MPManager.__address = address
286
288
 
287
289
  @staticmethod
288
- def _get_manager_address() -> str:
290
+ def _get_manager_address() -> Union[None, str]:
289
291
  """
290
292
  Get the address of the manager
291
293
  """
@@ -1,9 +1,19 @@
1
1
  import os.path
2
2
 
3
- from typing import Union
3
+ from typing import Union, Optional, TYPE_CHECKING
4
4
 
5
+ if TYPE_CHECKING:
6
+ from siliconcompiler.project import Project
5
7
 
6
- def builddir(project) -> str:
8
+
9
+ def cwdir(project: "Project") -> str:
10
+ from siliconcompiler import Project
11
+ if not isinstance(project, Project):
12
+ raise TypeError("project must be a Project type")
13
+ return project._Project__cwd
14
+
15
+
16
+ def builddir(project: "Project") -> str:
7
17
  """
8
18
  Returns the absolute path to the project's build directory.
9
19
 
@@ -24,14 +34,14 @@ def builddir(project) -> str:
24
34
  if not isinstance(project, Project):
25
35
  raise TypeError("project must be a Project type")
26
36
 
27
- builddir = project.get('option', 'builddir')
37
+ builddir: str = project.get('option', 'builddir')
28
38
  if os.path.isabs(builddir):
29
39
  return builddir
30
40
 
31
- return os.path.join(project._Project__cwd, builddir)
41
+ return os.path.join(cwdir(project), builddir)
32
42
 
33
43
 
34
- def jobdir(project) -> str:
44
+ def jobdir(project: "Project") -> str:
35
45
  """
36
46
  Returns the absolute path to the current job directory.
37
47
 
@@ -55,13 +65,15 @@ def jobdir(project) -> str:
55
65
  if not project.name:
56
66
  raise ValueError("name has not been set")
57
67
 
58
- return os.path.join(
59
- builddir(project),
60
- project.name,
61
- project.get('option', 'jobname'))
68
+ jobname: str = project.get('option', 'jobname')
69
+
70
+ return os.path.join(builddir(project), project.name, jobname)
62
71
 
63
72
 
64
- def workdir(project, step: str = None, index: Union[int, str] = None, relpath: bool = False) -> str:
73
+ def workdir(project: "Project",
74
+ step: Optional[str] = None,
75
+ index: Optional[Union[int, str]] = None,
76
+ relpath: Optional[bool] = False) -> str:
65
77
  """
66
78
  Returns path to the working directory for a given step and index.
67
79
 
@@ -100,12 +112,12 @@ def workdir(project, step: str = None, index: Union[int, str] = None, relpath: b
100
112
 
101
113
  path = os.path.join(jobdir(project), *dirlist)
102
114
  if relpath:
103
- return os.path.relpath(path, project._Project__cwd)
115
+ return os.path.relpath(path, cwdir(project))
104
116
 
105
117
  return path
106
118
 
107
119
 
108
- def collectiondir(project) -> str:
120
+ def collectiondir(project: "Project") -> Union[None, str]:
109
121
  """
110
122
  Returns the absolute path to the file collection directory.
111
123
 
@@ -1,6 +1,8 @@
1
1
  import math
2
2
  import re
3
3
 
4
+ from typing import Optional, Tuple
5
+
4
6
  SI_UNITS = (
5
7
  ('y', -24),
6
8
  ('z', -21),
@@ -51,7 +53,7 @@ BINARY_TYPES = (
51
53
  )
52
54
 
53
55
 
54
- def convert(value, from_unit=None, to_unit=None):
56
+ def convert(value: float, from_unit: Optional[str] = None, to_unit: Optional[str] = None) -> float:
55
57
  '''
56
58
  Convert a value to from one SI power to another SI power
57
59
 
@@ -80,7 +82,7 @@ def convert(value, from_unit=None, to_unit=None):
80
82
  return value * scale
81
83
 
82
84
 
83
- def _get_scale(unit):
85
+ def _get_scale(unit: Optional[str]) -> int:
84
86
  if not unit:
85
87
  unit = ''
86
88
  unit_prefix = get_si_prefix(unit)
@@ -91,7 +93,7 @@ def _get_scale(unit):
91
93
  return 1
92
94
 
93
95
 
94
- def get_si_prefix(unit):
96
+ def get_si_prefix(unit: Optional[str]) -> str:
95
97
  '''
96
98
  Get the SI prefix of the specific unit.
97
99
 
@@ -107,8 +109,10 @@ def get_si_prefix(unit):
107
109
  if matches:
108
110
  return matches[0][0]
109
111
 
112
+ return ''
113
+
110
114
 
111
- def get_si_power(unit):
115
+ def get_si_power(unit: Optional[str]) -> int:
112
116
  '''
113
117
  Get the SI power of the specific unit.
114
118
  This is mainly needed for area units.
@@ -129,28 +133,28 @@ def get_si_power(unit):
129
133
  return 1
130
134
 
131
135
 
132
- def is_base_si_unit(unit):
136
+ def is_base_si_unit(unit: Optional[str]) -> bool:
133
137
  '''
134
138
  Check if a unit has no magnitude
135
139
  '''
136
140
  return unit in SI_TYPES
137
141
 
138
142
 
139
- def is_base_si_unit_power(unit):
143
+ def is_base_si_unit_power(unit: Optional[str]) -> bool:
140
144
  '''
141
145
  Check if a unit has a power associated with it
142
146
  '''
143
147
  return get_si_power(unit) > 1
144
148
 
145
149
 
146
- def is_base_binary_unit(unit):
150
+ def is_base_binary_unit(unit: Optional[str]) -> bool:
147
151
  '''
148
152
  Check if a unit is binary
149
153
  '''
150
154
  return unit in BINARY_TYPES
151
155
 
152
156
 
153
- def format_si(value, unit, margin=3, digits=3):
157
+ def format_si(value: float, unit: str, margin: int = 3, digits: int = 3) -> str:
154
158
  '''
155
159
  Format a number as an SI number. Returns a string.
156
160
 
@@ -171,7 +175,7 @@ def format_si(value, unit, margin=3, digits=3):
171
175
  return f'{scaled_value:.{digits}f}{prefix}'
172
176
 
173
177
 
174
- def scale_si(value, unit, margin=3, digits=3):
178
+ def scale_si(value: float, unit: str, margin: int = 3, digits: int = 3) -> Tuple[float, str]:
175
179
  '''
176
180
  Format a number as an SI number. Returns a float.
177
181
 
@@ -200,7 +204,7 @@ def scale_si(value, unit, margin=3, digits=3):
200
204
  return (float(f'{value:.{digits}f}'), '')
201
205
 
202
206
 
203
- def format_binary(value, unit, digits=3):
207
+ def format_binary(value: float, unit: Optional[str], digits: int = 3) -> str:
204
208
  '''
205
209
  Format a number as a binary number. Returns a string.
206
210
 
@@ -214,7 +218,7 @@ def format_binary(value, unit, digits=3):
214
218
  return f'{scaled_value:.{digits}f}{prefix}'
215
219
 
216
220
 
217
- def scale_binary(value, unit, digits=3):
221
+ def scale_binary(value: float, unit: Optional[str], digits: int = 3) -> Tuple[float, str]:
218
222
  '''
219
223
  Format a number as a binary number. Returns a float.
220
224
 
@@ -239,7 +243,7 @@ def scale_binary(value, unit, digits=3):
239
243
  return (float(f'{value:.{digits}f}'), '')
240
244
 
241
245
 
242
- def format_time(value):
246
+ def format_time(value: float) -> str:
243
247
  '''
244
248
  Format a number as time.
245
249
  Prints as hh:mm:ss.ms (hours:minutes:seconds.milliseconds)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: siliconcompiler
3
- Version: 0.35.0
3
+ Version: 0.35.1
4
4
  Summary: A compiler framework that automates translation from source code to silicon.
5
5
  Author: Zero ASIC
6
6
  License: Apache License 2.0
@@ -24,7 +24,7 @@ Classifier: Topic :: Software Development :: Build Tools
24
24
  Requires-Python: >=3.9
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE
27
- Requires-Dist: aiohttp<3.13.0,>=3.10.11
27
+ Requires-Dist: aiohttp<3.14.0,>=3.10.11
28
28
  Requires-Dist: distro<2.0.0,>=1.9.0
29
29
  Requires-Dist: docker<8.0.0,>=7.1.0
30
30
  Requires-Dist: fastjsonschema<2.22.0,>=2.20.0
@@ -37,7 +37,7 @@ Requires-Dist: PyYAML<7.0.0,>=6.0.0
37
37
  Requires-Dist: GitPython<3.2,>=3.1.44
38
38
  Requires-Dist: PyGithub<2.9.0,>=2.8.0
39
39
  Requires-Dist: urllib3>=1.26.0
40
- Requires-Dist: lambdapdk>=0.2.0
40
+ Requires-Dist: lambdapdk>=0.2.1
41
41
  Requires-Dist: fasteners>=0.20
42
42
  Requires-Dist: pandas>=1.1.5
43
43
  Requires-Dist: psutil>=5.8.0
@@ -58,7 +58,6 @@ Requires-Dist: pytest-asyncio==1.2.0; extra == "test"
58
58
  Requires-Dist: pytest-cov==7.0.0; extra == "test"
59
59
  Requires-Dist: responses==0.25.8; extra == "test"
60
60
  Requires-Dist: PyVirtualDisplay==3.0; extra == "test"
61
- Requires-Dist: logiklib==0.1.0; extra == "test"
62
61
  Provides-Extra: lint
63
62
  Requires-Dist: flake8==7.3.0; extra == "lint"
64
63
  Requires-Dist: tclint==0.6.1; extra == "lint"