Skip to content

Commit

Permalink
Pytest compat layer
Browse files Browse the repository at this point in the history
  • Loading branch information
iurisilvio committed Mar 3, 2024
1 parent 1dff17d commit fb2243f
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 48 deletions.
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
47 changes: 10 additions & 37 deletions pytest_ruff.py → pytest_ruff/__init__.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,12 @@
from subprocess import Popen, PIPE

from pathlib import Path

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

import pytest

try:
from pytest import StashKey
except ImportError:
from _pytest.store import StoreKey as StashKey

from ruff.__main__ import find_ruff_bin

PYTEST_VER = tuple(int(x) for x in pytest.__version__.split(".")[:2])
from pytest_ruff._pytest_compat import get_stash, make_path_kwargs, set_stash

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


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


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 pytest_addoption(parser):
Expand All @@ -51,7 +23,7 @@ def pytest_configure(config):
if not config.option.ruff or not hasattr(config, "cache"):
return

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


def pytest_collect_file(path, parent, fspath=None):
Expand All @@ -62,7 +34,7 @@ def pytest_collect_file(path, parent, fspath=None):
if path.ext != ".py":
return

return RuffFile.from_parent(parent, **_make_path_kwargs(path))
return RuffFile.from_parent(parent, **make_path_kwargs(path))


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


Expand Down Expand Up @@ -120,16 +92,17 @@ def __init__(self, *k, **kwargs):
self.add_marker("ruff")

def setup(self):
ruffmtimes = _stash(self.config).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 = _stash(self.config).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
16 changes: 6 additions & 10 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@

import pytest

try:
from pytest import Stash
except ImportError:
from _pytest.store import Store as Stash
import pytest_ruff
from pytest_ruff._pytest_compat import Stash, get_stash


def test_configure(mocker):
Expand All @@ -17,19 +14,18 @@ def test_configure(mocker):
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=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 @@ -65,7 +61,7 @@ def test_pytest_ruff_format():
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
).communicate()
assert err == b""
assert err.decode() == ""
assert "File would be reformatted" in out.decode("utf-8")


Expand All @@ -81,5 +77,5 @@ def test_pytest_ruff_noformat():
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
).communicate()
assert err == b""
assert err.decode() == ""
assert "File would be reformatted" not in out.decode("utf-8")

0 comments on commit fb2243f

Please sign in to comment.