diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index d97fe17..09c1e75 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -23,10 +23,10 @@ jobs: run: | pip install -e . - - name: Check with black + - name: Check with ruff format run: | - pip install black - black . --check + pip install ruff + ruff format - name: Check with ruff run: | diff --git a/pyproject.toml b/pyproject.toml index 21c357b..ca32d6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,6 +2,57 @@ requires = ["setuptools>=57", "wheel"] build-backend = "setuptools.build_meta" +[project] +name = "skillbridge" +authors = [ + {name = "Niels Buwen", email = "dev@niels-buwen.de"}, + {name = "Tobias Markus", email = "tobias_markus@gmx.net"}, +] +description = "A seamless Python remote bridge to Cadence's Skill in Virtuoso" +readme = {file = "README.md", content-type = "text/markdown"} +requires-python = ">=3.8" +dependencies = [] +urls = {Repository = "https://github.com/unihd-cag/skillbridge"} +license = {file = "LICENSE"} +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: Information Technology", + "Operating System :: POSIX :: Linux", + "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", + "Topic :: Software Development", + "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", +] +dynamic = ["version"] + +[tool.setuptools.dynamic] +version = {attr = "skillbridge.version.__version__"} + +[project.optional-dependencies] +dev = [ + "pytest", + "pytest-coverage", + "hypothesis", + "mypy", + "ruff>=0.2.1", +] +doc = [ + "sphinx" +] + +[project.scripts] +skillbridge = "skillbridge.__main__:main" + +[tool.setuptools.packages.find] +include = ["skillbridge*"] +namespaces = false + [tool.black] skip-string-normalization = true target-version = ["py38"] @@ -50,32 +101,39 @@ implicit_reexport = false strict_equality = true [tool.ruff] +preview = true exclude = ["venv", "env", "build"] line-length = 100 target-version = "py38" + +[tool.ruff.lint] select = ["ALL"] ignore = [ "A003", "ANN10", "ANN401", "B028", + "COM812", + "CPY001", "D", "EM101", "EM102", "FBT001", "FBT002", "G004", + "ISC001", "N999", "PD901", - "PLR0911", + "PLR0911", "PLR6301", + "PLW1641", "PLW3201", "PT001", "PT013", "PTH123", "Q000", - "S101", "S108", "S310", "S311", + "S101", "S108", "S310", "S311", "S404", "T201", "TCH001", "TCH002", "TCH003", "TID252", "TRY003", "TRY004", "TRY400", ] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "tests/*" = [ "ANN", "ARG001", @@ -95,5 +153,9 @@ ignore = [ "A001", ] -[tool.ruff.pylint] +[tool.ruff.lint.pylint] max-args = 7 + +[tool.ruff.format] +docstring-code-format = true +quote-style = "preserve" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index c6d568b..0000000 --- a/setup.cfg +++ /dev/null @@ -1,56 +0,0 @@ -[metadata] -name = skillbridge -version = attr: skillbridge.version.__version__ -author = Niels Buwen -author_email = dev@niels-buwen.de -maintainer = Tobias Markus -maintainer_email = tobias_markus@gmx.net -description = A seamless Python remote bridge to Cadence's Skill in Virtuoso -long_description = file: README.md -long_description_content_type = text/markdown -url = https://github.com/unihd-cag/skillbridge -classifiers = - Development Status :: 4 - Beta - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Intended Audience :: Developers - Intended Audience :: Science/Research - Intended Audience :: Information Technology - Operating System :: POSIX :: Linux - Topic :: Scientific/Engineering :: Electronic Design Automation (EDA) - Topic :: Software Development - License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) -license_files = - LICENSE - -[options] -packages = find: -python_requires = >=3.8 -include_package_data = True -install_requires = - -[options.packages.find] -include = - skillbridge* - -[options.entry_points] -console_scripts = - skillbridge = skillbridge.__main__:main - -[options.extras_require] -dev = - pytest - pytest-cov - hypothesis - mypy - ruff -doc = - sphinx - -[flake8] -exclude = .git, .mypy_cache, __pycache__, .pytest_cache, .tox, env, htmlcov, .idea -max_line_length = 100 -max-complexity = 10 diff --git a/skillbridge/__init__.py b/skillbridge/__init__.py index 5e95a92..5c91a5a 100644 --- a/skillbridge/__init__.py +++ b/skillbridge/__init__.py @@ -14,27 +14,27 @@ from .client.workspace import Workspace, current_workspace __all__ = [ - 'Workspace', - 'Var', + 'Function', + 'GlobalVar', + 'Globals', + 'Key', + 'LazyList', 'ParseError', + 'RemoteObject', + 'RemoteTable', + 'RemoteVector', + 'SkillCode', + 'SkillList', + 'SkillTuple', 'Symbol', - 'Key', - 'generate_static_completion', + 'Var', + 'Workspace', 'current_workspace', + 'generate_static_completion', 'keys', - 'SkillTuple', - 'SkillList', - 'SkillCode', - 'Function', 'loop_var', 'loop_var_i', 'loop_var_j', - 'Globals', - 'GlobalVar', - 'RemoteTable', - 'RemoteVector', - 'RemoteObject', - 'LazyList', ] loop_var = Var('i') @@ -43,7 +43,7 @@ def generate_static_completion() -> None: - from mypy.stubgen import Options, generate_stubs + from mypy.stubgen import Options, generate_stubs # noqa: PLC0415 base = Path(__file__).parent.absolute() / 'client' annotation = base / 'workspace.pyi' @@ -83,7 +83,7 @@ def generate_static_completion() -> None: text = sub(r' {4}[a-z][a-zA-Z]+: FunctionCollection\n', '', text) annotation.write_text(text) - with open(annotation, 'a') as fout: + with open(annotation, 'a', encoding='utf-8') as fout: for key, value in ws.__dict__.items(): if not isinstance(value, FunctionCollection): continue diff --git a/skillbridge/__main__.py b/skillbridge/__main__.py index 16a351e..b88081b 100644 --- a/skillbridge/__main__.py +++ b/skillbridge/__main__.py @@ -30,7 +30,7 @@ def deprecated_command() -> None: # pragma: no cover def shell_command(ws_id: str | None, ping: bool) -> None: - import skillbridge + import skillbridge # noqa: PLC0415 variables = {name: getattr(skillbridge, name) for name in dir(skillbridge)} ws = skillbridge.Workspace.open(ws_id) diff --git a/skillbridge/client/channel.py b/skillbridge/client/channel.py index 574ae08..5400647 100644 --- a/skillbridge/client/channel.py +++ b/skillbridge/client/channel.py @@ -187,7 +187,9 @@ def create_channel_class() -> type[TcpChannel]: class WindowsChannel(TcpChannel): def configure(self, sock: socket) -> None: try: - from socket import SIO_LOOPBACK_FAST_PATH # type: ignore[attr-defined] + from socket import ( # type: ignore[attr-defined] # noqa: PLC0415 + SIO_LOOPBACK_FAST_PATH, + ) sock.ioctl( # type: ignore[attr-defined] SIO_LOOPBACK_FAST_PATH, @@ -206,7 +208,7 @@ def create_address(id_: Any) -> Any: else: def create_channel_class() -> type[TcpChannel]: - from socket import AF_UNIX + from socket import AF_UNIX # noqa: PLC0415 class UnixChannel(TcpChannel): address_family = AF_UNIX diff --git a/skillbridge/client/globals.py b/skillbridge/client/globals.py index f99b4ef..f478d4b 100644 --- a/skillbridge/client/globals.py +++ b/skillbridge/client/globals.py @@ -10,7 +10,7 @@ class GlobalVar: - __slots__ = 'name', '_channel', '_translator' + __slots__ = '_channel', '_translator', 'name' def __init__(self, name: str, channel: Channel, translator: Translator) -> None: self.name = name diff --git a/skillbridge/client/hints.py b/skillbridge/client/hints.py index 44f378b..323f78a 100644 --- a/skillbridge/client/hints.py +++ b/skillbridge/client/hints.py @@ -11,16 +11,16 @@ class Protocol: __all__ = [ - 'Number', - 'Symbol', + 'Function', 'Key', - 'SkillComponent', - 'SkillCode', + 'Number', 'Skill', - 'Function', - 'SkillTuple', + 'SkillCode', + 'SkillComponent', 'SkillList', + 'SkillTuple', 'SupportsReprSkill', + 'Symbol', ] Number = Union[int, float] diff --git a/skillbridge/client/objects.py b/skillbridge/client/objects.py index 5972ec8..20f1924 100644 --- a/skillbridge/client/objects.py +++ b/skillbridge/client/objects.py @@ -175,12 +175,10 @@ def filter(self, *args: str, **kwargs: Any) -> LazyList: return LazyList(self._channel, self._translator, variable) @overload - def __getitem__(self, item: int) -> RemoteObject: - ... # pragma: nocover + def __getitem__(self, item: int) -> RemoteObject: ... # pragma: nocover @overload - def __getitem__(self, item: slice) -> list[RemoteObject]: - ... # pragma: nocover + def __getitem__(self, item: slice) -> list[RemoteObject]: ... # pragma: nocover def __getitem__( self, diff --git a/skillbridge/client/workspace.py b/skillbridge/client/workspace.py index 4556caa..d2f0983 100644 --- a/skillbridge/client/workspace.py +++ b/skillbridge/client/workspace.py @@ -21,7 +21,7 @@ _open_workspaces: dict[WorkspaceId, Workspace] = {} -logger = getLogger(__file__) +logger = getLogger(__name__) class _NoWorkspace: @@ -328,7 +328,7 @@ def register(self, function: Callable[..., Any]) -> Function: name = camel_to_snake(function.__name__) try: - prefix, rest = name.split('_', maxsplit=1) + prefix, _ = name.split('_', maxsplit=1) except ValueError: raise RuntimeError("Function does not have a prefix.") from None diff --git a/skillbridge/server/python_server.py b/skillbridge/server/python_server.py index bdeba4f..ff9489c 100644 --- a/skillbridge/server/python_server.py +++ b/skillbridge/server/python_server.py @@ -38,7 +38,7 @@ def read_from_skill(timeout: float | None) -> str: def create_windows_server_class(single: bool) -> type[BaseServer]: - from socketserver import TCPServer + from socketserver import TCPServer # noqa: PLC0415 class SingleWindowsServer(TCPServer): request_queue_size = 0 @@ -49,7 +49,9 @@ def __init__(self, port: int, handler: type[BaseRequestHandler]) -> None: def server_bind(self) -> None: try: - from socket import SIO_LOOPBACK_FAST_PATH # type: ignore[attr-defined] + from socket import ( # type: ignore[attr-defined] # noqa: PLC0415 + SIO_LOOPBACK_FAST_PATH, + ) self.socket.ioctl( # type: ignore[attr-defined] SIO_LOOPBACK_FAST_PATH, @@ -71,7 +73,7 @@ def data_windows_ready(timeout: float | None) -> bool: def create_unix_server_class(single: bool) -> type[BaseServer]: - from socketserver import UnixStreamServer + from socketserver import UnixStreamServer # noqa: PLC0415 class SingleUnixServer(UnixStreamServer): request_queue_size = 0 diff --git a/tests/test_channel.py b/tests/test_channel.py index 4b68bf6..d069c2a 100644 --- a/tests/test_channel.py +++ b/tests/test_channel.py @@ -48,7 +48,7 @@ def ws() -> Workspace: else: break else: - raise + raise RuntimeError yield ws ws.close() @@ -291,7 +291,7 @@ def test_warning_is_printed(server, ws): result = ws.ge.get_edit_cell_view() assert len(w) == 1 - assert w[0].category == UserWarning + assert w[0].category is UserWarning assert "This is a warning" in str(w[0].message) assert result == 1234 diff --git a/tests/test_workspace.py b/tests/test_workspace.py index 2fac7b7..b7911fd 100644 --- a/tests/test_workspace.py +++ b/tests/test_workspace.py @@ -3,7 +3,7 @@ from skillbridge import Workspace from skillbridge.client.channel import Channel from skillbridge.client.translator import DefaultTranslator -from skillbridge.client.workspace import _open_workspaces +from skillbridge.client.workspace import _open_workspaces # noqa: PLC2701 class DummyChannel(Channel):