diff --git a/.flake8 b/.flake8 new file mode 100644 index 000000000..98e9a7dbc --- /dev/null +++ b/.flake8 @@ -0,0 +1,108 @@ +[flake8] + +# Print the total number of errors: +count = true + +# Don't even try to analyze these: +extend-exclude = + # GitHub configs + .github, + # Cache files of MyPy + .mypy_cache, + # Cache files of pytest + .pytest_cache, + # Countless third-party libs in venvs + .tox, + # Occasional virtualenv dir + .venv, + # VS Code + .vscode, + # Metadata of `pip wheel` cmd is autogenerated + pip-wheel-metadata, + +# IMPORTANT: avoid using ignore option, always use extend-ignore instead +# Completely and unconditionally ignore the following errors: +extend-ignore = + # Legitimate cases, no need to "fix" these violations: + # D202: No blank lines allowed after function docstring, conflicts with `ruff format` + D202, + # E203: whitespace before ':', conflicts with `ruff format` + E203, + # E501: "line too long", its function is replaced by `flake8-length` + E501, + # W505: "doc line too long", its function is replaced by `flake8-length` + W505, + # I: flake8-isort is drunk + we have isort integrated into pre-commit + I, + # WPS305: "Found f string" -- nothing bad about this + WPS305, + # WPS322: "Found incorrect multi-line string" -- false-positives with + # attribute docstrings. Ref: + # https://github.com/wemake-services/wemake-python-styleguide/issues/3056 + WPS322, + # WPS326: "Found implicit string concatenation" -- nothing bad about this + WPS326, + # WPS428: "Found statement that has no effect" -- false-positives with + # attribute docstrings. Ref: + # https://github.com/wemake-services/wemake-python-styleguide/issues/3056 + WPS428, + # WPS462: "Wrong multiline string usage" -- false-positives with + # attribute docstrings. Ref: + # https://github.com/wemake-services/wemake-python-styleguide/issues/3056 + WPS462, + # WPS300: "Forbid imports relative to the current folder" -- we use relative imports + WPS300, + +# https://wemake-python-styleguide.readthedocs.io/en/latest/pages/usage/formatter.html +format = wemake + +# Let's not overcomplicate the code: +max-complexity = 10 + +# Accessibility/large fonts and PEP8 friendly. +# This is being flexibly extended through the `flake8-length`: +max-line-length = 79 + +# Allow certain violations in certain files: +# Please keep both sections of this list sorted, as it will be easier for others to find and add entries in the future +per-file-ignores = + # The following ignores have been researched and should be considered permanent + # each should be preceded with an explanation of each of the error codes + # If other ignores are added for a specific file in the section following this, + # these will need to be added to that line as well. + + tests/pytest/_cli_test.py: + # WPS431: "Forbid nested classes" -- this is a legitimate use case for tests + WPS431, + # WPS226: "Forbid the overuse of string literals" -- this is a legitimate use case for tests + WPS226, + # WPS115: "Require snake_case for naming class attributes" -- testing legitimate case, ignored in main code + WPS115, + # We will not spend time on fixing complexity in deprecated hook + src/pre_commit_terraform/terraform_docs_replace.py: WPS232 + +# Count the number of occurrences of each error/warning code and print a report: +statistics = true + +# ## Plugin-provided settings: ## + +# flake8-eradicate +# E800: +eradicate-whitelist-extend = isort:\s+\w+ + +# flake8-pytest-style +# PT001: +pytest-fixture-no-parentheses = true +# PT006: +pytest-parametrize-names-type = tuple +# PT007: +pytest-parametrize-values-type = tuple +pytest-parametrize-values-row-type = tuple +# PT023: +pytest-mark-no-parentheses = true + +# wemake-python-styleguide +# WPS410: "Forbid some module-level variables" -- __all__ is a legitimate use case +allowed-module-metadata = __all__ + +show-source = true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c0d86e84e..498a147bd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -112,6 +112,11 @@ repos: - --fix - id: ruff-format +- repo: https://github.com/wemake-services/wemake-python-styleguide + rev: 6d4ca2bdc16b3098422a2770728136fc0751b817 # frozen: 1.1.0 + hooks: + - id: wemake-python-styleguide + - repo: https://github.com/pre-commit/mirrors-mypy.git rev: 7010b10a09f65cd60a23c207349b539aa36dbec1 # frozen: v1.16.0 hooks: diff --git a/ruff.toml b/ruff.toml index 8bb19749a..0e57620ea 100644 --- a/ruff.toml +++ b/ruff.toml @@ -17,6 +17,7 @@ convention = "pep257" [lint] select = ["ALL"] preview = true +external = ["WPS"] # Do not remove noqa for wemake-python-style (WPS) checks ignore = [ "CPY001", # Skip copyright notice requirement at top of files ] diff --git a/src/pre_commit_terraform/_cli.py b/src/pre_commit_terraform/_cli.py index abd95df75..8c99e2b54 100644 --- a/src/pre_commit_terraform/_cli.py +++ b/src/pre_commit_terraform/_cli.py @@ -33,28 +33,28 @@ def invoke_cli_app(cli_args: list[str]) -> ReturnCodeType: parsed_cli_args.invoke_cli_app, ) - try: + try: # noqa: WPS225 - too many `except` cases return invoke_cli_app(parsed_cli_args) except PreCommitTerraformExit as exit_err: - # T201 - FIXME here and below - we will replace 'print' with - # logging later - print(f'App exiting: {exit_err!s}', file=sys.stderr) # noqa: T201 + # T201,WPS421 - FIXME here and below - we will replace 'print' + # with logging later + print(f'App exiting: {exit_err!s}', file=sys.stderr) # noqa: T201,WPS421 raise except PreCommitTerraformRuntimeError as unhandled_exc: - print( # noqa: T201 + print( # noqa: T201,WPS421 f'App execution took an unexpected turn: {unhandled_exc!s}. ' 'Exiting...', file=sys.stderr, ) return ReturnCode.ERROR except PreCommitTerraformBaseError as unhandled_exc: - print( # noqa: T201 + print( # noqa: T201,WPS421 f'A surprising exception happened: {unhandled_exc!s}. Exiting...', file=sys.stderr, ) return ReturnCode.ERROR except KeyboardInterrupt as ctrl_c_exc: - print( # noqa: T201 + print( # noqa: T201,WPS421 f'User-initiated interrupt: {ctrl_c_exc!s}. Exiting...', file=sys.stderr, ) diff --git a/src/pre_commit_terraform/_cli_subcommands.py b/src/pre_commit_terraform/_cli_subcommands.py index fc268e552..ba7a6982d 100644 --- a/src/pre_commit_terraform/_cli_subcommands.py +++ b/src/pre_commit_terraform/_cli_subcommands.py @@ -4,9 +4,9 @@ from ._types import CLISubcommandModuleProtocol -SUBCOMMAND_MODULES: list[CLISubcommandModuleProtocol] = [ +SUBCOMMAND_MODULES: tuple[CLISubcommandModuleProtocol] = ( terraform_docs_replace, -] +) __all__ = ('SUBCOMMAND_MODULES',) diff --git a/src/pre_commit_terraform/_structs.py b/src/pre_commit_terraform/_structs.py index 12cf0dad3..f701d71a9 100644 --- a/src/pre_commit_terraform/_structs.py +++ b/src/pre_commit_terraform/_structs.py @@ -9,8 +9,10 @@ class ReturnCode(IntEnum): To be used in check callable implementations. """ - OK = 0 - ERROR = 1 + # WPS115: "Require snake_case for naming class attributes". According to + # "Correct" example in docs - it's valid use case => false-positive + OK = 0 # noqa: WPS115 + ERROR = 1 # noqa: WPS115 __all__ = ('ReturnCode',) diff --git a/src/pre_commit_terraform/_types.py b/src/pre_commit_terraform/_types.py index c08320f71..69f71e690 100644 --- a/src/pre_commit_terraform/_types.py +++ b/src/pre_commit_terraform/_types.py @@ -14,7 +14,11 @@ class CLISubcommandModuleProtocol(Protocol): """A protocol for the subcommand-implementing module shape.""" - CLI_SUBCOMMAND_NAME: str + # WPS115: "Require snake_case for naming class attributes". + # This protocol describes module shapes and not regular classes. + # It's a valid use case as then it's used as constants: + # "CLI_SUBCOMMAND_NAME: Final[str] = 'hook-name'"" on top level + CLI_SUBCOMMAND_NAME: str # noqa: WPS115 """This constant contains a CLI.""" def populate_argument_parser( diff --git a/src/pre_commit_terraform/terraform_docs_replace.py b/src/pre_commit_terraform/terraform_docs_replace.py index 43f496bb1..3bfb3bc43 100644 --- a/src/pre_commit_terraform/terraform_docs_replace.py +++ b/src/pre_commit_terraform/terraform_docs_replace.py @@ -58,7 +58,9 @@ def populate_argument_parser(subcommand_parser: ArgumentParser) -> None: ) -def invoke_cli_app(parsed_cli_args: Namespace) -> ReturnCodeType: +# WPS231 - Found function with too much cognitive complexity +# We will not spend time on fixing complexity in deprecated hook +def invoke_cli_app(parsed_cli_args: Namespace) -> ReturnCodeType: # noqa: WPS231 """Run the entry-point of the CLI app. Returns: @@ -86,7 +88,7 @@ def invoke_cli_app(parsed_cli_args: Namespace) -> ReturnCodeType: retval = ReturnCode.OK for directory in dirs: - try: + try: # noqa: WPS229 - ignore as it's deprecated hook proc_args = [] proc_args.append('terraform-docs') if cast_to('bool', parsed_cli_args.sort): @@ -107,8 +109,10 @@ def invoke_cli_app(parsed_cli_args: Namespace) -> ReturnCodeType: subprocess.check_call(' '.join(proc_args), shell=True) # noqa: S602 # PERF203 - try-except shouldn't be in a loop, but it's deprecated # hook, so leave as is - except subprocess.CalledProcessError as e: # noqa: PERF203 - # T201 - Leave print statement as is, as this is deprecated hook - print(e) # noqa: T201 + # WPS111 - Too short var name, but it's deprecated hook, so leave as is + except subprocess.CalledProcessError as e: # noqa: PERF203,WPS111 + # T201,WPS421 - Leave print statement as is, as this is + # deprecated hook + print(e) # noqa: T201,WPS421,WPS111 retval = ReturnCode.ERROR return retval diff --git a/tests/pytest/_cli_test.py b/tests/pytest/_cli_test.py index fd4b1fef5..773825269 100644 --- a/tests/pytest/_cli_test.py +++ b/tests/pytest/_cli_test.py @@ -55,7 +55,7 @@ def populate_argument_parser( self, subcommand_parser: ArgumentParser, ) -> None: - return None + pass # noqa: WPS420. This is a stub, docstring not needed so "pass" required. def invoke_cli_app(self, parsed_cli_args: Namespace) -> ReturnCodeType: raise raised_error @@ -85,7 +85,7 @@ def populate_argument_parser( self, subcommand_parser: ArgumentParser, ) -> None: - return None + pass # noqa: WPS420. This is a stub, docstring not needed so "pass" required. def invoke_cli_app(self, parsed_cli_args: Namespace) -> ReturnCodeType: raise PreCommitTerraformExit(self.CLI_SUBCOMMAND_NAME)