diff --git a/pyproject.toml b/pyproject.toml index 85c290a..868c432 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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 + ] + diff --git a/snarled/__init__.py b/snarled/__init__.py index f0baef8..86944c6 100644 --- a/snarled/__init__.py +++ b/snarled/__init__.py @@ -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' diff --git a/snarled/trace.py b/snarled/trace.py index a7d0d9b..316f049 100644 --- a/snarled/trace.py +++ b/snarled/trace.py @@ -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( diff --git a/snarled/utils.py b/snarled/utils.py index 3274755..752d61e 100644 --- a/snarled/utils.py +++ b/snarled/utils.py @@ -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]