diff --git a/README.md b/README.md index 72adc48..9f40eba 100644 --- a/README.md +++ b/README.md @@ -316,6 +316,17 @@ change the docstring of the `ErrorInfo` class in the `refurb/checks/pathlib/with You can find the file for a given check by grep-ing for `code = XYZ`, where `XYZ` is the check you are looking for but with the `FURB` prefix removed. +Use the `--verbose` flag with `--explain` to find the filename for a given check. For example: + +``` +$ refurb --explain FURB123 --verbose +Filename: refurb/checks/readability/no_unnecessary_cast.py + +FURB123: no-redundant-cast [readability] + +... +``` + ## Why Does This Exist? I love doing code reviews: I like taking something and making it better, faster, more diff --git a/pyproject.toml b/pyproject.toml index 65433dd..2beee92 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "refurb" -version = "1.18.0" +version = "1.19.0" description = "A tool for refurbish and modernize Python codebases" authors = ["dosisod"] license = "GPL-3.0-only" diff --git a/refurb/explain.py b/refurb/explain.py index c86a56d..ccb084d 100644 --- a/refurb/explain.py +++ b/refurb/explain.py @@ -1,12 +1,16 @@ +from pathlib import Path from textwrap import dedent from refurb.loader import get_error_class, get_modules +from refurb.settings import Settings from .error import ErrorCode -def explain(lookup: ErrorCode, paths: list[str] | None = None) -> str: - for module in get_modules(paths or []): +def explain(settings: Settings) -> str: + lookup = settings.explain + + for module in get_modules(settings.load): error = get_error_class(module) if error and ErrorCode.from_error(error) == lookup: @@ -15,12 +19,22 @@ def explain(lookup: ErrorCode, paths: list[str] | None = None) -> str: if docstring.startswith(f"{error.__name__}("): return f'refurb: Explanation for "{lookup}" not found' + output = "" + + if settings.verbose: + root = Path(__file__).parent.parent + file = Path(module.__file__ or "").relative_to(root) + + output += f"Filename: {file}\n\n" + docstring = dedent(error.__doc__ or "").strip() name = error.name or "" error_code = ErrorCode.from_error(error) categories = " ".join(f"[{x}]" for x in error.categories) - return f"{error_code}: {name} {categories}\n\n{docstring}" + output += f"{error_code}: {name} {categories}\n\n{docstring}" + + return output return f'refurb: Error code "{lookup}" not found' diff --git a/refurb/main.py b/refurb/main.py index debc188..ee9e2e3 100644 --- a/refurb/main.py +++ b/refurb/main.py @@ -264,7 +264,7 @@ def main(args: list[str]) -> int: return 0 if settings.explain: - print(explain(settings.explain, settings.load or [])) + print(explain(settings)) return 0 diff --git a/test/test_explain.py b/test/test_explain.py index 796da92..d256a32 100644 --- a/test/test_explain.py +++ b/test/test_explain.py @@ -1,9 +1,10 @@ from refurb.error import ErrorCode from refurb.explain import explain +from refurb.settings import Settings def test_get_check_explanation_by_id() -> None: - explanation = explain(ErrorCode(100)) + explanation = explain(Settings(explain=ErrorCode(100))) from refurb.checks.pathlib.with_suffix import ErrorInfo as furb100 @@ -14,13 +15,24 @@ def test_get_check_explanation_by_id() -> None: assert all(cat in explanation for cat in furb100.categories) +def test_verbose_check_includes_filepath() -> None: + explanation = explain(Settings(explain=ErrorCode(100), verbose=True)) + + assert "Filename: " in explanation + + def test_error_if_check_doesnt_exist() -> None: - msg = explain(ErrorCode(999)) + msg = explain(Settings(explain=ErrorCode(999))) assert msg == 'refurb: Error code "FURB999" not found' def test_check_with_no_docstring_gives_error() -> None: - msg = explain(ErrorCode(102, "XYZ"), ["test.custom_checks"]) + msg = explain( + Settings( + explain=ErrorCode(102, "XYZ"), + load=["test.custom_checks"], + ) + ) assert msg == 'refurb: Explanation for "XYZ102" not found'