Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support old pytests #13

Merged
merged 3 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"]
build-backend = "poetry_dynamic_versioning.backend"

[tool.poetry.dependencies]
pytest = ">=5"
python = "^3.8"
ruff = ">=0.0.242"

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0"
pytest-mock = "^3.10.0"
pytest-cov = "^4.1.0"

Expand Down
28 changes: 14 additions & 14 deletions pytest_ruff.py → pytest_ruff/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from subprocess import Popen, PIPE

# Python<=3.8 don't support typing with builtin dict.
from typing import Dict

import pytest

from ruff.__main__ import find_ruff_bin

from pytest_ruff._pytest_compat import get_stash, make_path_kwargs, set_stash

HISTKEY = "ruff/mtimes"
_MTIMES_STASH_KEY = pytest.StashKey[Dict[str, float]]()


def pytest_addoption(parser):
Expand All @@ -24,18 +23,18 @@
if not config.option.ruff or not hasattr(config, "cache"):
return

config.stash[_MTIMES_STASH_KEY] = config.cache.get(HISTKEY, {})
set_stash(config, config.cache.get(HISTKEY, {}))


def pytest_collect_file(file_path, path, parent):
def pytest_collect_file(path, parent, fspath=None):
config = parent.config
if not config.option.ruff:
return

if file_path.suffix != ".py":
if path.ext != ".py":
return

return RuffFile.from_parent(parent, path=file_path)
return RuffFile.from_parent(parent, **make_path_kwargs(path))


def pytest_sessionfinish(session, exitstatus):
Expand All @@ -48,7 +47,7 @@
# It works fine if pytest-xdist is not being used.
if not hasattr(config, "workerinput"):
cache = config.cache.get(HISTKEY, {})
cache.update(config.stash[_MTIMES_STASH_KEY])
cache.update(get_stash(config))
config.cache.set(HISTKEY, cache)


Expand Down Expand Up @@ -93,16 +92,17 @@
self.add_marker("ruff")

def setup(self):
ruffmtimes = self.config.stash.get(_MTIMES_STASH_KEY, {})
ruffmtimes = get_stash(self.config)
self._ruffmtime = self.fspath.mtime()
old = ruffmtimes.get(str(self.fspath))
if old == self._ruffmtime:
pytest.skip("file previously passed ruff checks")
if ruffmtimes:
old = ruffmtimes.get(str(self.fspath))

Check warning on line 98 in pytest_ruff/__init__.py

View check run for this annotation

Codecov / codecov/patch

pytest_ruff/__init__.py#L98

Added line #L98 was not covered by tests
if old == self._ruffmtime:
pytest.skip("file previously passed ruff checks")

Check warning on line 100 in pytest_ruff/__init__.py

View check run for this annotation

Codecov / codecov/patch

pytest_ruff/__init__.py#L100

Added line #L100 was not covered by tests

def runtest(self):
self.handler(path=self.fspath)

ruffmtimes = self.config.stash.get(_MTIMES_STASH_KEY, None)
ruffmtimes = get_stash(self.config)
if ruffmtimes:
ruffmtimes[str(self.fspath)] = self._ruffmtime

Expand Down
46 changes: 46 additions & 0 deletions pytest_ruff/_pytest_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from pathlib import Path

# Python<=3.8 don't support typing with builtin dict.
from typing import Dict

import pytest

try:
from pytest import Stash, StashKey
except ImportError:
import _pytest.store

Stash = _pytest.store.Store
StashKey = _pytest.store.StoreKey

PYTEST_VER = tuple(int(x) for x in pytest.__version__.split(".")[:2])
_MTIMES_STASH_KEY = StashKey[Dict[str, float]]()


def make_path_kwargs(p):
"""
Make keyword arguments passing either path or fspath, depending on pytest version.

In pytest 7.0, the `fspath` argument to Nodes has been deprecated, so we pass `path`
instead.
"""
return dict(path=Path(p)) if PYTEST_VER >= (7, 0) else dict(fspath=p)


def get_stash_object(config):
try:
stash = config.stash
except AttributeError:
stash = config._store
return stash


def get_stash(config):
missing = object()
stash = get_stash_object(config).get(_MTIMES_STASH_KEY, default=missing)
assert stash is not missing
return stash


def set_stash(config, value):
get_stash_object(config)[_MTIMES_STASH_KEY] = value
12 changes: 7 additions & 5 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@
import pytest

import pytest_ruff
from pytest_ruff._pytest_compat import Stash, get_stash


def test_configure(mocker):
config = mocker.Mock(
cache={pytest_ruff.HISTKEY: mocker.sentinel.cache},
option=mocker.Mock(ruff=True),
stash=pytest.Stash(),
stash=Stash(),
)
pytest_ruff.pytest_configure(config)
assert config.stash[pytest_ruff._MTIMES_STASH_KEY] == mocker.sentinel.cache
assert get_stash(config) == mocker.sentinel.cache


def test_configure_without_ruff(mocker):
config = mocker.Mock(
option=mocker.Mock(ruff=False),
stash=pytest.Stash(),
# Mocking to `not hasattr(config, "cache")`.
spec=["addinivalue_line", "option", "stash"],
)
set_stash_mock = mocker.patch("pytest_ruff.set_stash", spec=True)
pytest_ruff.pytest_configure(config)
with pytest.raises(KeyError):
config.stash[pytest_ruff._MTIMES_STASH_KEY]
set_stash_mock.assert_not_called()


def test_check_file():
Expand Down Expand Up @@ -61,6 +61,7 @@ def test_pytest_ruff_format():
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
).communicate()
assert err.decode() == ""
assert "File would be reformatted" in out.decode("utf-8")


Expand All @@ -76,4 +77,5 @@ def test_pytest_ruff_noformat():
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
).communicate()
assert err.decode() == ""
assert "File would be reformatted" not in out.decode("utf-8")
10 changes: 9 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
[tox]
isolated_build = true
envlist = py{38,39,310,311,312},lint
envlist = py{38,39,310,311,312}-pytest{5,6,7,8},lint

[testenv]
allowlist_externals = poetry
commands =
poetry install --no-root --with dev
pytest5: pip install "pytest<6"
pytest6: pip install "pytest>=6,<7"
pytest7: pip install "pytest>=7,<8"
pytest8: pip install "pytest>=8,<9"
# Disable ruff plugin to generate better coverage results
poetry run pytest -p no:ruff -vvv --cov --cov-append --cov-report term --cov-report xml {posargs}

# pytest 5 does not work on python>=3.10
[testenv:py{310,311,312}-pytest{5}]
ignore_outcome = true

[testenv:lint]
description = lint source code
deps =
Expand Down
Loading