siliconcompiler 0.29.4__py3-none-any.whl → 0.30.0__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 (35) hide show
  1. siliconcompiler/_metadata.py +1 -1
  2. siliconcompiler/apps/sc.py +1 -1
  3. siliconcompiler/apps/sc_install.py +28 -0
  4. siliconcompiler/core.py +15 -4
  5. siliconcompiler/schema/schema_cfg.py +149 -92
  6. siliconcompiler/tools/__init__.py +3 -1
  7. siliconcompiler/tools/bluespec/__init__.py +35 -0
  8. siliconcompiler/tools/bluespec/convert.py +44 -5
  9. siliconcompiler/tools/graphviz/__init__.py +12 -0
  10. siliconcompiler/tools/graphviz/screenshot.py +48 -0
  11. siliconcompiler/tools/graphviz/show.py +20 -0
  12. siliconcompiler/tools/openroad/_apr.py +6 -0
  13. siliconcompiler/tools/openroad/macro_placement.py +9 -0
  14. siliconcompiler/tools/openroad/power_grid.py +6 -0
  15. siliconcompiler/tools/openroad/scripts/apr/sc_clock_tree_synthesis.tcl +2 -0
  16. siliconcompiler/tools/openroad/scripts/apr/sc_detailed_route.tcl +2 -0
  17. siliconcompiler/tools/openroad/scripts/apr/sc_global_route.tcl +15 -5
  18. siliconcompiler/tools/openroad/scripts/apr/sc_macro_placement.tcl +9 -1
  19. siliconcompiler/tools/openroad/scripts/apr/sc_power_grid.tcl +53 -0
  20. siliconcompiler/tools/openroad/scripts/common/procs.tcl +26 -5
  21. siliconcompiler/tools/openroad/scripts/common/reports.tcl +10 -3
  22. siliconcompiler/toolscripts/_tools.json +4 -4
  23. siliconcompiler/toolscripts/rhel9/install-openroad.sh +1 -1
  24. siliconcompiler/toolscripts/ubuntu20/install-openroad.sh +1 -1
  25. siliconcompiler/toolscripts/ubuntu22/install-openroad.sh +1 -1
  26. siliconcompiler/toolscripts/ubuntu24/install-openroad.sh +1 -1
  27. siliconcompiler/utils/__init__.py +11 -0
  28. siliconcompiler/utils/showtools.py +7 -0
  29. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.30.0.dist-info}/METADATA +5 -5
  30. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.30.0.dist-info}/RECORD +34 -32
  31. siliconcompiler/tools/bluespec/bluespec.py +0 -40
  32. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.30.0.dist-info}/LICENSE +0 -0
  33. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.30.0.dist-info}/WHEEL +0 -0
  34. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.30.0.dist-info}/entry_points.txt +0 -0
  35. {siliconcompiler-0.29.4.dist-info → siliconcompiler-0.30.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,20 @@
1
+ from PIL import Image
2
+ from siliconcompiler.tools.graphviz import screenshot
3
+
4
+
5
+ def setup(chip):
6
+ '''
7
+ Show a graphviz dot file
8
+ '''
9
+
10
+ screenshot.setup(chip)
11
+
12
+
13
+ def run(chip):
14
+ screenshot_ret = screenshot.run(chip)
15
+ if screenshot_ret != 0:
16
+ return screenshot_ret
17
+
18
+ Image.open(f"outputs/{chip.top()}.png").show()
19
+
20
+ return 0
@@ -128,6 +128,8 @@ def extract_metrics(chip):
128
128
  "drvs": [
129
129
  "timing/drv_violators.rpt",
130
130
  "floating_nets.rpt",
131
+ "overdriven_nets.rpt",
132
+ "overdriven_nets_with_parallel.rpt",
131
133
  f"{chip.design}_antenna.rpt",
132
134
  f"{chip.design}_antenna_post_repair.rpt"
133
135
  ],
@@ -281,6 +283,10 @@ def extract_metrics(chip):
281
283
  'sc__metric__timing__drv__max_slew',
282
284
  'sc__metric__timing__drv__max_cap',
283
285
  'sc__metric__timing__drv__max_fanout',
286
+ 'sc__metric__timing__drv__max_fanout',
287
+ 'sc__metric__timing__drv__floating__nets',
288
+ 'sc__metric__timing__drv__floating__pins',
289
+ 'sc__metric__timing__drv__overdriven__nets',
284
290
  'sc__metric__antenna__violating__nets',
285
291
  'sc__metric__antenna__violating__pins']:
286
292
  if metric in metrics:
@@ -43,6 +43,15 @@ def setup(chip):
43
43
  'unconstrained'
44
44
  ])
45
45
 
46
+ chip.set('tool', tool, 'task', task, 'file', 'rtlmp_constraints',
47
+ 'contraints script for macro placement',
48
+ field='help')
49
+
50
+ if chip.get('tool', tool, 'task', task, 'file', 'rtlmp_constraints', step=step, index=index):
51
+ chip.add('tool', tool, 'task', task, 'require',
52
+ ",".join(['tool', tool, 'task', task, 'file', 'rtlmp_constraints']),
53
+ step=step, index=index)
54
+
46
55
 
47
56
  def pre_process(chip):
48
57
  step = chip.get('arg', 'step')
@@ -1,6 +1,7 @@
1
1
  from siliconcompiler import NodeStatus
2
2
 
3
3
  from siliconcompiler.tools._common import get_tool_task, has_pre_post_script
4
+ from siliconcompiler.tools._common.asic import set_tool_task_var
4
5
 
5
6
  from siliconcompiler.tools.openroad._apr import setup as apr_setup
6
7
  from siliconcompiler.tools.openroad._apr import set_reports, set_pnr_inputs, set_pnr_outputs
@@ -39,6 +40,11 @@ def setup(chip):
39
40
  define_pdn_params(chip)
40
41
  define_psm_params(chip)
41
42
 
43
+ set_tool_task_var(chip, param_key='fixed_pin_keepout',
44
+ default_value=0,
45
+ schelp='if > 0, applies a blockage in multiples of the routing pitch '
46
+ 'to each fixed pin to ensure there is room for routing.')
47
+
42
48
  set_reports(chip, [])
43
49
 
44
50
 
@@ -43,6 +43,8 @@ if { [llength [all_clocks]] > 0 } {
43
43
  -distance_between_buffers $cts_distance_between_buffers \
44
44
  {*}$sc_cts_arguments
45
45
 
46
+ tee -file reports/cts.rpt {report_cts}
47
+
46
48
  set_propagated_clock [all_clocks]
47
49
 
48
50
  estimate_parasitics -placement
@@ -15,6 +15,8 @@ source -echo "$sc_refdir/apr/preamble.tcl"
15
15
  # Detailed Routing
16
16
  ###############################
17
17
 
18
+ sc_setup_detailed_route
19
+
18
20
  set drt_arguments []
19
21
  if { [lindex [sc_cfg_tool_task_get {var} drt_disable_via_gen] 0] == "true" } {
20
22
  lappend drt_arguments "-disable_via_gen"
@@ -16,6 +16,8 @@ source -echo "$sc_refdir/apr/preamble.tcl"
16
16
  ###############################
17
17
 
18
18
  if { [lindex [sc_cfg_tool_task_get {var} grt_use_pin_access] 0] == "true" } {
19
+ sc_setup_detailed_route
20
+
19
21
  set sc_minmetal [sc_cfg_get pdk $sc_pdk minlayer $sc_stackup]
20
22
  set sc_minmetal [sc_get_layer_name $sc_minmetal]
21
23
  set sc_maxmetal [sc_cfg_get pdk $sc_pdk maxlayer $sc_stackup]
@@ -45,11 +47,19 @@ if { [lindex [sc_cfg_tool_task_get {var} grt_allow_overflow] 0] == "true" } {
45
47
  lappend sc_grt_arguments "-allow_overflow"
46
48
  }
47
49
 
48
- global_route -guide_file "reports/route.guide" \
49
- -congestion_iterations [lindex [sc_cfg_tool_task_get {var} grt_overflow_iter] 0] \
50
- -congestion_report_file "reports/${sc_design}_congestion.rpt" \
51
- -verbose \
52
- {*}$sc_grt_arguments
50
+ if {
51
+ [catch {
52
+ global_route -guide_file "reports/route.guide" \
53
+ -congestion_iterations [lindex [sc_cfg_tool_task_get {var} grt_overflow_iter] 0] \
54
+ -congestion_report_file "reports/${sc_design}_congestion.rpt" \
55
+ -verbose \
56
+ {*}$sc_grt_arguments
57
+ }]
58
+ } {
59
+ write_db "reports/${sc_design}.globalroute-error.odb"
60
+ utl::error FLW 1 \
61
+ "Global routing failed, saving database to reports/${sc_design}.globalroute-error.odb"
62
+ }
53
63
 
54
64
  # estimate for metrics
55
65
  estimate_parasitics -global_routing
@@ -11,6 +11,14 @@ source ./sc_manifest.tcl > /dev/null
11
11
  set sc_refdir [sc_cfg_tool_task_get refdir]
12
12
  source -echo "$sc_refdir/apr/preamble.tcl"
13
13
 
14
+ ###############################
15
+ # Macro placement constraints
16
+ ###############################
17
+ foreach script [sc_cfg_tool_task_get file rtlmp_constraints] {
18
+ puts "Sourcing macro placement constraints: $script"
19
+ source -echo $script
20
+ }
21
+
14
22
  # Need to check if we have any macros before performing macro placement,
15
23
  # since we get an error otherwise.
16
24
  if { [sc_design_has_unplaced_macros] } {
@@ -94,7 +102,7 @@ if { [sc_design_has_unplaced_macros] } {
94
102
  -report_directory reports/rtlmp \
95
103
  -halo_width $halo_x \
96
104
  -halo_height $halo_y \
97
- -target_util [sc_global_placement_density] \
105
+ -target_util [sc_global_placement_density -exclude_padding] \
98
106
  {*}$rtlmp_args
99
107
  }
100
108
 
@@ -19,6 +19,48 @@ if { [sc_design_has_unplaced_macros] } {
19
19
  utl::error FLW 1 "Design contains unplaced macros."
20
20
  }
21
21
 
22
+ ###############################
23
+ # Add blockages
24
+ ###############################
25
+
26
+ set pdn_blockages []
27
+ set pdn_pin_keepout [lindex [sc_cfg_tool_task_get var fixed_pin_keepout] 0]
28
+ if { $pdn_pin_keepout > 0 } {
29
+ foreach bterm [[ord::get_db_block] getBTerms] {
30
+ foreach bpin [$bterm getBPins] {
31
+ if {
32
+ [$bpin getPlacementStatus] != "FIRM" &&
33
+ [$bpin getPlacementStatus] != "LOCKED"
34
+ } {
35
+ continue
36
+ }
37
+
38
+ foreach box [$bpin getBoxes] {
39
+ set layer [$box getTechLayer]
40
+ if { $layer == "NULL" } {
41
+ continue
42
+ }
43
+
44
+ set tech_pitch [expr { [$layer getPitch] * $pdn_pin_keepout }]
45
+
46
+ set xmin [expr { [$box xMin] - $tech_pitch }]
47
+ set xmax [expr { [$box xMax] + $tech_pitch }]
48
+ set ymin [expr { [$box yMin] - $tech_pitch }]
49
+ set ymax [expr { [$box yMax] + $tech_pitch }]
50
+
51
+ set blockage [odb::dbObstruction_create \
52
+ [ord::get_db_block] \
53
+ $layer \
54
+ $xmin $ymin \
55
+ $xmax $ymax]
56
+ lappend pdn_blockages $blockage
57
+ }
58
+ }
59
+ }
60
+
61
+ utl::info FLW 1 "Added [llength $pdn_blockages] obstructions to pins"
62
+ }
63
+
22
64
  ###############################
23
65
  # Power Network
24
66
  ###############################
@@ -64,6 +106,17 @@ foreach net [sc_psm_check_nets] {
64
106
  {*}$check_args
65
107
  }
66
108
 
109
+ ###############################
110
+ # Remove blockages
111
+ ###############################
112
+
113
+ if { [llength $pdn_blockages] > 0 } {
114
+ foreach obstruction $pdn_blockages {
115
+ odb::dbObstruction_destroy $obstruction
116
+ }
117
+ utl::info FLW 1 "Deleted [llength $pdn_blockages] obstructions"
118
+ }
119
+
67
120
  ###############################
68
121
  # Task Postamble
69
122
  ###############################
@@ -2,15 +2,24 @@
2
2
  # Global Placement
3
3
  #######################
4
4
 
5
- proc sc_global_placement_density { } {
6
- set gpl_padding [lindex [sc_cfg_tool_task_get var pad_global_place] 0]
5
+ proc sc_global_placement_density { args } {
6
+ sta::parse_key_args "sc_global_placement_density" args \
7
+ keys {} \
8
+ flags {-exclude_padding}
9
+ sta::check_argc_eq0 "sc_global_placement_density" $args
10
+
7
11
  set gpl_place_density [lindex [sc_cfg_tool_task_get var place_density] 0]
8
12
  set gpl_uniform_placement_adjustment \
9
13
  [lindex [sc_cfg_tool_task_get var gpl_uniform_placement_adjustment] 0]
10
14
 
11
- set or_uniform_density [gpl::get_global_placement_uniform_density \
12
- -pad_left $gpl_padding \
13
- -pad_right $gpl_padding]
15
+ set density_args []
16
+ if { ![info exists flags(-exclude_padding)] } {
17
+ set gpl_padding [lindex [sc_cfg_tool_task_get var pad_global_place] 0]
18
+
19
+ lappend density_args -pad_left $gpl_padding
20
+ lappend density_args -pad_right $gpl_padding
21
+ }
22
+ set or_uniform_density [gpl::get_global_placement_uniform_density {*}$density_args]
14
23
 
15
24
  # Small adder to ensure requested density is slightly over the uniform density
16
25
  set or_adjust_density_adder 0.001
@@ -762,3 +771,15 @@ proc sc_set_dont_use { args } {
762
771
  tee -quiet -file reports/$keys(-report).rpt {report_dont_use}
763
772
  }
764
773
  }
774
+
775
+ proc sc_setup_detailed_route { } {
776
+ foreach via [sc_cfg_tool_task_get var detailed_route_default_via] {
777
+ utl::info FLW 1 "Marking $via a default routing via"
778
+ detailed_route_set_default_via $via
779
+ }
780
+ foreach layer [sc_cfg_tool_task_get var detailed_route_unidirectional_layer] {
781
+ set layer [sc_get_layer_name $layer]
782
+ utl::info FLW 1 "Marking $layer as a unidirectional routing layer"
783
+ detailed_route_set_unidirectional_layer $layer
784
+ }
785
+ }
@@ -70,10 +70,17 @@ if { [sc_cfg_tool_task_check_in_list drv_violations var reports] } {
70
70
  tee -file reports/timing/drv_violators.rpt \
71
71
  "report_check_types -max_slew -max_capacitance -max_fanout -violators"
72
72
  report_erc_metrics
73
+ }
73
74
 
74
- puts "$PREFIX floating nets"
75
- tee -file reports/floating_nets.rpt \
76
- "report_floating_nets -verbose"
75
+ puts "$PREFIX floating nets"
76
+ tee -file reports/floating_nets.rpt \
77
+ "report_floating_nets -verbose"
78
+ if { [sc_check_version 19048] } {
79
+ puts "$PREFIX overdriven nets"
80
+ tee -file reports/overdriven_nets.rpt \
81
+ "report_overdriven_nets -verbose"
82
+ tee -file reports/overdriven_nets_with_parallel.rpt \
83
+ "report_overdriven_nets -include_parallel_driven -verbose"
77
84
  }
78
85
 
79
86
  utl::metric_int "timing__clocks" [llength [all_clocks]]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "openroad": {
3
3
  "git-url": "https://github.com/The-OpenROAD-Project/OpenROAD.git",
4
- "git-commit": "6645a5370f109cff49d7a735d81dae239df387c0",
4
+ "git-commit": "3258b30e2c47d695ff2bb6c14a23c6779ed130bb",
5
5
  "docker-cmds": [
6
6
  "# Remove OR-Tools files",
7
7
  "RUN rm -f $SC_PREFIX/Makefile $SC_PREFIX/README.md",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "sv2v": {
47
47
  "git-url": "https://github.com/zachjs/sv2v.git",
48
- "git-commit": "aa0a885699ca8f4fc1d07ef34fb041c6f37b1ba3",
48
+ "git-commit": "4ec99fcffd2c533c4a2c74ad6f56278f2672f05d",
49
49
  "auto-update": true
50
50
  },
51
51
  "verilator": {
@@ -91,7 +91,7 @@
91
91
  },
92
92
  "yosys": {
93
93
  "git-url": "https://github.com/YosysHQ/yosys.git",
94
- "git-commit": "v0.49",
94
+ "git-commit": "v0.50",
95
95
  "version-prefix": "",
96
96
  "auto-update": true
97
97
  },
@@ -128,7 +128,7 @@
128
128
  "auto-update": false
129
129
  },
130
130
  "slang": {
131
- "git-commit": "v7.0",
131
+ "git-commit": "v8.0",
132
132
  "git-url": "https://github.com/MikePopoloski/slang.git",
133
133
  "auto-update": true
134
134
  },
@@ -19,7 +19,7 @@ deps_args=""
19
19
  if [ ! -z ${PREFIX} ]; then
20
20
  deps_args="-prefix=$PREFIX"
21
21
  fi
22
- sudo ./etc/DependencyInstaller.sh $deps_args
22
+ sudo ./etc/DependencyInstaller.sh -all $deps_args
23
23
 
24
24
  cmake_args="-DENABLE_TESTS=OFF"
25
25
  if [ ! -z ${PREFIX} ]; then
@@ -16,7 +16,7 @@ deps_args=""
16
16
  if [ ! -z ${PREFIX} ]; then
17
17
  deps_args="-prefix=$PREFIX"
18
18
  fi
19
- sudo ./etc/DependencyInstaller.sh $deps_args
19
+ sudo ./etc/DependencyInstaller.sh -all $deps_args
20
20
 
21
21
  cmake_args="-DENABLE_TESTS=OFF"
22
22
  if [ ! -z ${PREFIX} ]; then
@@ -16,7 +16,7 @@ deps_args=""
16
16
  if [ ! -z ${PREFIX} ]; then
17
17
  deps_args="-prefix=$PREFIX"
18
18
  fi
19
- sudo ./etc/DependencyInstaller.sh $deps_args
19
+ sudo ./etc/DependencyInstaller.sh -all $deps_args
20
20
 
21
21
  cmake_args="-DENABLE_TESTS=OFF"
22
22
  if [ ! -z ${PREFIX} ]; then
@@ -16,7 +16,7 @@ deps_args=""
16
16
  if [ ! -z ${PREFIX} ]; then
17
17
  deps_args="-prefix=$PREFIX"
18
18
  fi
19
- sudo ./etc/DependencyInstaller.sh $deps_args
19
+ sudo ./etc/DependencyInstaller.sh -all $deps_args
20
20
 
21
21
  cmake_args="-DENABLE_TESTS=OFF"
22
22
  if [ ! -z ${PREFIX} ]; then
@@ -130,6 +130,12 @@ def get_default_iomap():
130
130
  report_drc = ('lyrdb', 'ascii')
131
131
  report_log = ('log',)
132
132
 
133
+ # Images
134
+ image_dot = ('dot', 'xdot')
135
+ image_png = ('png',)
136
+ image_jpg = ('jpg', 'jpeg')
137
+ image_bmp = ('bmp',)
138
+
133
139
  # Build default map with fileset and type
134
140
  default_iomap = {}
135
141
  default_iomap.update({ext: ('hll', 'c') for ext in hll_c})
@@ -169,6 +175,11 @@ def get_default_iomap():
169
175
  default_iomap.update({ext: ('report', 'drc') for ext in report_drc})
170
176
  default_iomap.update({ext: ('report', 'log') for ext in report_log})
171
177
 
178
+ default_iomap.update({ext: ('image', 'dot') for ext in image_dot})
179
+ default_iomap.update({ext: ('image', 'png') for ext in image_png})
180
+ default_iomap.update({ext: ('image', 'jpeg') for ext in image_jpg})
181
+ default_iomap.update({ext: ('image', 'bitmap') for ext in image_bmp})
182
+
172
183
  return default_iomap
173
184
 
174
185
 
@@ -6,6 +6,8 @@ from siliconcompiler.tools.vpr import show as vpr_show
6
6
  from siliconcompiler.tools.vpr import screenshot as vpr_screenshot
7
7
  from siliconcompiler.tools.yosys import screenshot as yosys_screenshot
8
8
  from siliconcompiler.tools.gtkwave import show as gtkwave_show
9
+ from siliconcompiler.tools.graphviz import show as graphviz_show
10
+ from siliconcompiler.tools.graphviz import screenshot as graphviz_screenshot
9
11
 
10
12
 
11
13
  def setup(chip):
@@ -32,3 +34,8 @@ def setup(chip):
32
34
  chip.register_showtool('vg', yosys_screenshot)
33
35
 
34
36
  chip.register_showtool('vcd', gtkwave_show)
37
+
38
+ chip.register_showtool('dot', graphviz_show)
39
+ chip.register_showtool('dot', graphviz_screenshot)
40
+ chip.register_showtool('xdot', graphviz_show)
41
+ chip.register_showtool('xdot', graphviz_screenshot)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: siliconcompiler
3
- Version: 0.29.4
3
+ Version: 0.30.0
4
4
  Summary: A compiler framework that automates translation from source code to silicon.
5
5
  Author-email: Andreas Olofsson <andreas.d.olofsson@gmail.com>
6
6
  License: Apache License 2.0
@@ -26,7 +26,7 @@ Requires-Python: >=3.8
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: aiohttp==3.10.11; python_version <= "3.8"
29
- Requires-Dist: aiohttp==3.11.11; python_version >= "3.9"
29
+ Requires-Dist: aiohttp==3.11.12; python_version >= "3.9"
30
30
  Requires-Dist: requests==2.32.3
31
31
  Requires-Dist: PyYAML==6.0.2
32
32
  Requires-Dist: pandas>=1.1.5
@@ -39,7 +39,7 @@ Requires-Dist: Pillow==10.4.0; python_version <= "3.8"
39
39
  Requires-Dist: Pillow==11.1.0; python_version >= "3.9"
40
40
  Requires-Dist: GitPython==3.1.44
41
41
  Requires-Dist: lambdapdk>=0.1.47
42
- Requires-Dist: PyGithub==2.5.0
42
+ Requires-Dist: PyGithub==2.6.0
43
43
  Requires-Dist: urllib3>=1.26.0
44
44
  Requires-Dist: fasteners==0.19
45
45
  Requires-Dist: fastjsonschema==2.21.1
@@ -48,7 +48,7 @@ Requires-Dist: importlib_metadata; python_version < "3.10"
48
48
  Requires-Dist: sc-surelog==1.84.1
49
49
  Requires-Dist: orjson==3.10.15
50
50
  Requires-Dist: streamlit==1.40.1; python_version <= "3.8"
51
- Requires-Dist: streamlit==1.41.1; python_version >= "3.9" and python_full_version != "3.9.7"
51
+ Requires-Dist: streamlit==1.42.0; python_version >= "3.9" and python_full_version != "3.9.7"
52
52
  Requires-Dist: streamlit_agraph==0.0.45; python_full_version != "3.9.7"
53
53
  Requires-Dist: streamlit-antd-components==0.3.2; python_full_version != "3.9.7"
54
54
  Requires-Dist: streamlit_javascript==0.1.5; python_full_version != "3.9.7"
@@ -64,7 +64,7 @@ Requires-Dist: pytest-cov==6.0.0; python_version >= "3.9" and extra == "test"
64
64
  Requires-Dist: responses==0.25.6; extra == "test"
65
65
  Requires-Dist: PyVirtualDisplay==3.0; extra == "test"
66
66
  Provides-Extra: lint
67
- Requires-Dist: flake8==7.1.1; extra == "lint"
67
+ Requires-Dist: flake8==7.1.2; extra == "lint"
68
68
  Requires-Dist: tclint==0.5.0; extra == "lint"
69
69
  Requires-Dist: codespell==2.4.1; extra == "lint"
70
70
  Provides-Extra: docs