diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1b105884..cb3c1e2a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,16 +10,8 @@ repos: - id: end-of-file-fixer exclude: '.*\.pth$' - id: debug-statements - - repo: https://github.com/PyCQA/isort - rev: 5.12.0 + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.253 hooks: - - id: isort - - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 - hooks: - - id: pyupgrade - args: [--py37-plus] - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 - hooks: - - id: flake8 + - id: ruff + args: [--fix, --exit-non-zero-on-fix, --show-fixes] diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 00000000..12fe797c --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,57 @@ +# [tool.ruff] # <- TODO Uncomment when migrating to pyproject.toml +exclude = [ + ".eggs", + ".tox", + "build", + "ci/templates", + "dist", +] +ignore = [ + "ANN", # flake8-annotations + "ARG", # flake8-unused-arguments + "BLE", # flake8-blind-except + "COM", # flake8-comma + "D", # pydocstyle + "EM", # flake8-errmsg + "FBT", # flake8-boolean-trap + "INP", # flake8-no-pep420 + "PLR0133", # Pylint Refactor + "PLR2004", # Pylint Refactor + "PLW", # Pylint Warning + "PTH", # flake8-use-pathlib + "Q", # flake8-quotes + "RET", # flake8-return + "RUF100", # Ruff-internal + "S101", # flake8-bandit assert + "S102", # flake8-bandit exec + "S110", # flake8-bandit try-except-pass + "SIM102", # flake8-simplify collapsible-if + "SIM105", # flake8-simplify use-contextlib-suppress + "SLF", # flake8-self + "T20", # flake8-print + "TRY", # tryceratops +] +line-length = 140 +select = ["ALL"] +target-version = "py37" + +# [tool.ruff.isort] # <- TODO Uncomment when migrating to pyproject.toml +[isort] +# default-section = "THIRDPARTY" +force-single-line = true +forced-separate = ["test_pytest_cov"] +known-first-party = ["pytest_cov"] + +[mccabe] +max-complexity = 12 + +[per-file-ignores] +"ci/bootstrap.py" = ["S701"] +"docs/conf.py" = ["A001"] +"src/pytest_cov/plugin.py" = ["B904", "PT004"] +"setup.py" = ["SIM117"] +"tests/test_pytest_cov.py" = ["N801", "PT004", "RSE102", "SIM117"] + +[pylint] +max-args = 8 +max-branches = 13 diff --git a/MANIFEST.in b/MANIFEST.in index cbb88f74..ebf88344 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,22 +7,22 @@ prune examples/adhoc-layout/*.egg-info prune examples/src-layout/src/*.egg-info graft .github/workflows -graft src graft ci +graft src graft tests include .bumpversion.cfg include .cookiecutterrc include .coveragerc include .editorconfig -include tox.ini -include .readthedocs.yml include .pre-commit-config.yaml +include .readthedocs.yml +include .ruff.toml include AUTHORS.rst include CHANGELOG.rst include CONTRIBUTING.rst include LICENSE include README.rst - +include tox.ini global-exclude *.py[cod] __pycache__/* *.so *.dylib diff --git a/examples/adhoc-layout/tests/test_example.py b/examples/adhoc-layout/tests/test_example.py index f4948e66..8cf207de 100644 --- a/examples/adhoc-layout/tests/test_example.py +++ b/examples/adhoc-layout/tests/test_example.py @@ -3,4 +3,4 @@ def test_add(): assert example.add(1, 1) == 2 - assert not example.add(0, 1) == 2 + assert example.add(0, 1) != 2 diff --git a/examples/src-layout/tests/test_example.py b/examples/src-layout/tests/test_example.py index f4948e66..8cf207de 100644 --- a/examples/src-layout/tests/test_example.py +++ b/examples/src-layout/tests/test_example.py @@ -3,4 +3,4 @@ def test_add(): assert example.add(1, 1) == 2 - assert not example.add(0, 1) == 2 + assert example.add(0, 1) != 2 diff --git a/setup.cfg b/setup.cfg index 360a416d..268333ec 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,3 @@ -[flake8] -max-line-length = 140 -exclude = .tox,.eggs,ci/templates,build,dist - [tool:pytest] testpaths = tests python_files = test_*.py @@ -9,11 +5,3 @@ addopts = -ra --strict -p pytester - -[tool:isort] -force_single_line = True -line_length = 120 -known_first_party = pytest_cov -default_section = THIRDPARTY -forced_separate = test_pytest_cov -skip = .tox,.eggs,ci/templates,build,dist diff --git a/src/pytest_cov/embed.py b/src/pytest_cov/embed.py index f8a2749f..be50a50b 100644 --- a/src/pytest_cov/embed.py +++ b/src/pytest_cov/embed.py @@ -38,10 +38,7 @@ def init(): import coverage # Determine all source roots. - if cov_source in os.pathsep: - cov_source = None - else: - cov_source = cov_source.split(os.pathsep) + cov_source = None if cov_source in os.pathsep else cov_source.split(os.pathsep) if cov_config == os.pathsep: cov_config = True @@ -108,7 +105,7 @@ def _signal_cleanup_handler(signum, frame): elif signum == signal.SIGTERM: os._exit(128 + signum) elif signum == signal.SIGINT: - raise KeyboardInterrupt() + raise KeyboardInterrupt def cleanup_on_signal(signum): diff --git a/src/pytest_cov/engine.py b/src/pytest_cov/engine.py index 27e1a090..91e32169 100644 --- a/src/pytest_cov/engine.py +++ b/src/pytest_cov/engine.py @@ -412,5 +412,3 @@ def finish(self): def summary(self, stream): """Only the master reports so do nothing.""" - - pass diff --git a/src/pytest_cov/plugin.py b/src/pytest_cov/plugin.py index dd7b8c4e..a406eb33 100644 --- a/src/pytest_cov/plugin.py +++ b/src/pytest_cov/plugin.py @@ -35,7 +35,7 @@ def validate_report(arg): all_choices = term_choices + file_choices values = arg.split(":", 1) report_type = values[0] - if report_type not in all_choices + ['']: + if report_type not in [*all_choices, '']: msg = f'invalid choice: "{arg}" (choose from "{all_choices}")' raise argparse.ArgumentTypeError(msg) @@ -247,7 +247,7 @@ def pytest_sessionstart(self, session): self.pid = os.getpid() if self._is_worker(session): nodeid = ( - session.config.workerinput.get('workerid', getattr(session, 'nodeid')) + session.config.workerinput.get('workerid', session.nodeid) ) self.start(engine.DistWorker, session.config, nodeid) elif not self._started: @@ -308,7 +308,7 @@ def pytest_runtestloop(self, session): message = 'Failed to generate report: %s\n' % exc session.config.pluginmanager.getplugin("terminalreporter").write( 'WARNING: %s\n' % message, red=True, bold=True) - warnings.warn(CovReportWarning(message)) + warnings.warn(CovReportWarning(message)) # noqa: B028 self.cov_total = 0 assert self.cov_total is not None, 'Test coverage should never be `None`' if self._failed_cov_total() and not self.options.collectonly: @@ -320,7 +320,7 @@ def pytest_terminal_summary(self, terminalreporter): if self.options.no_cov_should_warn: message = 'Coverage disabled via --no-cov switch!' terminalreporter.write('WARNING: %s\n' % message, red=True, bold=True) - warnings.warn(CovDisabledWarning(message)) + warnings.warn(CovDisabledWarning(message)) # noqa: B028 return if self.cov_controller is None: return @@ -389,13 +389,12 @@ def switch_context(self, item, when): os.environ['COV_CORE_CONTEXT'] = context -@pytest.fixture +@pytest.fixture() def no_cover(): """A pytest fixture to disable coverage.""" - pass -@pytest.fixture +@pytest.fixture() def cov(request): """A pytest fixture to provide access to the underlying coverage object.""" diff --git a/tests/contextful.py b/tests/contextful.py index 3527e499..7edb87c0 100644 --- a/tests/contextful.py +++ b/tests/contextful.py @@ -39,7 +39,7 @@ def test_04(self): assert self.items[0] == "hello" # r4 -@pytest.fixture +@pytest.fixture() def some_data(): return [1, 2, 3] # s5 s6 @@ -48,7 +48,7 @@ def test_05(some_data): assert len(some_data) == 3 # r5 -@pytest.fixture +@pytest.fixture() def more_data(some_data): return [2*x for x in some_data] # s6 @@ -83,7 +83,7 @@ def test_10(): assert 1 == 1 # r10 -@pytest.mark.parametrize("x, ans", [ +@pytest.mark.parametrize(("x", "ans"), [ (1, 101), (2, 202), ]) @@ -91,7 +91,7 @@ def test_11(x, ans): assert 100 * x + x == ans # r11-1 r11-2 -@pytest.mark.parametrize("x, ans", [ +@pytest.mark.parametrize(("x", "ans"), [ (1, 101), (2, 202), ], ids=['one', 'two']) diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 77859bf4..d1f10a20 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -1945,7 +1945,7 @@ def test_contexts(pytester, testdir, opts): line_data = find_labels(contextful_tests, r"[crst]\d+(?:-\d+)?") for context, label in EXPECTED_CONTEXTS.items(): - if context == '': + if context == '': # noqa: PLC1901 continue data.set_query_context(context) actual = set(data.lines(test_context_path)) diff --git a/tox.ini b/tox.ini index aeccd9de..fe1c20cc 100644 --- a/tox.ini +++ b/tox.ini @@ -93,14 +93,14 @@ deps = check-manifest colorama # TODO Remove when isort > v6.0.0b2 is released. docutils - flake8 isort pygments readme-renderer + ruff skip_install = true usedevelop = false commands = python setup.py check --strict --metadata --restructuredtext check-manifest {toxinidir} - flake8 src tests setup.py + ruff . isort --check-only --diff src tests setup.py