Skip to content
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
36 changes: 28 additions & 8 deletions pytest_ruff/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ def pytest_addoption(parser):
group.addoption(
"--ruff-format", action="store_true", help="enable format checking with ruff"
)
group.addoption(
"--ruff-config",
action="store",
type=str,
help="uses custom ruff config file",
)


def pytest_configure(config):
Expand Down Expand Up @@ -77,14 +83,23 @@ class RuffError(Exception):
class RuffFile(pytest.File):
def collect(self):
collection = []
config_file = None
if self.config.option.ruff_config:
config_file = self.config.option.ruff_config
if self.config.option.ruff:
collection.append(RuffItem)
collection.append(
RuffItem.from_parent(self, name="ruff", config_file=config_file)
)
if self.config.option.ruff_format:
collection.append(RuffFormatItem.from_parent(self, name="ruff::format"))
return [Item.from_parent(self, name=Item.name) for Item in collection]
collection.append(
RuffFormatItem.from_parent(
self, name="ruff::format", config_file=config_file
)
)
return collection


def check_file(path):
def check_file(path, config_file):
ruff = find_ruff_bin()
command = [
ruff,
Expand All @@ -94,6 +109,8 @@ def check_file(path):
"--output-format=full",
"--force-exclude",
]
if config_file:
command.append("--config={}".format(config_file))
child = Popen(command, stdout=PIPE, stderr=PIPE)
stdout, stderr = child.communicate()

Expand All @@ -104,9 +121,11 @@ def check_file(path):
raise RuffError(stderr.decode())


def format_file(path):
def format_file(path, config_file):
ruff = find_ruff_bin()
command = [ruff, "format", path, "--quiet", "--check", "--force-exclude"]
if config_file:
command.append("--config={}".format(config_file))
with Popen(command) as child:
pass

Expand All @@ -125,9 +144,10 @@ def pytest_exception_interact(node, call, report):
class RuffItem(pytest.Item):
name = "ruff"

def __init__(self, *k, **kwargs):
def __init__(self, *k, config_file, **kwargs):
super().__init__(*k, **kwargs)
self.add_marker("ruff")
self._config_file = config_file

def setup(self):
ruffmtimes = get_stash(self.config)
Expand All @@ -148,11 +168,11 @@ def reportinfo(self):
return (self.fspath, None, "")

def handler(self, path):
return check_file(path)
return check_file(path, self._config_file)


class RuffFormatItem(RuffItem):
name = "ruff::format"

def handler(self, path):
return format_file(path)
return format_file(path, self._config_file)
2 changes: 2 additions & 0 deletions tests/assets/long_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# File with just 1 value that conforms to the override config file but breaks the default
a = "This is a very long string that goes over the default number of characters, " + "but according to the config override should be fine"
2 changes: 2 additions & 0 deletions tests/assets/long_line_config/ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# longer than the default at the project root
line-length = 140
41 changes: 39 additions & 2 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ def test_configure_without_ruff(mocker):

def test_check_file():
with pytest.raises(pytest_ruff.RuffError, match=r"`os` imported but unused"):
pytest_ruff.check_file("tests/assets/check_broken.py")
pytest_ruff.check_file("tests/assets/check_broken.py", None)


def test_format_file():
with pytest.raises(pytest_ruff.RuffError, match=r"File would be reformatted"):
pytest_ruff.format_file("tests/assets/format_broken.py")
pytest_ruff.format_file("tests/assets/format_broken.py", None)


def test_pytest_ruff():
Expand Down Expand Up @@ -98,6 +98,43 @@ def test_broken_ruff_config():
assert "unknown field `broken`" in out.decode()


def test_custom_ruff_config():
# fails with default
process = subprocess.Popen(
[
sys.executable,
"-m",
"pytest",
"--ruff",
"--ruff-format",
"tests/assets/long_line.py",
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
out, err = process.communicate()
assert err.decode() == ""
assert "File would be reformatted" in out.decode("utf-8")

# succeeds with custom
process = subprocess.Popen(
[
sys.executable,
"-m",
"pytest",
"--ruff",
"--ruff-format",
"--ruff-config=tests/assets/long_line_config/ruff.toml",
"tests/assets/long_line.py",
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
out, err = process.communicate()
assert err.decode() == ""
assert "tests/assets/long_line.py ." in out.decode()


def test_without_pytest_cache():
process = subprocess.Popen(
[
Expand Down