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



@runtime_checkable
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason to do this in this PR?

Comment on lines +17 to +20
if 'pre_commit_terraform.__main__' in sys.modules:
importlib.reload(sys.modules['pre_commit_terraform.__main__'])
else:
import pre_commit_terraform.__main__ # noqa: F401
Copy link
Contributor

Choose a reason for hiding this comment

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

Nooooooo! Don't do this! Use runpy like you're supposed to. This module is to be invoked as an entry-point and not in the middle of runtime. So in general you should've instead just called it through sys.executable and checked the return code + the output. No need to patch stuff in this case.

mock_return_code = 0

mocker.patch('sys.argv', mock_argv)
mock_invoke_cli_app = mocker.patch(
Copy link
Contributor

Choose a reason for hiding this comment

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

Also, you could do a --help instead of patching most of the logic out. It would give you your successful return code.

Comment on lines +13 to +69
def test_populate_common_argument_parser(mocker):
parser = ArgumentParser(add_help=False)
populate_common_argument_parser(parser)
args = parser.parse_args(
['-a', 'arg1', '-h', 'hook1', '-i', 'init1', '-e', 'env1', 'file1', 'file2'],
)

assert args.args == ['arg1']
assert args.hook_config == ['hook1']
assert args.tf_init_args == ['init1']
assert args.env_vars_strs == ['env1']
assert args.files == ['file1', 'file2']


def test_populate_common_argument_parser_defaults(mocker):
parser = ArgumentParser(add_help=False)
populate_common_argument_parser(parser)
args = parser.parse_args([])

assert args.args == []
assert args.hook_config == []
assert args.tf_init_args == []
assert args.env_vars_strs == []
assert args.files == []


def test_populate_common_argument_parser_multiple_values(mocker):
parser = ArgumentParser(add_help=False)
populate_common_argument_parser(parser)
args = parser.parse_args(
[
'-a',
'arg1',
'-a',
'arg2',
'-h',
'hook1',
'-h',
'hook2',
'-i',
'init1',
'-i',
'init2',
'-e',
'env1',
'-e',
'env2',
'file1',
'file2',
],
)

assert args.args == ['arg1', 'arg2']
assert args.hook_config == ['hook1', 'hook2']
assert args.tf_init_args == ['init1', 'init2']
assert args.env_vars_strs == ['env1', 'env2']
assert args.files == ['file1', 'file2']
Copy link
Contributor

Choose a reason for hiding this comment

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

These are actually a single test, and it should be a single test function. To run it multiple times, use @pytest.mark.parametrize. Don't forget to specify test IDs for better UX/DX in test report and invocation.

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

Choose a reason for hiding this comment

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

Also, why didn't you write a docstring, so I would know what you're testing/expecting here?

Copy link
Contributor

Choose a reason for hiding this comment

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

In general, I see a huge overuse of mocking here. It's best to avoid it entirely where possible. Or only have a few exceptions. Designing runtime code well (like through dependency injection) allows for testing without mocking random things out.

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants