From 559ac11db9b3dc1576a3f24a72f065fc80802c74 Mon Sep 17 00:00:00 2001 From: Hasier Date: Thu, 22 May 2025 12:51:49 +0100 Subject: [PATCH 1/2] Add custom config argument --- pytest_ruff/__init__.py | 36 ++++++++++++++++++++++++++++-------- tests/test_plugin.py | 4 ++-- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/pytest_ruff/__init__.py b/pytest_ruff/__init__.py index 7709aca..235d42f 100644 --- a/pytest_ruff/__init__.py +++ b/pytest_ruff/__init__.py @@ -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): @@ -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, @@ -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() @@ -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 @@ -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) @@ -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) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index a3facd8..c0efd2f 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -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(): From c70eb04c7da3a20be5c3267353f8b9652d2526e4 Mon Sep 17 00:00:00 2001 From: Hasier Date: Thu, 22 May 2025 13:01:31 +0100 Subject: [PATCH 2/2] Add test --- tests/assets/long_line.py | 2 ++ tests/assets/long_line_config/ruff.toml | 2 ++ tests/test_plugin.py | 37 +++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/assets/long_line.py create mode 100644 tests/assets/long_line_config/ruff.toml diff --git a/tests/assets/long_line.py b/tests/assets/long_line.py new file mode 100644 index 0000000..bc6429c --- /dev/null +++ b/tests/assets/long_line.py @@ -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" diff --git a/tests/assets/long_line_config/ruff.toml b/tests/assets/long_line_config/ruff.toml new file mode 100644 index 0000000..d73ed1e --- /dev/null +++ b/tests/assets/long_line_config/ruff.toml @@ -0,0 +1,2 @@ +# longer than the default at the project root +line-length = 140 diff --git a/tests/test_plugin.py b/tests/test_plugin.py index c0efd2f..efee0ea 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -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( [