Skip to content
Open
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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,6 @@ Will not show up if no `.readthedocs.yml`/`.readthedocs.yaml` file is present.
- [`RF002`](https://learn.scientific-python.org/development/guides/style#RF002): Target version must be set
- [`RF003`](https://learn.scientific-python.org/development/guides/style#RF003): src directory doesn't need to be specified anymore (0.6+)
- [`RF101`](https://learn.scientific-python.org/development/guides/style#RF101): Bugbear must be selected
- [`RF102`](https://learn.scientific-python.org/development/guides/style#RF102): isort must be selected
- [`RF103`](https://learn.scientific-python.org/development/guides/style#RF103): pyupgrade must be selected
- `RF201`: Avoid using deprecated config settings
- `RF202`: Use (new) lint config section
Expand Down
17 changes: 4 additions & 13 deletions docs/guides/style.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,6 @@ won't tell you what or why it fixed things.
[tool.ruff.lint]
extend-select = [
"B", # flake8-bugbear
"I", # isort
"RUF", # Ruff-specific
"UP", # pyupgrade
]
Expand All @@ -290,24 +289,18 @@ extend-select = [
extend-select = [
"ARG", # flake8-unused-arguments
"B", # flake8-bugbear
"BLE", # flake8-blind-except
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"EM", # flake8-errmsg
"EXE", # flake8-executable
"FA", # flake8-future-annotations
"FLY", # flynt
"FURB", # refurb
"G", # flake8-logging-format
"I", # isort
"ICN", # flake8-import-conventions
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"NPY", # NumPy specific rules
"PD", # pandas-vet
"PERF", # perflint
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PL", # pylint
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
Expand All @@ -323,7 +316,6 @@ extend-select = [
"TC", # flake8-type-checking
"TRY", # tryceratops
"UP", # pyupgrade
"YTT", # flake8-2020
]
ignore = [
"PLR09", # Too many <...>
Expand Down Expand Up @@ -407,11 +399,10 @@ Here are some good error codes to enable on most (but not all!) projects:
stood the test of time. Not required if you use `extend-select` (`W` not
needed if you use a formatter)
- `B`: This finds patterns that are very bug-prone. {rr}`RF101`
- `I`: This sorts your includes. There are multiple benefits, such as smaller
diffs, fewer conflicts, a way to auto-inject `__future__` imports, and easier
for readers to tell what's built-in, third-party, and local. It has a lot of
configuration options, but defaults to a Black-compatible style.
{rr}`RF102`
- `I`: This sorts your includes (on by default since Ruff 0.16). Select this
group only if you also want `I002`, which can auto-inject imports, such as
`from __future__ import annotations`; it needs the
`lint.isort.required-imports` setting.
- `ARG`: This looks for unused arguments. You might need to `# noqa: ARG001`
occasionally, but it's overall pretty useful.
- `C4`: This looks for places that could use comprehensions, and can autofix
Expand Down
7 changes: 0 additions & 7 deletions src/sp_repo_review/checks/ruff.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,6 @@ class RF101(RF1xx):
name = "flake8-bugbear"


class RF102(RF1xx):
"isort must be selected"

code = "I"
name = "isort"


class RF103(RF1xx):
"pyupgrade must be selected"

Expand Down
32 changes: 28 additions & 4 deletions src/sp_repo_review/ruff_checks/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
select_info = json.load(f)
LIBS = frozenset(select_info["libs"])
SPECIALTY = frozenset(r["name"] for r in select_info["specialty"])
# Selected by Ruff without configuration (0.16+)
DEFAULTS = {r["name"]: r["reason"] for r in select_info["defaults"]}

with RESOURCE_DIR.joinpath("ignore.json").open(encoding="utf-8") as f:
IGNORE_INFO = json.load(f)
Expand Down Expand Up @@ -105,6 +107,7 @@ def _print_output_rich(
libs_items: dict[str, str],
spec_items: dict[str, str],
unselected_items: dict[str, str],
default_items: dict[str, str],
) -> None:
"""Print rich formatted output."""
import rich.columns
Expand All @@ -128,6 +131,10 @@ def _print_output_rich(
uns = "\n".join(_print_each_rich(unselected_items))

rich.print(rich.columns.Columns([panel_sel, panel_lib, panel_spec]))
if default_items:
rich.print("[yellow]Selected, but on by default [dim](safe to remove)")
for item in _print_each_rich(default_items):
rich.print(item)
if uns:
rich.print("[red]Unselected [dim](copy and paste ready)")
rich.print(uns)
Expand All @@ -138,12 +145,18 @@ def _print_output_plain(
libs_items: dict[str, str],
spec_items: dict[str, str],
unselected_items: dict[str, str],
default_items: dict[str, str],
) -> None:
"""Print plain formatted output."""
print("Selected:")
for item in _print_each_plain(selected_items):
print(item)

if default_items:
print("\nSelected, but on by default (safe to remove):")
for item in _print_each_plain(default_items):
print(item)

if libs_items:
print("\nLibrary specific:")
for item in _print_each_plain(libs_items):
Expand Down Expand Up @@ -236,18 +249,29 @@ def process_dir(path: Path, format: str = "auto") -> None:
_handle_all_selected(fmt, ruff_config)
return

selected_items = {k: v for k, v in LINT_INFO.items() if k in selected}
all_uns_items = {k: v for k, v in LINT_INFO.items() if k not in selected}
default_items = {
k: DEFAULTS[k] for k in LINT_INFO if k in selected & DEFAULTS.keys()
}
selected_items = {
k: v for k, v in LINT_INFO.items() if k in selected and k not in DEFAULTS
}
all_uns_items = {
k: v for k, v in LINT_INFO.items() if k not in selected and k not in DEFAULTS
}
unselected_items = {
k: v for k, v in all_uns_items.items() if k not in LIBS | SPECIALTY
}
libs_items = {k: v for k, v in all_uns_items.items() if k in LIBS}
spec_items = {k: v for k, v in all_uns_items.items() if k in SPECIALTY}

if fmt == "rich":
_print_output_rich(selected_items, libs_items, spec_items, unselected_items)
_print_output_rich(
selected_items, libs_items, spec_items, unselected_items, default_items
)
else:
_print_output_plain(selected_items, libs_items, spec_items, unselected_items)
_print_output_plain(
selected_items, libs_items, spec_items, unselected_items, default_items
)


def main() -> None:
Expand Down
12 changes: 11 additions & 1 deletion src/sp_repo_review/ruff_checks/select.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
{
"libs": ["AIR", "ASYNC", "DJ", "FAST", "INT", "NPY", "PD"],
"libs": ["AIR", "ASYNC", "DJ", "FAST", "NPY", "PD"],
"defaults": [
{ "name": "BLE", "reason": "on by default" },
{ "name": "DTZ", "reason": "on by default" },
{ "name": "FA", "reason": "on by default" },
{ "name": "FLY", "reason": "on by default" },
{ "name": "I", "reason": "on by default, except I002, which needs config" },
{ "name": "INT", "reason": "on by default" },
{ "name": "PIE", "reason": "on by default" },
{ "name": "YTT", "reason": "on by default" }
],
"specialty": [
{ "name": "CPY", "reason": "preview only" },
{ "name": "A", "reason": "Naming related" },
Expand Down
10 changes: 1 addition & 9 deletions tests/test_ruff.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,7 @@ def test_rf101_selected():


def test_rf101_missing():
assert not compute_check("RF101", ruff={"lint": {"select": ["I"]}}).result


def test_rf102_selected():
assert compute_check("RF102", ruff={"lint": {"select": ["I"]}}).result


def test_rf102_missing():
assert not compute_check("RF102", ruff={"lint": {"select": ["UP"]}}).result
assert not compute_check("RF101", ruff={"lint": {"select": ["UP"]}}).result


def test_rf103_selected():
Expand Down
19 changes: 19 additions & 0 deletions tests/test_ruff_checks_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,22 @@ def test_plain_format_has_quotes_and_comma(monkeypatch, tmp_path, capsys):
ruff_checks.process_dir(tmp_path, format="plain")
captured = capsys.readouterr()
assert '"A",' in captured.out


def test_plain_format_default_rules(monkeypatch, tmp_path, capsys):
"""Rules Ruff selects itself are reported as removable, not as missing."""
monkeypatch.setattr(ruff_checks, "ruff", lambda *_a, **_k: {"tool": "ruff"})
monkeypatch.setattr(ruff_checks, "get_rule_selection", lambda *_a, **_k: {"A", "B"})
monkeypatch.setattr(ruff_checks, "LINT_INFO", {"A": "Rule A", "B": "Rule B"})
monkeypatch.setattr(ruff_checks, "LIBS", frozenset())
monkeypatch.setattr(ruff_checks, "SPECIALTY", frozenset())
monkeypatch.setattr(
ruff_checks, "DEFAULTS", {"A": "on by default", "C": "likewise"}
)

ruff_checks.process_dir(tmp_path, format="plain")
captured = capsys.readouterr()
selected, defaults = captured.out.split("Selected, but on by default")
assert '"B",' in selected
assert '"A",' in defaults
assert '"C",' not in captured.out
7 changes: 0 additions & 7 deletions {{cookiecutter.project_name}}/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -288,24 +288,18 @@ show-fixes = true
extend-select = [
"ARG", # flake8-unused-arguments
"B", # flake8-bugbear
"BLE", # flake8-blind-except
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"EM", # flake8-errmsg
"EXE", # flake8-executable
"FA", # flake8-future-annotations
"FLY", # flynt
"FURB", # refurb
"G", # flake8-logging-format
"I", # isort
"ICN", # flake8-import-conventions
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"NPY", # NumPy specific rules
"PD", # pandas-vet
"PERF", # perflint
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PL", # pylint
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
Expand All @@ -321,7 +315,6 @@ extend-select = [
"TC", # flake8-type-checking
"TRY", # tryceratops
"UP", # pyupgrade
"YTT", # flake8-2020
]
ignore = [
"PLR09", # Too many <...>
Expand Down
Loading