Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Backpush to main changes to skeleton of python hooks #741

Draft
wants to merge 75 commits into
base: master
Choose a base branch
from

Conversation

MaxymVlasov
Copy link
Collaborator

@MaxymVlasov MaxymVlasov commented Jan 3, 2025

Put an x into the box if that apply:

  • This PR introduces breaking change.
  • This PR fixes a bug.
  • This PR adds new functionality.
  • This PR enhances existing functionality.

Description of your changes

This PR includes only changes to skeleton of python hooks, w/o addition of hooks itself, as it will be required a new release.

Changes includes but not limited to:

  • Addition of basic tests in Pytest (mostly generated by GH Copilot, so could be not very useful, but at least they catch basic issues)
  • Rename basic skeleton things to more usual in bash (like CLI_SUBCOMMAND_NAME to HOOK_ID)
  • Dropping of support of Python 2 in python package definition - it was never supported - terraform_docs_replace using python 3 syntax here from hook addition
  • Addition of linters and fix most of found issues
    • Would be nice to support relative imports of submodules, but I didn't find solution that will be pass linters, especially mypy - error: No parent module -- cannot perform relative import - Found 1 error in 1 file (errors prevented further checking)
  • Reimplementation of _common.sh functionality. Located mostly in _common.py, _run_on_whole_repo.py and _logger.py. common::parse_cmdline function was fully reworked by @webknjaz in prev PRs and now populated with common functionality in _cli_parsing.py

This PR DOES NOT include any hooks additions or breaking changes for existing hooks. In branch with hooks exist a bunch of TODOs part of which could result in rework of functional in this PR. But there are already many changes, and this could block @webknjaz to implement testing best practices, so I checkout to new branch, dropped everything which could end in new release and created this PR to merge non-user-faced changes to master

How can we test changes

You can

repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: a278a04b257f82ee86c84410e7f462fb357a9810
    hooks:
      - id: terraform_docs_replace

or play around using updated CONTIBUTING.md notes

Additional references

This PR includes and based on work of @webknjaz who set all these best-practice CLI structure in pre PRs and fixed essential bug of accessing .pre-commit-hooks.yaml values in not-yet-released python hooks (#740 (included in this PR)) and initial work of @ericfrederich who shown us in #652 that reimplementation in Python can be done relatively easy

Summary by CodeRabbit

  • New Features
     - Expanded pre-commit hook support with new linting, formatting, and static analysis checks.
     - Improved CLI argument parsing that offers clearer usage instructions and more robust error handling.

  • Improvements
     - Updated CI/CD to run on Python 3.10 for enhanced compatibility.
     - Enhanced IDE configuration for improved module resolution.
     - Refined build and package settings to ensure essential configuration files are included.
     - Updated project metadata and dependencies for better alignment with current standards.

  • Tests
     - Extended test coverage to bolster stability and validate command-line behavior.

mock_subcommand_modules,
)

from pre_commit_terraform._cli_subcommands import (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not add imports within functions. It's a really bad idea that makes runtime less predictable / more difficult to interpret. Also, it's already imported at the top, it's not going to load the file for the second time, it's already cached. Don't disable the linters that report that this is dumb.

Comment on lines +2 to +3
import os
from os.path import join
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double import. Don't. Just don't. Enable the linters and fix the problems instead of showing this to other humans.

# ?
# ? get_unique_dirs
# ?
def test_get_unique_dirs_empty():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring?

Comment on lines +148 to +181
def test_parse_env_vars_empty():
env_var_strs = []
result = parse_env_vars(env_var_strs)
assert result == {}


def test_parse_env_vars_single():
env_var_strs = ['VAR1=value1']
result = parse_env_vars(env_var_strs)
assert result == {'VAR1': 'value1'}


def test_parse_env_vars_multiple():
env_var_strs = ['VAR1=value1', 'VAR2=value2']
result = parse_env_vars(env_var_strs)
assert result == {'VAR1': 'value1', 'VAR2': 'value2'}


def test_parse_env_vars_with_quotes():
env_var_strs = ['VAR1="value1"', 'VAR2="value2"']
result = parse_env_vars(env_var_strs)
assert result == {'VAR1': 'value1', 'VAR2': 'value2'}


def test_parse_env_vars_with_equal_sign_in_value():
env_var_strs = ['VAR1=value=1', 'VAR2=value=2']
result = parse_env_vars(env_var_strs)
assert result == {'VAR1': 'value=1', 'VAR2': 'value=2'}


def test_parse_env_vars_with_empty_value():
env_var_strs = ['VAR1=', 'VAR2=']
result = parse_env_vars(env_var_strs)
assert result == {'VAR1': '', 'VAR2': ''}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parametrize

Comment on lines +187 to +226
def test_expand_env_vars_no_vars():
args = ['arg1', 'arg2']
env_vars = {}
result = expand_env_vars(args, env_vars)
assert result == ['arg1', 'arg2']


def test_expand_env_vars_single_var():
args = ['arg1', '${VAR1}', 'arg3']
env_vars = {'VAR1': 'value1'}
result = expand_env_vars(args, env_vars)
assert result == ['arg1', 'value1', 'arg3']


def test_expand_env_vars_multiple_vars():
args = ['${VAR1}', 'arg2', '${VAR2}']
env_vars = {'VAR1': 'value1', 'VAR2': 'value2'}
result = expand_env_vars(args, env_vars)
assert result == ['value1', 'arg2', 'value2']


def test_expand_env_vars_no_expansion():
args = ['arg1', 'arg2']
env_vars = {'VAR1': 'value1'}
result = expand_env_vars(args, env_vars)
assert result == ['arg1', 'arg2']


def test_expand_env_vars_partial_expansion():
args = ['arg1', '${VAR1}', '${VAR2}']
env_vars = {'VAR1': 'value1'}
result = expand_env_vars(args, env_vars)
assert result == ['arg1', 'value1', '${VAR2}']


def test_expand_env_vars_with_special_chars():
args = ['arg1', '${VAR_1}', 'arg3']
env_vars = {'VAR_1': 'value1'}
result = expand_env_vars(args, env_vars)
assert result == ['arg1', 'value1', 'arg3']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parametrize

Comment on lines +232 to +263
def test_get_tf_binary_path_from_hook_config():
hook_config = ['--tf-path=/custom/path/to/terraform']
result = get_tf_binary_path(hook_config)
assert result == '/custom/path/to/terraform'


def test_get_tf_binary_path_from_pct_tfpath_env_var(mocker):
hook_config = []
mocker.patch.dict(os.environ, {'PCT_TFPATH': '/env/path/to/terraform'})
result = get_tf_binary_path(hook_config)
assert result == '/env/path/to/terraform'


def test_get_tf_binary_path_from_terragrunt_tfpath_env_var(mocker):
hook_config = []
mocker.patch.dict(os.environ, {'TERRAGRUNT_TFPATH': '/env/path/to/terragrunt'})
result = get_tf_binary_path(hook_config)
assert result == '/env/path/to/terragrunt'


def test_get_tf_binary_path_from_system_path_terraform(mocker):
hook_config = []
mocker.patch('shutil.which', return_value='/usr/local/bin/terraform')
result = get_tf_binary_path(hook_config)
assert result == '/usr/local/bin/terraform'


def test_get_tf_binary_path_from_system_path_tofu(mocker):
hook_config = []
mocker.patch('shutil.which', side_effect=[None, '/usr/local/bin/tofu'])
result = get_tf_binary_path(hook_config)
assert result == '/usr/local/bin/tofu'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parametrize


def test_get_tf_binary_path_from_pct_tfpath_env_var(mocker):
hook_config = []
mocker.patch.dict(os.environ, {'PCT_TFPATH': '/env/path/to/terraform'})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use monkeypatch.setenv()

Comment on lines +269 to +274
with pytest.raises(
BinaryNotFoundError,
match='Neither Terraform nor OpenTofu binary could be found. Please either set the "--tf-path"'
+ ' hook configuration argument, or set the "PCT_TFPATH" environment variable, or set the'
+ ' "TERRAGRUNT_TFPATH" environment variable, or install Terraform or OpenTofu globally.',
):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
with pytest.raises(
BinaryNotFoundError,
match='Neither Terraform nor OpenTofu binary could be found. Please either set the "--tf-path"'
+ ' hook configuration argument, or set the "PCT_TFPATH" environment variable, or set the'
+ ' "TERRAGRUNT_TFPATH" environment variable, or install Terraform or OpenTofu globally.',
):
error_msg = (
r'^Neither Terraform nor OpenTofu binary could be found. Please either set the "--tf-path" '
'hook configuration argument, or set the "PCT_TFPATH" environment variable, or set the '
'"TERRAGRUNT_TFPATH" environment variable, or install Terraform or OpenTofu globally\.$'
)
with pytest.raises(BinaryNotFoundError, match=error_msg):

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module is rather pointless. Delete it.

def sample_function():
pass

scope = globals()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this is nasty! Messing up the entire process state for all the test functions, eh? Don't do this. At least copy the thing instead of side-effecting everything...

Suggested change
scope = globals()
scope = globals().copy()

Comment on lines +17 to +18
scope = globals()
scope['sample_function'] = sample_function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But really.. Can't you just not go the unnecessarily complicated route? KISS.

Suggested change
scope = globals()
scope['sample_function'] = sample_function
scope = {'sample_function': sample_function}

Comment on lines +10 to +46
# ?
# ? is_function_defined
# ?
def test_is_function_defined_existing_function():
def sample_function():
pass

scope = globals()
scope['sample_function'] = sample_function

assert is_function_defined('sample_function', scope) is True


def test_is_function_defined_non_existing_function():
scope = globals()

assert is_function_defined('non_existing_function', scope) is False


def test_is_function_defined_non_callable():
non_callable = 'I am not a function'
scope = globals()
scope['non_callable'] = non_callable

assert is_function_defined('non_callable', scope) is False


def test_is_function_defined_callable_object():
class CallableObject:
def __call__(self):
pass

callable_object = CallableObject()
scope = globals()
scope['callable_object'] = callable_object

assert is_function_defined('callable_object', scope) is True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parametrize

Comment on lines +71 to +108
def test_is_hook_run_on_whole_repo(mocker, mock_git_ls_files, mock_hooks_config):
# Mock the return value of git ls-files
mocker.patch('subprocess.check_output', return_value='\n'.join(mock_git_ls_files))
# Mock the return value of reading the .pre-commit-hooks.yaml file
mocker.patch('builtins.open', mocker.mock_open(read_data=yaml.dump(mock_hooks_config)))
# Mock the Path object to return a specific path
mock_path = mocker.patch('pathlib.Path.resolve')
mock_path.return_value.parents.__getitem__.return_value = Path('/mocked/path')
# Mock the read_text method of Path to return the hooks config
mocker.patch('pathlib.Path.read_text', return_value=yaml.dump(mock_hooks_config))

# Test case where files match the included pattern and do not match the excluded pattern
files = [
'environment/prd/backends.tf',
'environment/prd/data.tf',
'environment/prd/main.tf',
'environment/prd/outputs.tf',
'environment/prd/providers.tf',
'environment/prd/variables.tf',
'environment/prd/versions.tf',
'environment/qa/backends.tf',
]
assert is_hook_run_on_whole_repo('example_hook_id', files) is True

# Test case where files do not match the included pattern
files = ['environment/prd/README.md']
assert is_hook_run_on_whole_repo('example_hook_id', files) is False

# Test case where files match the excluded pattern
files = ['environment/prd/.terraform/config.tf']
assert is_hook_run_on_whole_repo('example_hook_id', files) is False

# Test case where hook_id is not found
with pytest.raises(
ValueError,
match='Hook ID "non_existing_hook_id" not found in .pre-commit-hooks.yaml',
):
is_hook_run_on_whole_repo('non_existing_hook_id', files)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually multiple tests stuffed into one. They should be split, perhaps parametrized.

Of mocking, you can use tmp_path and generate an actual example Git repo and just run the test against that. With mocks you're mostly testing your mocks and not logic. Especially, with this many in place.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't very useful either. Delete.

Comment on lines +28 to +36
assert isinstance(MockSubcommandModule(), CLISubcommandModuleProtocol)

class InvalidSubcommandModule:
HOOK_ID = 'invalid_hook'

def populate_argument_parser(self, subcommand_parser: ArgumentParser) -> None:
pass

assert not isinstance(InvalidSubcommandModule(), CLISubcommandModuleProtocol)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like two separate tests, they shouldn't be one.

Copy link
Contributor

@webknjaz webknjaz Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, this is merely checking that CPython stdlib works. I don't see it being useful and would just remove it.

@MaxymVlasov MaxymVlasov marked this pull request as draft January 8, 2025 12:04
@webknjaz
Copy link
Contributor

webknjaz commented Jan 8, 2025

@MaxymVlasov look into how the tests are structured in the test infra PR and follow that. Avoid mocks where possible. When we get to have a call, I'll show you how to inspect coverage locally to judge if you even need a test.

.gitignore Outdated Show resolved Hide resolved
args: [--force-single-line, --profile=black]
exclude: |
(?x)
# Uses incorrect indentation in imports in places where it shouldn't
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, this ignore is irrelevant because your code defies best practices. It should be fixed instead of skipping the checks.

Copy link

codecov bot commented Jan 8, 2025

❌ 18 Tests Failed:

Tests completed Failed Passed Skipped
18 18 0 0
View the top 3 failed tests by shortest run time
tests/pytest/_cli_test.py::::tests.pytest._cli_test
Stack Traces | 0s run time
#x1B[1m#x1B[31mtests/pytest/_cli_test.py#x1B[0m:8: in <module>
    from pre_commit_terraform import _cli_parsing as _cli_parsing_mod
        ArgumentParser = <class 'argparse.ArgumentParser'>
        Namespace  = <class 'argparse.Namespace'>
        __builtins__ = <builtins>
        __cached__ = '.../pytest/__pycache__/_cli_test.cpython-312.pyc'
        __doc__    = 'Tests for the high-level CLI entry point.'
        __file__   = '.../tests/pytest/_cli_test.py'
        __loader__ = <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f3d19c0f440>
        __name__   = '_cli_test'
        __package__ = ''
        __spec__   = ModuleSpec(name='_cli_test', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f3d19c0f440>, origin='.../tests/pytest/_cli_test.py')
        pytest     = <module 'pytest' from '.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12.../site-packages/pytest/__init__.py'>
#x1B[1m#x1B[31m.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/_cli_parsing.py#x1B[0m:9: in <module>
    from pre_commit_terraform._cli_subcommands import SUBCOMMAND_MODULES
        ArgumentParser = <class 'argparse.ArgumentParser'>
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12.../pre_commit_terraform/__pycache__/_cli_parsing.cpython-312.pyc'
        __doc__    = 'Argument parser initialization logic.\n\nThis defines helpers for setting up both the root parser and the parsers\nof all the sub-commands.\n'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/_cli_parsing.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f3d1922d910>
        __name__   = 'pre_commit_terraform._cli_parsing'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._cli_parsing', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7....../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/_cli_parsing.py')
#x1B[1m#x1B[31m.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/_cli_subcommands.py#x1B[0m:3: in <module>
    from pre_commit_terraform import terraform_docs_replace
        __annotations__ = {}
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12.../pre_commit_terraform/__pycache__/_cli_subcommands.cpython-312.pyc'
        __doc__    = 'A CLI sub-commands organization module.'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/_cli_subcommands.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f3d1922ecc0>
        __name__   = 'pre_commit_terraform._cli_subcommands'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._cli_subcommands', loader=<_frozen_importlib_external.SourceFileLoader object at...e-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/_cli_subcommands.py')
#x1B[1m#x1B[31m.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/terraform_docs_replace.py#x1B[0m:12: in <module>
    from pre_commit_terraform._types import ReturnCodeType
        ArgumentParser = <class 'argparse.ArgumentParser'>
        Final      = typing.Final
        Namespace  = <class 'argparse.Namespace'>
        ReturnCode = <enum 'ReturnCode'>
        __annotations__ = {}
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12.../pre_commit_terraform/__pycache__/terraform_docs_replace.cpython-312.pyc'
        __doc__    = "Deprecated hook. Don't use it."
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/terraform_docs_replace.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f3d1922fc80>
        __name__   = 'pre_commit_terraform.terraform_docs_replace'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform.terraform_docs_replace', loader=<_frozen_importlib_external.SourceFileLoader obj...it-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/terraform_docs_replace.py')
        cast_to    = <function cast at 0x7f3d1a6c0180>
        os         = <module 'os' (frozen)>
        subprocess = <module 'subprocess' from '.../hostedtoolcache/Python/3.12.8....../x64/lib/python3.12/subprocess.py'>
        warnings   = <module 'warnings' from '.../hostedtoolcache/Python/3.12.8....../x64/lib/python3.12/warnings.py'>
#x1B[1m#x1B[31m.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/_types.py#x1B[0m:15: in <module>
    @runtime_checkable
#x1B[1m#x1B[31mE   NameError: name 'runtime_checkable' is not defined#x1B[0m
        ArgumentParser = <class 'argparse.ArgumentParser'>
        CLIAppEntryPointCallableType = collections.abc.Callable[[argparse.Namespace], typing.Union[pre_commit_terraform._structs.ReturnCode, int]]
        Callable   = <class 'collections.abc.Callable'>
        Namespace  = <class 'argparse.Namespace'>
        Protocol   = <class 'typing.Protocol'>
        ReturnCode = <enum 'ReturnCode'>
        ReturnCodeType = typing.Union[pre_commit_terraform._structs.ReturnCode, int]
        Union      = typing.Union
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12.../pre_commit_terraform/__pycache__/_types.cpython-312.pyc'
        __doc__    = 'Composite types for annotating in-project code.'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/_types.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f3d190b0050>
        __name__   = 'pre_commit_terraform._types'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._types', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f3d190...er/wor.../pre-commit-terraform/pre-commit-terraform/.tox......................................./py/lib/python3.12........./site-packages/pre_commit_terraform/_types.py')
tests/pytest/test__cli.py::tests.pytest.test__cli
Stack Traces | 0s run time
#x1B[1m#x1B[31mtests/pytest/test__cli.py#x1B[0m:3: in <module>
    from pre_commit_terraform._cli import invoke_cli_app
        __builtins__ = <builtins>
        __cached__ = '.../pytest/__pycache__/test__cli.cpython-311.pyc'
        __doc__    = None
        __file__   = '.../tests/pytest/test__cli.py'
        __loader__ = <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f74bbfe4a50>
        __name__   = 'test__cli'
        __package__ = ''
        __spec__   = ModuleSpec(name='test__cli', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f74bbfe4a50>, origin='.../tests/pytest/test__cli.py')
        pytest     = <module 'pytest' from '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11.../site-packages/pytest/__init__.py'>
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_cli.py#x1B[0m:6: in <module>
    from ._cli_parsing import initialize_argument_parser
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11.../pre_commit_terraform/__pycache__/_cli.cpython-311.pyc'
        __doc__    = 'Outer CLI layer of the app interface.'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_cli.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f74bb180290>
        __name__   = 'pre_commit_terraform._cli'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._cli', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f74bb180....../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_cli.py')
        cast_to    = <function cast at 0x7f74bc8ed300>
        sys        = <module 'sys' (built-in)>
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_cli_parsing.py#x1B[0m:9: in <module>
    from pre_commit_terraform._cli_subcommands import SUBCOMMAND_MODULES
        ArgumentParser = <class 'argparse.ArgumentParser'>
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11.../pre_commit_terraform/__pycache__/_cli_parsing.cpython-311.pyc'
        __doc__    = 'Argument parser initialization logic.\n\nThis defines helpers for setting up both the root parser and the parsers\nof all the sub-commands.\n'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_cli_parsing.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f74bb0e3b90>
        __name__   = 'pre_commit_terraform._cli_parsing'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._cli_parsing', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7....../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_cli_parsing.py')
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_cli_subcommands.py#x1B[0m:3: in <module>
    from pre_commit_terraform import terraform_docs_replace
        __annotations__ = {}
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11.../pre_commit_terraform/__pycache__/_cli_subcommands.cpython-311.pyc'
        __doc__    = 'A CLI sub-commands organization module.'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_cli_subcommands.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f74bb682b50>
        __name__   = 'pre_commit_terraform._cli_subcommands'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._cli_subcommands', loader=<_frozen_importlib_external.SourceFileLoader object at...e-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_cli_subcommands.py')
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/terraform_docs_replace.py#x1B[0m:12: in <module>
    from pre_commit_terraform._types import ReturnCodeType
        ArgumentParser = <class 'argparse.ArgumentParser'>
        Final      = typing.Final
        Namespace  = <class 'argparse.Namespace'>
        ReturnCode = <enum 'ReturnCode'>
        __annotations__ = {}
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11.../pre_commit_terraform/__pycache__/terraform_docs_replace.cpython-311.pyc'
        __doc__    = "Deprecated hook. Don't use it."
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/terraform_docs_replace.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f74bb15b210>
        __name__   = 'pre_commit_terraform.terraform_docs_replace'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform.terraform_docs_replace', loader=<_frozen_importlib_external.SourceFileLoader obj...it-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/terraform_docs_replace.py')
        cast_to    = <function cast at 0x7f74bc8ed300>
        os         = <module 'os' (frozen)>
        subprocess = <module 'subprocess' from '.../hostedtoolcache/Python/3.11.11....../x64/lib/python3.11/subprocess.py'>
        warnings   = <module 'warnings' from '.../hostedtoolcache/Python/3.11.11....../x64/lib/python3.11/warnings.py'>
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_types.py#x1B[0m:15: in <module>
    @runtime_checkable
#x1B[1m#x1B[31mE   NameError: name 'runtime_checkable' is not defined#x1B[0m
        ArgumentParser = <class 'argparse.ArgumentParser'>
        CLIAppEntryPointCallableType = collections.abc.Callable[[argparse.Namespace], typing.Union[pre_commit_terraform._structs.ReturnCode, int]]
        Callable   = <class 'collections.abc.Callable'>
        Namespace  = <class 'argparse.Namespace'>
        Protocol   = <class 'typing.Protocol'>
        ReturnCode = <enum 'ReturnCode'>
        ReturnCodeType = typing.Union[pre_commit_terraform._structs.ReturnCode, int]
        Union      = typing.Union
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11.../pre_commit_terraform/__pycache__/_types.cpython-311.pyc'
        __doc__    = 'Composite types for annotating in-project code.'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_types.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f74bb159bd0>
        __name__   = 'pre_commit_terraform._types'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._types', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f74bb1...er/wor.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.11........./site-packages/pre_commit_terraform/_types.py')
tests/pytest/test__cli.py::tests.pytest.test__cli
Stack Traces | 0s run time
#x1B[1m#x1B[31mtests/pytest/test__cli.py#x1B[0m:3: in <module>
    from pre_commit_terraform._cli import invoke_cli_app
        __builtins__ = <builtins>
        __cached__ = '.../pytest/__pycache__/test__cli.cpython-39.pyc'
        __doc__    = None
        __file__   = '.../tests/pytest/test__cli.py'
        __loader__ = <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f2ba79c9220>
        __name__   = 'test__cli'
        __package__ = ''
        __spec__   = ModuleSpec(name='test__cli', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7f2ba79c9220>, origin='.../tests/pytest/test__cli.py')
        pytest     = <module 'pytest' from '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9.../site-packages/pytest/__init__.py'>
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_cli.py#x1B[0m:6: in <module>
    from ._cli_parsing import initialize_argument_parser
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9.../pre_commit_terraform/__pycache__/_cli.cpython-39.pyc'
        __doc__    = 'Outer CLI layer of the app interface.'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_cli.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f2ba7c8b6d0>
        __name__   = 'pre_commit_terraform._cli'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._cli', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f2ba7c8b....../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_cli.py')
        cast_to    = <function cast at 0x7f2ba83933a0>
        sys        = <module 'sys' (built-in)>
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_cli_parsing.py#x1B[0m:9: in <module>
    from pre_commit_terraform._cli_subcommands import SUBCOMMAND_MODULES
        ArgumentParser = <class 'argparse.ArgumentParser'>
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9.../pre_commit_terraform/__pycache__/_cli_parsing.cpython-39.pyc'
        __doc__    = 'Argument parser initialization logic.\n\nThis defines helpers for setting up both the root parser and the parsers\nof all the sub-commands.\n'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_cli_parsing.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f2ba7c8ba90>
        __name__   = 'pre_commit_terraform._cli_parsing'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._cli_parsing', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7....../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_cli_parsing.py')
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_cli_subcommands.py#x1B[0m:3: in <module>
    from pre_commit_terraform import terraform_docs_replace
        __annotations__ = {}
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9.../pre_commit_terraform/__pycache__/_cli_subcommands.cpython-39.pyc'
        __doc__    = 'A CLI sub-commands organization module.'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_cli_subcommands.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f2ba7c8be80>
        __name__   = 'pre_commit_terraform._cli_subcommands'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._cli_subcommands', loader=<_frozen_importlib_external.SourceFileLoader object at...re-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_cli_subcommands.py')
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/terraform_docs_replace.py#x1B[0m:12: in <module>
    from pre_commit_terraform._types import ReturnCodeType
        ArgumentParser = <class 'argparse.ArgumentParser'>
        Final      = typing.Final
        Namespace  = <class 'argparse.Namespace'>
        ReturnCode = <enum 'ReturnCode'>
        __annotations__ = {}
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9.../pre_commit_terraform/__pycache__/terraform_docs_replace.cpython-39.pyc'
        __doc__    = "Deprecated hook. Don't use it."
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/terraform_docs_replace.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f2ba7c8f1f0>
        __name__   = 'pre_commit_terraform.terraform_docs_replace'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform.terraform_docs_replace', loader=<_frozen_importlib_external.SourceFileLoader obj...mit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/terraform_docs_replace.py')
        cast_to    = <function cast at 0x7f2ba83933a0>
        os         = <module 'os' from '.../hostedtoolcache/Python/3.9.21........./x64/lib/python3.9/os.py'>
        subprocess = <module 'subprocess' from '.../hostedtoolcache/Python/3.9.21........./x64/lib/python3.9/subprocess.py'>
        warnings   = <module 'warnings' from '.../hostedtoolcache/Python/3.9.21........./x64/lib/python3.9/warnings.py'>
#x1B[1m#x1B[31m.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_types.py#x1B[0m:15: in <module>
    @runtime_checkable
#x1B[1m#x1B[31mE   NameError: name 'runtime_checkable' is not defined#x1B[0m
        ArgumentParser = <class 'argparse.ArgumentParser'>
        CLIAppEntryPointCallableType = collections.abc.Callable[[argparse.Namespace], typing.Union[pre_commit_terraform._structs.ReturnCode, int]]
        Callable   = <class 'collections.abc.Callable'>
        Namespace  = <class 'argparse.Namespace'>
        Protocol   = <class 'typing.Protocol'>
        ReturnCode = <enum 'ReturnCode'>
        ReturnCodeType = typing.Union[pre_commit_terraform._structs.ReturnCode, int]
        Union      = typing.Union
        __builtins__ = <builtins>
        __cached__ = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9.../pre_commit_terraform/__pycache__/_types.cpython-39.pyc'
        __doc__    = 'Composite types for annotating in-project code.'
        __file__   = '.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_types.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7f2ba7c8f580>
        __name__   = 'pre_commit_terraform._types'
        __package__ = 'pre_commit_terraform'
        __spec__   = ModuleSpec(name='pre_commit_terraform._types', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f2ba7c...ner/wo.../pre-commit-terraform/pre-commit-terraform/.tox................................................/py/lib/python3.9........./site-packages/pre_commit_terraform/_types.py')

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

Copy link

github-actions bot commented Feb 8, 2025

This PR has been automatically marked as stale because it has been open 30 days

with no activity. Remove stale label or comment or this PR will be closed in 10 days

@github-actions github-actions bot added the stale Denotes an issue or PR has remained open with no activity and has become stale. label Feb 8, 2025
Copy link

coderabbitai bot commented Feb 8, 2025

Walkthrough

The changes update configuration files, source code, and tests for the pre-commit Terraform tool. Configuration modifications include an upgraded Python version in GitHub Actions and new linting and formatting hooks. Source code updates adjust import paths, enhance CLI argument parsing, add common utilities, improve logging and error handling, and update subcommand protocols. A new file introduces reusable functions for environment variable processing and binary resolution. Additionally, tests have been extended to cover the new functionalities and modifications across multiple modules.

Changes

Files (Grouped) Change Summary
.github/workflows/pre-commit.yaml, .vscode/settings.json, hatch.toml, pyproject.toml, .pre-commit-config.yaml, .pre-commit-hooks.yaml Update Python version in GitHub Actions; add new linting/formatting hooks (ruff, isort, autopep8, pylint, wemake styleguide), update hadolint and mypy settings; remove/deprecate Terraform-related hooks and add terraform_checkov/terraform_trivy; add extra Python analysis path and include pre-commit hook file in build targets; update project description and add pyyaml dependency.
src/pre_commit_terraform/main.py, _cli.py, _cli_parsing.py, _cli_subcommands.py, _types.py, terraform_docs_replace.py Change import paths from relative to absolute; add new function (populate_common_argument_parser) and update subcommand parser behavior; update protocol attribute from CLI_SUBCOMMAND_NAME to HOOK_ID; reformat error handling and mark terraform_docs_replace hook as deprecated with new HOOK_ID constant and hook-specific argument parser.
src/pre_commit_terraform/_common.py, _logger.py, _run_on_whole_repo.py, _errors.py Introduce new utilities for environment variable parsing, file directory processing, binary resolution (with custom exception), colored logging, and functions to detect hook execution on the entire repository; reformat runtime error class.
tests/pytest/* Add and update tests across modules covering CLI execution, argument parsing, subcommand processing, environment variable utilities, error classes, binary lookup functions, and ReturnCode behavior; improve formatting and import clarity in several test files.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant M as __main__.py
    participant P as _cli_parsing.py
    participant C as _cli.py
    participant E as _errors.py

    U->>M: Execute CLI command
    M->>P: Initialize parser and parse arguments
    P-->>M: Return parsed args
    M->>C: Call invoke_cli_app(parsed_args)
    alt Successful execution
        C-->>M: Return OK code
    else Exception raised
        C->>E: Handle exception and format error message
        E-->>C: Return error code
    end
    M->>U: Exit with return code
Loading
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🔭 Outside diff range comments (1)
tests/pytest/test__run_on_whole_repo.py (1)

1-109: Rename file to match test pattern and refactor tests.

  1. The file name should be renamed to match the pattern '.*_test.py'.

  2. The tests should be parametrized for better maintainability.

  3. The global state modification should be avoided.

  4. Rename the file:

-tests/pytest/test__run_on_whole_repo.py
+tests/pytest/run_on_whole_repo_test.py
  1. Parametrize the tests:
@pytest.mark.parametrize(
    ('function_name', 'expected_result'),
    [
        ('sample_function', True),
        ('non_existing_function', False),
        ('non_callable', False),
        ('callable_object', True),
    ],
)
def test_is_function_defined(function_name: str, expected_result: bool) -> None:
    scope = {'sample_function': lambda: None, 'non_callable': 'not a function', 'callable_object': type('CallableObject', (), {'__call__': lambda x: None})()}
    assert is_function_defined(function_name, scope) is expected_result
  1. Use a temporary directory for Git repository tests:
def test_is_hook_run_on_whole_repo(tmp_path: Path) -> None:
    # Initialize Git repo
    repo_dir = tmp_path / "repo"
    repo_dir.mkdir()
    subprocess.run(['git', 'init'], cwd=repo_dir, check=True)
    
    # Create test files
    (repo_dir / "test.tf").write_text("")
    subprocess.run(['git', 'add', '.'], cwd=repo_dir, check=True)
    
    # Test hook execution
    assert is_hook_run_on_whole_repo('example_hook_id', ['test.tf']) is True
🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 1-1: tests/pytest/test__run_on_whole_repo.py does not match pattern '.*_test.py'

♻️ Duplicate comments (2)
tests/pytest/test__types.py (1)

18-36: 🛠️ Refactor suggestion

Split the test into positive and negative test cases.

Following the previous review feedback, this should be split into two separate test functions for better clarity and maintainability.

Apply this diff to split the tests:

-def test_cli_subcommand_module_protocol():
+def test_cli_subcommand_module_protocol_valid() -> None:
     class MockSubcommandModule:
         HOOK_ID = 'mock_hook'
 
         def populate_argument_parser(self, subcommand_parser: ArgumentParser) -> None:
             pass
 
         def invoke_cli_app(self, parsed_cli_args: Namespace) -> ReturnCodeType:
             return ReturnCode.OK
 
     assert isinstance(MockSubcommandModule(), CLISubcommandModuleProtocol)
 
+def test_cli_subcommand_module_protocol_invalid() -> None:
     class InvalidSubcommandModule:
         HOOK_ID = 'invalid_hook'
 
         def populate_argument_parser(self, subcommand_parser: ArgumentParser) -> None:
             pass
 
     assert not isinstance(InvalidSubcommandModule(), CLISubcommandModuleProtocol)
src/pre_commit_terraform/_cli_parsing.py (1)

35-41: 🛠️ Refactor suggestion

Update help text to be more abstract.

The help text should be tool-agnostic as it could be used with different tools like tofu, terraform-alpha, etc.

Apply this diff to make the help text more abstract:

-        help='Arguments for `tf init` command',
+        help="Arguments to tool's `init` sub-command",
🧹 Nitpick comments (6)
src/pre_commit_terraform/_types.py (1)

19-20: Update docstring to use correct terminology.

The constant represents a subcommand identifier, not just a CLI.

     HOOK_ID: str
-    """This constant contains a CLI."""
+    """This constant contains the subcommand identifier."""
src/pre_commit_terraform/_logger.py (1)

52-88: Add type hints to environment variable access.

The environment variable access could benefit from type hints to make the code more maintainable.

Apply this diff to add type hints:

+from typing import Literal, Optional

+LogLevel = Literal['error', 'warn', 'warning', 'info', 'debug']

 def setup_logging() -> None:
     log_level = {
         'error': logging.ERROR,
         'warn': logging.WARNING,
         'warning': logging.WARNING,
         'info': logging.INFO,
         'debug': logging.DEBUG,
-    }[os.environ.get('PCT_LOG', 'warning').lower()]
+    }[os.environ.get('PCT_LOG', 'warning').lower()]  # type: ignore[index]
tests/pytest/terraform_docs_replace_test.py (1)

85-85: Improve readability by using a more explicit implementation.

The list comprehension is concise but less readable. Consider using a more explicit implementation:

-    executed_commands = [cmd for ((cmd,), _shell) in check_call_mock.call_args_list]
+    executed_commands = []
+    for (cmd,), shell in check_call_mock.call_args_list:
+        executed_commands.append(cmd)
.pre-commit-hooks.yaml (1)

45-169: Further removal of Terraform-related hooks.
Hooks including 'terraform_validate', 'terraform_providers_lock', 'terraform_tflint', the various terragrunt hooks, 'terraform_tfsec', 'terraform_trivy', 'checkov', 'terraform_checkov', 'terraform_wrapper_module_for_each', 'terrascan', and 'tfupdate' have been removed. This change focuses the hook configuration on core Python-based functionality. Please verify that any dependent processes are updated to reflect these removals.

.pre-commit-config.yaml (2)

134-143: Add Ruff and Ruff-format hooks for Python linting.
The new hooks from 'astral-sh/ruff-pre-commit' provide fast linting and formatting fixes. Note that the ruff-format hook passes arguments with spaces around '=' (e.g. "format.quote-style = 'single'"); verify that these arguments are parsed correctly. Consider revising the format to “--config=format.quote-style=single” if needed.


196-219: Integrate wemake-python-styleguide hook with custom thresholds and exclusion.
The new hook from 'wemake-services/wemake-python-styleguide' is configured with increased limits for local variables, returns, and imports. It uses a multiline regex (with (?x) mode) to exclude specific test files and a deprecated hook file. While the extended regex allows inline comments, consider whether a single-line version might improve readability in future revisions.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8bedb53 and 1bdb83e.

📒 Files selected for processing (27)
  • .github/workflows/pre-commit.yaml (1 hunks)
  • .pre-commit-config.yaml (2 hunks)
  • .pre-commit-hooks.yaml (1 hunks)
  • .vscode/settings.json (1 hunks)
  • hatch.toml (2 hunks)
  • pyproject.toml (1 hunks)
  • src/pre_commit_terraform/__main__.py (1 hunks)
  • src/pre_commit_terraform/_cli.py (2 hunks)
  • src/pre_commit_terraform/_cli_parsing.py (2 hunks)
  • src/pre_commit_terraform/_cli_subcommands.py (1 hunks)
  • src/pre_commit_terraform/_common.py (1 hunks)
  • src/pre_commit_terraform/_errors.py (1 hunks)
  • src/pre_commit_terraform/_logger.py (1 hunks)
  • src/pre_commit_terraform/_run_on_whole_repo.py (1 hunks)
  • src/pre_commit_terraform/_types.py (1 hunks)
  • src/pre_commit_terraform/terraform_docs_replace.py (1 hunks)
  • tests/pytest/_cli_test.py (3 hunks)
  • tests/pytest/terraform_docs_replace_test.py (6 hunks)
  • tests/pytest/test___main__.py (1 hunks)
  • tests/pytest/test__cli.py (1 hunks)
  • tests/pytest/test__cli_parsing.py (1 hunks)
  • tests/pytest/test__cli_subcommands.py (1 hunks)
  • tests/pytest/test__common.py (1 hunks)
  • tests/pytest/test__errors.py (1 hunks)
  • tests/pytest/test__run_on_whole_repo.py (1 hunks)
  • tests/pytest/test__structs.py (1 hunks)
  • tests/pytest/test__types.py (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • src/pre_commit_terraform/_errors.py
  • tests/pytest/_cli_test.py
  • src/pre_commit_terraform/_cli.py
🧰 Additional context used
🪛 GitHub Actions: Common issues check
tests/pytest/test__errors.py

[error] 8-8: Function is missing a return type annotation.


[error] 13-13: Function is missing a return type annotation.


[error] 18-18: Function is missing a return type annotation.

tests/pytest/test__types.py

[error] 9-9: Function is missing a return type annotation.

tests/pytest/test___main__.py

[error] 1-1: tests/pytest/test___main__.py does not match pattern '.*_test.py'

src/pre_commit_terraform/_types.py

[error] 15-15: Name 'runtime_checkable' is not defined.

tests/pytest/test__structs.py

[error] 6-6: Function is missing a return type annotation.


[error] 11-11: Function is missing a return type annotation.


[error] 16-16: Function is missing a return type annotation.

tests/pytest/test__cli_subcommands.py

[error] 1-1: tests/pytest/test__cli_subcommands.py does not match pattern '.*_test.py'

tests/pytest/test__run_on_whole_repo.py

[error] 1-1: tests/pytest/test__run_on_whole_repo.py does not match pattern '.*_test.py'

src/pre_commit_terraform/_run_on_whole_repo.py

[error] 8-8: Library stubs not installed for 'yaml'.


[error] 13-13: Missing type parameters for generic type 'dict'.

tests/pytest/test__cli.py

[error] 10-10: Function is missing a type annotation.


[error] 25-25: Function is missing a type annotation.


[error] 40-40: Function is missing a type annotation.


[error] 55-55: Function is missing a type annotation.


[error] 70-70: Function is missing a type annotation.

tests/pytest/test__cli_parsing.py

[error] 9-9: Function is missing a return type annotation.


[error] 13-13: Function is missing a type annotation.


[error] 27-27: Function is missing a type annotation.


[error] 39-39: Function is missing a type annotation.


[error] 75-75: Function is missing a type annotation.


[error] 101-101: Function is missing a type annotation.


[error] 116-116: Function is missing a type annotation.


[error] 152-152: Function is missing a type annotation.


[error] 178-178: Function is missing a type annotation.


[error] 193-193: Function is missing a type annotation.

tests/pytest/test__common.py

[error] 17-17: Function is missing a return type annotation.


[error] 23-23: Function is missing a return type annotation.


[error] 29-29: Function is missing a return type annotation.


[error] 35-35: Function is missing a return type annotation.


[error] 41-41: Function is missing a return type annotation.


[error] 148-148: Function is missing a return type annotation.


[error] 154-154: Function is missing a return type annotation.


[error] 160-160: Function is missing a return type annotation.


[error] 166-166: Function is missing a return type annotation.


[error] 172-172: Function is missing a return type annotation.


[error] 178-178: Function is missing a return type annotation.


[error] 187-187: Function is missing a return type annotation.


[error] 194-194: Function is missing a return type annotation.


[error] 201-201: Function is missing a return type annotation.


[error] 208-208: Function is missing a return type annotation.


[error] 215-215: Function is missing a return type annotation.


[error] 222-222: Function is missing a return type annotation.


[error] 232-232: Function is missing a return type annotation.


[error] 238-238: Function is missing a return type annotation.


[error] 252-252: Function is missing a return type annotation.


[error] 259-259: Function is missing a return type annotation.


[error] 266-266: Function is missing a return type annotation.

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)
tests/pytest/test__errors.py

[error] 8-8: Function is missing a return type annotation.


[error] 13-13: Function is missing a return type annotation.


[error] 18-18: Function is missing a return type annotation.

tests/pytest/test__types.py

[error] 5-5: NameError: name 'runtime_checkable' is not defined

tests/pytest/terraform_docs_replace_test.py

[error] 11-11: NameError: name 'runtime_checkable' is not defined

src/pre_commit_terraform/_types.py

[error] 15-15: Undefined variable 'runtime_checkable'.

tests/pytest/test__structs.py

[error] 6-6: Function is missing a return type annotation.

tests/pytest/test__cli_subcommands.py

[error] 1-1: NameError: name 'runtime_checkable' is not defined

src/pre_commit_terraform/_run_on_whole_repo.py

[error] 8-8: Library stubs not installed for 'yaml'.


[error] 13-13: Missing type parameters for generic type 'dict'.


[error] 77-77: Line too long (101/100).

tests/pytest/test__cli.py

[error] 3-3: NameError: name 'runtime_checkable' is not defined

tests/pytest/test__cli_parsing.py

[error] 5-5: NameError: name 'runtime_checkable' is not defined

tests/pytest/test__common.py

[error] 17-17: Function is missing a return type annotation.


[error] 18-18: Need type annotation for 'files'.


[error] 23-23: Function is missing a return type annotation.


[error] 29-29: Function is missing a return type annotation.


[error] 35-35: Function is missing a return type annotation.


[error] 41-41: Function is missing a return type annotation.


[error] 148-148: Function is missing a return type annotation.


[error] 149-149: Need type annotation for 'env_var_strs'.


[error] 154-154: Function is missing a return type annotation.


[error] 160-160: Function is missing a return type annotation.


[error] 166-166: Function is missing a return type annotation.


[error] 172-172: Function is missing a return type annotation.


[error] 178-178: Function is missing a return type annotation.


[error] 187-187: Function is missing a return type annotation.


[error] 194-194: Function is missing a return type annotation.


[error] 201-201: Function is missing a return type annotation.


[error] 208-208: Function is missing a return type annotation.


[error] 215-215: Function is missing a return type annotation.


[error] 222-222: Function is missing a return type annotation.


[error] 232-232: Function is missing a return type annotation.


[error] 238-238: Function is missing a type annotation.


[error] 245-245: Function is missing a type annotation.


[error] 252-252: Function is missing a type annotation.


[error] 259-259: Function is missing a type annotation.


[error] 266-266: Function is missing a type annotation.

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)
tests/pytest/test__errors.py

[error] 8-8: Function is missing a return type annotation.


[error] 13-13: Function is missing a return type annotation.


[error] 18-18: Function is missing a return type annotation.

tests/pytest/test__types.py

[error] 5-5: NameError: name 'runtime_checkable' is not defined

tests/pytest/terraform_docs_replace_test.py

[error] 11-11: NameError: name 'runtime_checkable' is not defined

src/pre_commit_terraform/_types.py

[error] 15-15: Undefined variable 'runtime_checkable'.

tests/pytest/test__structs.py

[error] 6-6: Function is missing a return type annotation.


[error] 11-11: Function is missing a return type annotation.


[error] 16-16: Function is missing a return type annotation.

tests/pytest/test__cli_subcommands.py

[error] 1-1: NameError: name 'runtime_checkable' is not defined

src/pre_commit_terraform/_run_on_whole_repo.py

[error] 8-8: Library stubs not installed for 'yaml'.


[error] 13-13: Missing type parameters for generic type 'dict'.


[error] 24-24: Expression type contains 'Any' (has type 'dict[Any, Any]').


[error] 25-25: Expression type contains 'Any' (has type 'dict[Any, Any]').

tests/pytest/test__cli.py

[error] 3-3: NameError: name 'runtime_checkable' is not defined

tests/pytest/test__cli_parsing.py

[error] 5-5: NameError: name 'runtime_checkable' is not defined

tests/pytest/test__common.py

[error] 17-17: Function is missing a return type annotation.


[error] 23-23: Function is missing a return type annotation.


[error] 29-29: Function is missing a return type annotation.


[error] 35-35: Function is missing a return type annotation.


[error] 41-41: Function is missing a return type annotation.


[error] 148-148: Function is missing a return type annotation.


[error] 154-154: Function is missing a return type annotation.


[error] 160-160: Function is missing a return type annotation.


[error] 166-166: Function is missing a return type annotation.


[error] 172-172: Function is missing a return type annotation.


[error] 178-178: Function is missing a return type annotation.


[error] 187-187: Function is missing a return type annotation.


[error] 194-194: Function is missing a return type annotation.


[error] 201-201: Function is missing a return type annotation.


[error] 208-208: Function is missing a return type annotation.


[error] 215-215: Function is missing a return type annotation.


[error] 222-222: Function is missing a return type annotation.


[error] 232-232: Function is missing a return type annotation.


[error] 238-238: Function is missing a return type annotation.


[error] 245-245: Function is missing a return type annotation.


[error] 252-252: Function is missing a return type annotation.


[error] 259-259: Function is missing a return type annotation.


[error] 266-266: Function is missing a return type annotation.

🪛 Ruff (0.8.2)
src/pre_commit_terraform/_types.py

15-15: Undefined name runtime_checkable

(F821)

src/pre_commit_terraform/terraform_docs_replace.py

65-65: No explicit stacklevel keyword argument found

(B028)


82-82: Loop control variable directory not used within loop body

Rename unused directory to _directory

(B007)

🔇 Additional comments (36)
src/pre_commit_terraform/_common.py (6)

1-5: Module docstring is concise and informative.
No concerns here; it clearly states its purpose.


17-35: Consider handling improperly formatted inputs.
Splitting on "=" will fail if the string does not contain "=", or has unexpected whitespace. You may wish to strip whitespace or skip empty entries, as previously discussed.


38-49: Efficient generator expression usage.
Using a generator expression inside set() to compute unique directories is a clean and memory-efficient approach.


51-75: Double-check multi-expansion logic.
When an arg contains multiple placeholders or repeated environment variables, the loop may replace them successively. Ensure this behavior is desired in all scenarios.


78-120: Review final exit code logic.
Currently, if multiple directories fail, only the last non-zero exit code is returned. Consider whether aggregating or otherwise combining failures might be preferable.


122-179: Fallback strategy for locating Terraform/OpenTofu is sound.
The environment and PATH checks are well-ordered. No major issues identified.

src/pre_commit_terraform/__main__.py (2)

3-4: Separate imports improve clarity.
Explicitly importing argv and exit_with_return_code helps with readability.


6-6: Absolute import avoids confusion.
Using an explicit package path helps prevent relative import conflicts.

src/pre_commit_terraform/_cli_subcommands.py (1)

3-8: Immutability and absolute imports.
Defining SUBCOMMAND_MODULES as a tuple and using absolute imports aligns with Python best practices.

tests/pytest/test__structs.py (1)

6-19: LGTM! Well-structured tests covering essential functionality.

The tests effectively verify:

  • Return code values
  • Return code names
  • Error handling for invalid values
🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 6-6: Function is missing a return type annotation.


[error] 11-11: Function is missing a return type annotation.


[error] 16-16: Function is missing a return type annotation.

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 6-6: Function is missing a return type annotation.

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)

[error] 6-6: Function is missing a return type annotation.


[error] 11-11: Function is missing a return type annotation.


[error] 16-16: Function is missing a return type annotation.

tests/pytest/test__errors.py (1)

1-21: Consider removing this test module.

These tests only verify that exceptions can be raised, which is basic Python functionality. They don't test any specific error conditions or error message formatting. Consider removing this module as it doesn't provide significant value.

🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 8-8: Function is missing a return type annotation.


[error] 13-13: Function is missing a return type annotation.


[error] 18-18: Function is missing a return type annotation.

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 8-8: Function is missing a return type annotation.


[error] 13-13: Function is missing a return type annotation.


[error] 18-18: Function is missing a return type annotation.

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)

[error] 8-8: Function is missing a return type annotation.


[error] 13-13: Function is missing a return type annotation.


[error] 18-18: Function is missing a return type annotation.

tests/pytest/test__cli_subcommands.py (2)

15-17: Move import statement to the top of the file.

Importing within functions makes runtime behavior less predictable. The module is already imported at the top, and Python's import caching means it won't be loaded twice.

-    from pre_commit_terraform._cli_subcommands import (
-        SUBCOMMAND_MODULES as patched_subcommand_modules,
-    )

Move the import to the top of the file and use the variable directly:

 from pre_commit_terraform import terraform_docs_replace
 from pre_commit_terraform._cli_subcommands import SUBCOMMAND_MODULES
+from pre_commit_terraform._cli_subcommands import SUBCOMMAND_MODULES as patched_subcommand_modules

5-24: LGTM! Well-structured tests for subcommand modules.

The tests effectively verify:

  • Mocking and patching of subcommand modules
  • Integration of terraform_docs_replace within the command structure
src/pre_commit_terraform/_types.py (1)

14-30: LGTM! Well-structured protocol definition.

The protocol effectively defines the interface for subcommand modules with:

  • Clear attribute definitions
  • Well-defined method signatures
  • Proper type annotations
🧰 Tools
🪛 Ruff (0.8.2)

15-15: Undefined name runtime_checkable

(F821)

🪛 GitHub Actions: Common issues check

[error] 15-15: Name 'runtime_checkable' is not defined.

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 15-15: Undefined variable 'runtime_checkable'.

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)

[error] 15-15: Undefined variable 'runtime_checkable'.

tests/pytest/test___main__.py (1)

1-45: Revise test implementation and rename file.

The test has the following issues:

  1. Filename doesn't match the pattern '.*_test.py'

  2. Test implementation uses mocking instead of the recommended runpy approach

  3. Rename the file from test___main__.py to __main__test.py

  4. Revise the implementation to use runpy:

-import importlib
 import sys
+import subprocess
+from pathlib import Path
 
-def test_main_success(mocker):
-    mock_argv = ['__main__.py', 'arg1', 'arg2']
-    mock_return_code = 0
+def test_main_success() -> None:
+    result = subprocess.run(
+        [sys.executable, '-m', 'pre_commit_terraform', '--help'],
+        capture_output=True,
+        text=True,
+    )
+    assert result.returncode == 0
+    assert 'usage:' in result.stdout
 
-    mocker.patch('sys.argv', mock_argv)
-    mock_invoke_cli_app = mocker.patch(
-        'pre_commit_terraform._cli.invoke_cli_app',
-        return_value=mock_return_code,
-    )
-    mock_exit = mocker.patch('sys.exit')
-
-    # Reload the module to trigger the main logic
-    if 'pre_commit_terraform.__main__' in sys.modules:
-        importlib.reload(sys.modules['pre_commit_terraform.__main__'])
-    else:
-        import pre_commit_terraform.__main__  # noqa: F401
-
-    mock_invoke_cli_app.assert_called_once_with(mock_argv[1:])
-    mock_exit.assert_called_once_with(mock_return_code)
-
-def test_main_failure(mocker):
-    mock_argv = ['__main__.py', 'arg1', 'arg2']
-    mock_return_code = 1
-
-    mocker.patch('sys.argv', mock_argv)
-    mock_invoke_cli_app = mocker.patch(
-        'pre_commit_terraform._cli.invoke_cli_app',
-        return_value=mock_return_code,
-    )
-    mock_exit = mocker.patch('sys.exit')
-
-    # Reload the module to trigger the main logic
-    if 'pre_commit_terraform.__main__' in sys.modules:
-        importlib.reload(sys.modules['pre_commit_terraform.__main__'])
-    else:
-        import pre_commit_terraform.__main__  # noqa: F401
-
-    mock_invoke_cli_app.assert_called_once_with(mock_argv[1:])
-    mock_exit.assert_called_once_with(mock_return_code)
+def test_main_failure() -> None:
+    result = subprocess.run(
+        [sys.executable, '-m', 'pre_commit_terraform', '--invalid-flag'],
+        capture_output=True,
+        text=True,
+    )
+    assert result.returncode == 1
+    assert 'error:' in result.stderr
🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 1-1: tests/pytest/test___main__.py does not match pattern '.*_test.py'

src/pre_commit_terraform/_logger.py (1)

8-50: Consider using Rich for better color support.

The current implementation uses ANSI escape codes directly. Consider using the Rich library which provides better color support, handles terminal compatibility, and offers additional features like syntax highlighting.

Here's how you could refactor this using Rich:

-class ColoredFormatter(logging.Formatter):
+from rich.logging import RichHandler
+from rich.console import Console
+
+class EnhancedFormatter(logging.Formatter):
     """A logging formatter that adds color to the log messages."""
 
     def __init__(self, pattern: str) -> None:
-        """
-        Initialize the formatter with the given pattern.
-
-        Args:
-            pattern (str): The log message format pattern.
-        """
         super().__init__(pattern)
-        self.disable_color = os.environ.get('PRE_COMMIT_COLOR') == 'never'
-
-    def format(self, record: logging.LogRecord) -> str:
-        """
-        Format the log record and add color to the levelname.
-
-        Args:
-            record (logging.LogRecord): The log record to format.
-
-        Returns:
-            str: The formatted log message.
-        """
-        if self.disable_color:
-            return super().format(record)
-
-        color_mapping = {
-            'DEBUG': 37,  # white
-            'INFO': 36,  # cyan
-            'WARNING': 33,  # yellow
-            'ERROR': 31,  # red
-            'CRITICAL': 41,  # white on red background
-        }
-
-        colored_record = copy(record)
-        levelname = colored_record.levelname
-
-        set_color = f'\033[{color_mapping.get(levelname, 37)}'  # default white   # noqa: WPS432
-        reset_color = '\033[0m'
-        colored_record.levelname = f'{set_color}m{levelname}{reset_color}'
-
-        return super().format(colored_record)
+        self.console = Console(
+            force_terminal=os.environ.get('PRE_COMMIT_COLOR') != 'never'
+        )

Then update the setup_logging function to use Rich:

-    formatter = ColoredFormatter(log_format)
-    log_handler = logging.StreamHandler()
+    formatter = EnhancedFormatter(log_format)
+    log_handler = RichHandler(console=formatter.console, show_time=False)
src/pre_commit_terraform/terraform_docs_replace.py (1)

14-14: 🛠️ Refactor suggestion

Update HOOK_ID definition to follow the convention.

The HOOK_ID should be defined using rpartition() and replace() to maintain consistency with other hooks.

-HOOK_ID: Final[str] = __name__.rpartition('.')[-1]
+HOOK_ID: Final[str] = __name__.rpartition('.')[-1].replace('_', '.')

Likely invalid or redundant comment.

src/pre_commit_terraform/_run_on_whole_repo.py (1)

77-78: 🛠️ Refactor suggestion

Fix line length and improve security.

The line exceeds the maximum length and could benefit from using shutil.which() for better security.

+from shutil import which
+
-    # S607 disabled as we need to maintain ability to call git command no matter where it is located.
-    git_ls_files_cmd = ['git', 'ls-files']  # noqa: S607
+    git_path = which('git')
+    if not git_path:
+        raise RuntimeError('git command not found')
+    git_ls_files_cmd = [git_path, 'ls-files']

Likely invalid or redundant comment.

🧰 Tools
🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 77-77: Line too long (101/100).

tests/pytest/test__cli_parsing.py (1)

10-12: Replace # ? comments with descriptive comments.

The # ? comments are not human-readable and should be replaced with descriptive comments.

Replace the comments with descriptive ones:

-# ?
-# ? populate_common_argument_parser
-# ?
+# Tests for populate_common_argument_parser function
+# Verifies that the function correctly populates the argument parser
+# with common arguments and their default values.
tests/pytest/test__common.py (1)

240-240: Use monkeypatch.setenv instead of mocker.patch.dict.

For setting environment variables in tests, it's recommended to use monkeypatch.setenv.

-    mocker.patch.dict(os.environ, {'PCT_TFPATH': '/env/path/to/terraform'})
+    monkeypatch.setenv('PCT_TFPATH', '/env/path/to/terraform')
.vscode/settings.json (1)

10-12: Add test directories to Python analysis paths.

Include test directories in the Python analysis paths for better code analysis coverage.

   "python.analysis.extraPaths": [
-    "./src"
+    "./src",
+    "./tests"
   ],
hatch.toml (2)

3-3: Include .pre-commit-hooks.yaml in sdist target.
The addition of '.pre-commit-hooks.yaml' in the include list guarantees that the hooks configuration file is bundled with the source distribution.


17-19: Force-include .pre-commit-hooks.yaml in wheel build.
The new [build.targets.wheel.force-include] section forces inclusion of '.pre-commit-hooks.yaml' from a custom source path, ensuring that the hooks file is present in the wheel package.

pyproject.toml (1)

41-44: Update project metadata and add dependency.
The project description has been updated and the dependency list now includes 'pyyaml' to support YAML parsing. This change aligns the project metadata with the updated functionality.

.github/workflows/pre-commit.yaml (1)

41-41: Upgrade Python version in workflow setup.
The python-version parameter has been updated from '3.9' to '3.10' to ensure compatibility with newer tooling and libraries used in subsequent steps.

.pre-commit-hooks.yaml (2)

1-35: Remove legacy Terraform hooks.
Hooks such as 'infracost_breakdown', 'terraform_fmt', 'terraform_docs', and 'terraform_docs_without_aggregate_type_defaults' have been removed. This cleanup streamlines the configuration by dropping deprecated or unused Terraform-related hooks.


36-44: Update terraform_docs_replace hook command.
The 'terraform_docs_replace' hook now uses the command
  python -Im pre_commit_terraform terraform_docs_replace
which aligns with the intended CLI naming conventions. Ensure all documentation and dependent references are updated accordingly.

.pre-commit-config.yaml (9)

43-63: Multiple MyPy configurations for distinct Python versions.
The configuration introduces separate MyPy hooks (with aliases for Python 3.13, 3.11, and 3.9) each with its own reporting parameters. This approach helps tailor type-checking to target environments.


98-103: Removal of shfmt and shellcheck repo from pre-commit-hooks.
The previous entry for the 'jumanjihouse/pre-commit-hooks' repository (which provided shfmt and shellcheck hooks) has been removed. Ensure that their functionality is now handled elsewhere (for example, via the dedicated workflow steps) or is no longer needed.


107-120: Update hadolint revision.
The hadolint hook’s repository revision has been updated to 'v2.13.1-beta'. Please verify that this beta version is stable and compatible with the Dockerfile linting requirements in your project.


122-130: Removal of mirrors-prettier repo for JSON5 linting.
The configuration for the mirrors-prettier repository (used for JSON5 files) has been removed. Confirm that JSON5 linting is either no longer required or is handled by another tool in the workflow.


144-156: Configure isort hook with custom exclusion regex.
The isort hook is set with '--force-single-line' and the 'black' profile, and it uses a multiline regex to exclude 'tests/pytest/test__cli_subcommands.py'. Please verify that the regex (utilizing the extended mode with (?x)) performs as intended.


157-160: Add trailing comma hook.
The addition of the 'add-trailing-comma' hook (v3.1.0) helps enforce a consistent code style with trailing commas.


162-169: Introduce autopep8 hook for formatting.
The autopep8 hook is configured to run in-place with a maximum line length of 100. This should help standardize code formatting automatically.


170-182: Configure pylint hook with tailored disables and exclusions.
The pylint hook now disables several warnings (such as import errors and ungrouped imports) and excludes test files. These settings appear to align with the project’s coding guidelines; ensure that these disable flags are acceptable for all contributors.


184-195: Additional MyPy configuration block – potential duplication.
An extra MyPy configuration block includes 'types-PyYAML' as an additional dependency and sets various arguments (ignoring missing imports, disallowing untyped calls, and warning on redundant casts). This may overlap with the earlier MyPy hooks for different Python versions. Please verify if both configurations are needed or consider consolidating them.

from pre_commit_terraform._structs import ReturnCode


def test_return_code_values():
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add return type annotations to test functions.

Add return type annotations to comply with type checking requirements:

-def test_return_code_values():
+def test_return_code_values() -> None:

-def test_return_code_names():
+def test_return_code_names() -> None:

-def test_return_code_invalid_value():
+def test_return_code_invalid_value() -> None:

Also applies to: 11-11, 16-16

🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 6-6: Function is missing a return type annotation.

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 6-6: Function is missing a return type annotation.

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)

[error] 6-6: Function is missing a return type annotation.

from pre_commit_terraform._errors import PreCommitTerraformRuntimeError


def test_pre_commit_terraform_base_error():
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add return type annotations to test functions.

Add return type annotations to comply with type checking requirements:

-def test_pre_commit_terraform_base_error():
+def test_pre_commit_terraform_base_error() -> None:

-def test_pre_commit_terraform_runtime_error():
+def test_pre_commit_terraform_runtime_error() -> None:

-def test_pre_commit_terraform_exit():
+def test_pre_commit_terraform_exit() -> None:

Also applies to: 13-13, 18-18

🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 8-8: Function is missing a return type annotation.

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 8-8: Function is missing a return type annotation.

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)

[error] 8-8: Function is missing a return type annotation.

@@ -0,0 +1,23 @@
from pre_commit_terraform import terraform_docs_replace
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Rename file to match test pattern.

The file name doesn't match the required pattern '.*_test.py'. Rename it to cli_subcommands_test.py.

🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 1-1: tests/pytest/test__cli_subcommands.py does not match pattern '.*_test.py'

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 1-1: NameError: name 'runtime_checkable' is not defined

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)

[error] 1-1: NameError: name 'runtime_checkable' is not defined

Comment on lines +6 to +7
from typing import Protocol
from typing import Union
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add missing import for runtime_checkable.

The runtime_checkable decorator is undefined. Add the import from typing:

-from typing import Protocol
+from typing import Protocol, runtime_checkable
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from typing import Protocol
from typing import Union
from typing import Protocol, runtime_checkable
from typing import Union

Comment on lines +9 to +16
def test_return_code_type():
assert isinstance(ReturnCode.OK, ReturnCodeType)
assert isinstance(ReturnCode.ERROR, ReturnCodeType)
assert isinstance(0, ReturnCodeType)
assert isinstance(1, ReturnCodeType)
assert not isinstance(2.5, ReturnCodeType)
assert not isinstance('string', ReturnCodeType)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add return type annotation to the test function.

Apply this diff to fix the issue:

-def test_return_code_type():
+def test_return_code_type() -> None:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_return_code_type():
assert isinstance(ReturnCode.OK, ReturnCodeType)
assert isinstance(ReturnCode.ERROR, ReturnCodeType)
assert isinstance(0, ReturnCodeType)
assert isinstance(1, ReturnCodeType)
assert not isinstance(2.5, ReturnCodeType)
assert not isinstance('string', ReturnCodeType)
def test_return_code_type() -> None:
assert isinstance(ReturnCode.OK, ReturnCodeType)
assert isinstance(ReturnCode.ERROR, ReturnCodeType)
assert isinstance(0, ReturnCodeType)
assert isinstance(1, ReturnCodeType)
assert not isinstance(2.5, ReturnCodeType)
assert not isinstance('string', ReturnCodeType)
🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 9-9: Function is missing a return type annotation.

Comment on lines +10 to +82
def test_invoke_cli_app_success(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.return_value = ReturnCode.OK

mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args

result = invoke_cli_app(['mock_arg'])

assert result == ReturnCode.OK
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)


def test_invoke_cli_app_pre_commit_terraform_exit(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = PreCommitTerraformExit('Exit error')

mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args

with pytest.raises(PreCommitTerraformExit):
invoke_cli_app(['mock_arg'])

mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)


def test_invoke_cli_app_pre_commit_terraform_runtime_error(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = PreCommitTerraformRuntimeError('Runtime error')

mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args

result = invoke_cli_app(['mock_arg'])

assert result == ReturnCode.ERROR
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)


def test_invoke_cli_app_pre_commit_terraform_base_error(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = PreCommitTerraformBaseError('Base error')

mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args

result = invoke_cli_app(['mock_arg'])

assert result == ReturnCode.ERROR
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)


def test_invoke_cli_app_keyboard_interrupt(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = KeyboardInterrupt('Interrupt')

mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args

result = invoke_cli_app(['mock_arg'])

assert result == ReturnCode.ERROR
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add type annotations to test functions.

The test functions are missing type annotations as required by the pipeline.

-def test_invoke_cli_app_success(mocker):
+def test_invoke_cli_app_success(mocker: pytest.MockFixture) -> None:

-def test_invoke_cli_app_pre_commit_terraform_exit(mocker):
+def test_invoke_cli_app_pre_commit_terraform_exit(mocker: pytest.MockFixture) -> None:

-def test_invoke_cli_app_pre_commit_terraform_runtime_error(mocker):
+def test_invoke_cli_app_pre_commit_terraform_runtime_error(mocker: pytest.MockFixture) -> None:

-def test_invoke_cli_app_pre_commit_terraform_base_error(mocker):
+def test_invoke_cli_app_pre_commit_terraform_base_error(mocker: pytest.MockFixture) -> None:

-def test_invoke_cli_app_keyboard_interrupt(mocker):
+def test_invoke_cli_app_keyboard_interrupt(mocker: pytest.MockFixture) -> None:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_invoke_cli_app_success(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.return_value = ReturnCode.OK
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
result = invoke_cli_app(['mock_arg'])
assert result == ReturnCode.OK
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
def test_invoke_cli_app_pre_commit_terraform_exit(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = PreCommitTerraformExit('Exit error')
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
with pytest.raises(PreCommitTerraformExit):
invoke_cli_app(['mock_arg'])
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
def test_invoke_cli_app_pre_commit_terraform_runtime_error(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = PreCommitTerraformRuntimeError('Runtime error')
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
result = invoke_cli_app(['mock_arg'])
assert result == ReturnCode.ERROR
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
def test_invoke_cli_app_pre_commit_terraform_base_error(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = PreCommitTerraformBaseError('Base error')
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
result = invoke_cli_app(['mock_arg'])
assert result == ReturnCode.ERROR
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
def test_invoke_cli_app_keyboard_interrupt(mocker):
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = KeyboardInterrupt('Interrupt')
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
result = invoke_cli_app(['mock_arg'])
assert result == ReturnCode.ERROR
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
def test_invoke_cli_app_success(mocker: pytest.MockFixture) -> None:
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.return_value = ReturnCode.OK
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
result = invoke_cli_app(['mock_arg'])
assert result == ReturnCode.OK
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
def test_invoke_cli_app_pre_commit_terraform_exit(mocker: pytest.MockFixture) -> None:
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = PreCommitTerraformExit('Exit error')
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
with pytest.raises(PreCommitTerraformExit):
invoke_cli_app(['mock_arg'])
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
def test_invoke_cli_app_pre_commit_terraform_runtime_error(mocker: pytest.MockFixture) -> None:
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = PreCommitTerraformRuntimeError('Runtime error')
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
result = invoke_cli_app(['mock_arg'])
assert result == ReturnCode.ERROR
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
def test_invoke_cli_app_pre_commit_terraform_base_error(mocker: pytest.MockFixture) -> None:
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = PreCommitTerraformBaseError('Base error')
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
result = invoke_cli_app(['mock_arg'])
assert result == ReturnCode.ERROR
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
def test_invoke_cli_app_keyboard_interrupt(mocker: pytest.MockFixture) -> None:
mock_parsed_args = mocker.MagicMock()
mock_parsed_args.invoke_cli_app.side_effect = KeyboardInterrupt('Interrupt')
mock_initialize_argument_parser = mocker.patch(
'pre_commit_terraform._cli.initialize_argument_parser',
)
mock_initialize_argument_parser.return_value.parse_args.return_value = mock_parsed_args
result = invoke_cli_app(['mock_arg'])
assert result == ReturnCode.ERROR
mock_parsed_args.invoke_cli_app.assert_called_once_with(mock_parsed_args)
🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 10-10: Function is missing a type annotation.


[error] 25-25: Function is missing a type annotation.


[error] 40-40: Function is missing a type annotation.


[error] 55-55: Function is missing a type annotation.


[error] 70-70: Function is missing a type annotation.

logger = logging.getLogger(__name__)


def is_function_defined(func_name: str, scope: dict) -> bool:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add type parameters to generic dict type.

The dict type needs type parameters to satisfy type checking.

-def is_function_defined(func_name: str, scope: dict) -> bool:
+def is_function_defined(func_name: str, scope: dict[str, object]) -> bool:
🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 13-13: Missing type parameters for generic type 'dict'.

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 13-13: Missing type parameters for generic type 'dict'.

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)

[error] 13-13: Missing type parameters for generic type 'dict'.

import subprocess
from importlib.resources import files as access_artifacts_of

import yaml
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Install type stubs for PyYAML.

Add types-PyYAML to development dependencies to resolve type checking issues.

# setup.py or pyproject.toml
     install_requires=[
         'pyyaml',
+        'types-PyYAML',  # dev dependency
     ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import yaml
# setup.py or pyproject.toml
install_requires=[
'pyyaml',
'types-PyYAML', # dev dependency
]
🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 8-8: Library stubs not installed for 'yaml'.

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 8-8: Library stubs not installed for 'yaml'.

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)

[error] 8-8: Library stubs not installed for 'yaml'.

# ?
# ? populate_common_argument_parser
# ?
def test_populate_common_argument_parser(mocker):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add type annotations to function parameters and return type.

The function is missing type annotations as indicated by pipeline failures.

-def test_populate_common_argument_parser(mocker):
+def test_populate_common_argument_parser(mocker: pytest_mock.MockerFixture) -> None:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_populate_common_argument_parser(mocker):
def test_populate_common_argument_parser(mocker: pytest_mock.MockerFixture) -> None:
🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 13-13: Function is missing a type annotation.

assert result == '/custom/path/to/terraform'


def test_get_tf_binary_path_from_pct_tfpath_env_var(mocker):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add type annotations to function parameters and return type.

The function is missing type annotations as indicated by pipeline failures.

-def test_get_tf_binary_path_from_pct_tfpath_env_var(mocker):
+def test_get_tf_binary_path_from_pct_tfpath_env_var(mocker: pytest_mock.MockerFixture) -> None:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_get_tf_binary_path_from_pct_tfpath_env_var(mocker):
def test_get_tf_binary_path_from_pct_tfpath_env_var(mocker: pytest_mock.MockerFixture) -> None:
🧰 Tools
🪛 GitHub Actions: Common issues check

[error] 238-238: Function is missing a return type annotation.

🪛 GitHub Actions: 🔀 PR 741 triggered by: pull_request of refs/pull/741/merge branch (workflow run ID: 12675889873; number: 33; attempt: 1)

[error] 238-238: Function is missing a type annotation.

🪛 GitHub Actions: 🌱 Commit 1bdb83e triggered by: push of refs/heads/rewrite_hooks_on_python_back_to_main branch (workflow run ID: 12675889103; number: 32; attempt: 1)

[error] 238-238: Function is missing a return type annotation.

@MaxymVlasov MaxymVlasov added on-hold Indicates that an issue or PR should not be auto-closed due to staleness. and removed stale Denotes an issue or PR has remained open with no activity and has become stale. labels Feb 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
on-hold Indicates that an issue or PR should not be auto-closed due to staleness.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants