From e9ba4872273b30c8962b4e2080892a13f8f3f19f Mon Sep 17 00:00:00 2001 From: Alexander Bessman Date: Tue, 6 Feb 2024 22:31:27 +0100 Subject: [PATCH] Remove prospector, add ruff --- .github/workflows/main.yml | 6 +-- .prospector.yaml | 51 ------------------- pyproject.toml | 86 ++++++++++++--------------------- src/pytest_reserial/reserial.py | 73 ++++++++++++++-------------- tox.ini | 37 ++++++++++++++ 5 files changed, 105 insertions(+), 148 deletions(-) delete mode 100644 .prospector.yaml create mode 100644 tox.ini diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7220177..3a82648 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,12 +9,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13-dev'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/.prospector.yaml b/.prospector.yaml deleted file mode 100644 index 9ec98d4..0000000 --- a/.prospector.yaml +++ /dev/null @@ -1,51 +0,0 @@ -strictness: veryhigh -test-warnings: false -doc-warnings: false -member-warnings: true -inherits: - - default -autodetect: false -max-line-length: 88 -ignore-paths: - - doc - -bandit: - run: true - -dodgy: - run: true - -frosted: - run: false - -mccabe: - run: true - options: - max-complexity: 5 - -pycodestyle: - run: true - disable: - - E203 - -pydocstyle: - run: false - -pyflakes: - run: true - -pylint: - run: true - disable: - - W1203 - -pyroma: - run: false - -mypy: - run: true - options: - strict: true - -vulture: - run: false diff --git a/pyproject.toml b/pyproject.toml index 2f7b271..368615c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "pytest-reserial" authors = [{name = "Alexander Bessman", email = "alexander.bessman@gmail.com"}] dynamic = ["version", "description"] readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.8" license = {file = "LICENSE"} dependencies = [ "pytest", @@ -15,11 +15,11 @@ dependencies = [ ] classifiers = [ "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", ] @@ -40,61 +40,35 @@ Home = "https://github.com/bessman/pytest-reserial" [project.entry-points."pytest11"] reserial = "pytest_reserial.reserial" -[tool.tox] -legacy_tox_ini = """ -[tox] -isolated_build = true -envlist = - isort - black - prospector - pydocstyle - test - report - -[testenv:isort] -deps = isort -commands = isort --check-only . - -[testenv:black] -deps = black -commands = black --check . - -[testenv:prospector] -deps = - prospector - mypy - bandit -commands = prospector . - -[testenv:pydocstyle] -deps = pydocstyle -commands = pydocstyle --convention=numpy src/ - -[testenv:test] -deps = - pytest - coverage -commands = coverage run --source=pytest_reserial -m pytest +[project.optional-dependencies] +test = [ + "coverage", +] +dev = [ + "black", + "isort", + "mypy", + "ruff", + "tox", +] -[testenv:report] -deps = coverage -commands = coverage report -depends = test +[tool.isort] +profile = "black" -[testenv:xml] -deps = coverage -commands = coverage xml -depends = test +[tool.ruff.lint] +select = ["ALL"] +ignore = [ + "D203", # one-blank-line-before-class + "D213", # multi-line-summary-second-line + "G004", # logging-f-string + "N818", # error-suffix-on-exception-name + "S101", # assert + "ANN101", # missing-type-self + "PT004", # pytest-missing-fixture-name-underscore +] -[gh-actions] -python = - 3.7: test - 3.8: test - 3.9: test - 3.10: test - 3.11: black, prospector, test, report -""" +[tool.ruff.lint.pydocstyle] +convention = "numpy" -[tool.isort] -profile = "black" +[tool.ruff.lint.per-file-ignores] +"**/{tests,docs}/*" = ["ALL"] diff --git a/src/pytest_reserial/reserial.py b/src/pytest_reserial/reserial.py index 8da97d2..6a41ab0 100644 --- a/src/pytest_reserial/reserial.py +++ b/src/pytest_reserial/reserial.py @@ -1,21 +1,37 @@ """Record or replay serial traffic when running tests.""" +from __future__ import annotations + import json from enum import IntEnum from pathlib import Path from typing import Callable, Dict, Generator, List, Tuple import pytest -from serial import Serial # type: ignore[import] +from serial import Serial # type: ignore[import-untyped] + +TrafficLog = Dict[str, List[int]] +PatchMethods = Tuple[ + Callable[[Serial, int], bytes], + Callable[[Serial, bytes], int], + Callable[[Serial], None], + Callable[[Serial], None], +] def pytest_addoption(parser: pytest.Parser) -> None: # noqa: D103 group = parser.getgroup("reserial") group.addoption( - "--record", action="store_true", default=False, help="Record serial traffic." + "--record", + action="store_true", + default=False, + help="Record serial traffic.", ) group.addoption( - "--replay", action="store_true", default=False, help="Replay serial traffic." + "--replay", + action="store_true", + default=False, + help="Replay serial traffic.", ) @@ -29,7 +45,8 @@ class Mode(IntEnum): def reconfigure_port_patch( - self: Serial, force_update: bool = False # pylint: disable=unused-argument + self: Serial, # noqa: ARG001 + force_update: bool = False, # noqa: ARG001, FBT001, FBT002 ) -> None: """Don't try to set parameters on the mocked port. @@ -39,7 +56,7 @@ def reconfigure_port_patch( """ -@pytest.fixture +@pytest.fixture() def reserial( monkeypatch: pytest.MonkeyPatch, request: pytest.FixtureRequest, @@ -81,7 +98,7 @@ def reserial( pytest.fail(msg) -def get_traffic_log(mode: Mode, logpath: Path, testname: str) -> Dict[str, List[int]]: +def get_traffic_log(mode: Mode, logpath: Path, testname: str) -> TrafficLog: """Load recorded traffic (replay) or create an empty log (record). Parameters @@ -105,26 +122,20 @@ def get_traffic_log(mode: Mode, logpath: Path, testname: str) -> Dict[str, List[ If both '--replay' and '--record' were specified. """ if mode == Mode.INVALID: - raise ValueError("Choose one of 'replay' or 'record', not both.") + msg = "Choose one of 'replay' or 'record', not both" + raise ValueError(msg) - log: Dict[str, List[int]] = {"rx": [], "tx": []} + log: TrafficLog = {"rx": [], "tx": []} if mode == Mode.REPLAY: - with open(logpath, "r", encoding="utf-8") as logfile: + with Path.open(logpath) as logfile: logs = json.load(logfile) log = logs[testname] return log -def get_patched_methods( - mode: Mode, log: Dict[str, List[int]] -) -> Tuple[ - Callable[[Serial, int], bytes], - Callable[[Serial, bytes], int], - Callable[[Serial], None], - Callable[[Serial], None], -]: +def get_patched_methods(mode: Mode, log: TrafficLog) -> PatchMethods: """Return patched read, write, open, and closed methods. The methods should be monkeypatched over the corresponding `Serial` methods. @@ -155,14 +166,7 @@ def get_patched_methods( return Serial.read, Serial.write, Serial.open, Serial.close -def get_replay_methods( - log: Dict[str, List[int]] -) -> Tuple[ - Callable[[Serial, int], bytes], - Callable[[Serial, bytes], int], - Callable[[Serial], None], - Callable[[Serial], None], -]: +def get_replay_methods(log: TrafficLog) -> PatchMethods: """Return patched read, write, open, and close methods for replaying logged traffic. Parameters @@ -183,7 +187,7 @@ def get_replay_methods( """ def replay_write( - self: Serial, # pylint: disable=unused-argument + self: Serial, # noqa: ARG001 data: bytes, ) -> int: """Compare TX data to recording instead of writing to the bus. @@ -208,7 +212,7 @@ def replay_write( return len(data) def replay_read( - self: Serial, # pylint: disable=unused-argument + self: Serial, # noqa: ARG001 size: int = 1, ) -> bytes: """Replay RX data from recording instead of reading from the bus. @@ -235,14 +239,7 @@ def replay_close(self: Serial) -> None: self.is_open = False -def get_record_methods( - log: Dict[str, List[int]] -) -> Tuple[ - Callable[[Serial, int], bytes], - Callable[[Serial, bytes], int], - Callable[[Serial], None], - Callable[[Serial], None], -]: +def get_record_methods(log: TrafficLog) -> PatchMethods: """Return patched read, write, open, and close methods for recording traffic. Parameters @@ -288,7 +285,7 @@ def record_read(self: Serial, size: int = 1) -> bytes: def write_log( - log: Dict[str, List[int]], + log: TrafficLog, logpath: Path, testname: str, ) -> None: @@ -305,7 +302,7 @@ def write_log( """ try: # If the file exists, read its contents. - with open(logpath, mode="r", encoding="utf-8") as logfile: + with Path.open(logpath) as logfile: logs = json.load(logfile) except FileNotFoundError: logs = {} @@ -313,5 +310,5 @@ def write_log( logs[testname] = log # Wipe the file if it exists, or create a new file if it doesn't. - with open(logpath, mode="w", encoding="utf-8") as logfile: + with Path.open(logpath, mode="w") as logfile: json.dump(logs, logfile) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..453b9d6 --- /dev/null +++ b/tox.ini @@ -0,0 +1,37 @@ +[tox] +envlist = + lint + test + +[testenv:format] +skip_install=True +allowlist_externals = + black + isort +commands = + black . + isort . + +[testenv:lint] +extras = dev +commands = + black --check . + isort --check . + mypy --strict src/ + ruff check . + +[testenv:test] +usedevelop=True +extras = test +commands = + coverage run --source=. -m pytest + coverage report + +[gh-actions] +python = + 3.8: test + 3.9: test + 3.10: test + 3.11: test + 3.12: test, lint + 3.13-dev: test, lint