Compare commits

...

9 Commits

5 changed files with 71 additions and 26 deletions

View File

@ -10,6 +10,7 @@ has deprived the man of both a schematic and a better connectivity tool.
- [Source repository](https://mpxd.net/code/jan/snarled)
- [PyPI](https://pypi.org/project/snarled)
- [Github mirror](https://github.com/anewusername/snarled)
## Installation

View File

@ -42,10 +42,10 @@ classifiers = [
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
]
requires-python = ">=3.10"
requires-python = ">=3.11"
dynamic = ["version"]
dependencies = [
"klayout~=0.28",
"klayout~=0.29",
]
@ -54,3 +54,40 @@ path = "snarled/__init__.py"
[project.scripts]
snarled = "snarled.main:main"
[tool.ruff]
exclude = [
".git",
"dist",
]
line-length = 145
indent-width = 4
lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
lint.select = [
"NPY", "E", "F", "W", "B", "ANN", "UP", "SLOT", "SIM", "LOG",
"C4", "ISC", "PIE", "PT", "RET", "TCH", "PTH", "INT",
"ARG", "PL", "R", "TRY",
"G010", "G101", "G201", "G202",
"Q002", "Q003", "Q004",
]
lint.ignore = [
#"ANN001", # No annotation
"ANN002", # *args
"ANN003", # **kwargs
"ANN401", # Any
"ANN101", # self: Self
"SIM108", # single-line if / else assignment
"RET504", # x=y+z; return x
"PIE790", # unnecessary pass
"ISC003", # non-implicit string concatenation
"C408", # dict(x=y) instead of {'x': y}
"PLR09", # Too many xxx
"PLR2004", # magic number
"PLC0414", # import x as x
"TRY003", # Long exception message
"PTH123", # open()
"UP015", # open(..., 'rt')
"PLW2901", # overwriting loop var
]

View File

@ -12,7 +12,10 @@ has deprived the man of a schematic and a better connectivity tool.
The main functionality is in `trace`.
`__main__.py` details the command-line interface.
"""
from .trace import trace_layout, TraceAnalysis
from .trace import (
trace_layout as trace_layout,
TraceAnalysis as TraceAnalysis,
)
__author__ = 'Jan Petykiewicz'
__version__ = '1.0'

View File

@ -1,10 +1,11 @@
from typing import Sequence, Iterable
from collections.abc import Sequence, Iterable
import logging
from collections import Counter
from itertools import chain
from klayout import db
from .types import lnum_t, layer_t
from .utils import SnarledError
logger = logging.getLogger(__name__)
@ -165,8 +166,8 @@ def trace_layout(
# Merge labels from a separate layout if asked
if lfile_path:
if not lfile_map:
raise Exception('Asked to load labels from a separate file, but no '
'label layers were specified in lfile_map')
raise SnarledError('Asked to load labels from a separate file, but no '
+ 'label layers were specified in lfile_map')
if lfile_layer_map is None:
lfile_layer_map = layer_map
@ -199,7 +200,7 @@ def trace_layout(
# Create l2n text layers
layer2texts = {}
for layer in labels_map.keys():
for layer in labels_map:
if isinstance(layer, str):
layer = layer_map[layer]
klayer = layout.layer(*layer)
@ -247,7 +248,7 @@ def trace_layout(
#
# Return merged nets
#
top_circuits = [cc for cc, _ in zip(nl.each_circuit_top_down(), range(nl.top_circuit_count()))]
top_circuits = [cc for cc, _ in zip(nl.each_circuit_top_down(), range(nl.top_circuit_count()), strict=False)]
# Nets with more than one label get their labels joined with a comma
nets = [
@ -275,9 +276,8 @@ def _get_topcell(
"""
if name is None:
return layout.top_cell()
else:
ind = layout.cell_by_name(name)
return layout.cell(ind)
ind = layout.cell_by_name(name)
return layout.cell(ind)
def _write_net_layout(

View File

@ -5,6 +5,10 @@ from .types import layer_t
logger = logging.getLogger(__name__)
class SnarledError(Exception):
pass
def strip_underscored_label(string: str) -> str:
"""
If the label ends in an underscore followed by an integer, strip
@ -50,18 +54,18 @@ def read_layermap(path: str) -> dict[str, tuple[int, int]]:
for cc in '*-()':
if cc in line:
raise Exception(f'Failed to read layermap on line {nn} due to special character "{cc}"')
raise SnarledError(f'Failed to read layermap on line {nn} due to special character "{cc}"')
for cc in ':/':
if cc not in line:
raise Exception(f'Failed to read layermap on line {nn}; missing "{cc}"')
raise SnarledError(f'Failed to read layermap on line {nn}; missing "{cc}"')
try:
layer_part, name = line.split(':')
layer_nums = str2lnum(layer_part)
except Exception as err:
logger.error(f'Layer map read failed on line {nn}')
raise err
except Exception:
logger.exception(f'Layer map read failed on line {nn}')
raise
layer_map[name.strip()] = layer_nums
@ -101,7 +105,7 @@ def read_connectivity(path: str) -> list[tuple[layer_t, layer_t | None, layer_t]
parts = line.split(',')
if len(parts) not in (2, 3):
raise Exception(f'Too many commas in connectivity spec on line {nn}')
raise SnarledError(f'Too many commas in connectivity spec on line {nn}')
layers = []
for part in parts:
@ -109,13 +113,13 @@ def read_connectivity(path: str) -> list[tuple[layer_t, layer_t | None, layer_t]
if '/' in part:
try:
layer = str2lnum(part)
except Exception as err:
logger.error(f'Connectivity spec read failed on line {nn}')
raise err
except Exception:
logger.exception(f'Connectivity spec read failed on line {nn}')
raise
else:
layer = part.strip()
if not layer:
raise Exception(f'Empty layer in connectivity spec on line {nn}')
raise SnarledError(f'Empty layer in connectivity spec on line {nn}')
layers.append(layer)
if len(layers) == 2:
@ -156,7 +160,7 @@ def read_remap(path: str) -> dict[layer_t, layer_t]:
parts = line.split(':')
if len(parts) != 2:
raise Exception(f'Too many commas in layer remap spec on line {nn}')
raise SnarledError(f'Too many commas in layer remap spec on line {nn}')
layers = []
for part in parts:
@ -164,13 +168,13 @@ def read_remap(path: str) -> dict[layer_t, layer_t]:
if '/' in part:
try:
layer = str2lnum(part)
except Exception as err:
logger.error(f'Layer remap spec read failed on line {nn}')
raise err
except Exception:
logger.exception(f'Layer remap spec read failed on line {nn}')
raise
else:
layer = part.strip()
if not layer:
raise Exception(f'Empty layer in layer remap spec on line {nn}')
raise SnarledError(f'Empty layer in layer remap spec on line {nn}')
layers.append(layer)
remap[layers[0]] = layers[1]