Add types to pre-commit

This commit is contained in:
Anthony Sottile 2020-01-10 23:32:28 -08:00
parent fa536a8693
commit 327ed924a3
62 changed files with 911 additions and 411 deletions

View file

@ -37,21 +37,21 @@ def test_use_color_no_tty():
def test_use_color_tty_with_color_support():
with mock.patch.object(sys.stdout, 'isatty', return_value=True):
with mock.patch('pre_commit.color.terminal_supports_color', True):
with envcontext.envcontext([('TERM', envcontext.UNSET)]):
with envcontext.envcontext((('TERM', envcontext.UNSET),)):
assert use_color('auto') is True
def test_use_color_tty_without_color_support():
with mock.patch.object(sys.stdout, 'isatty', return_value=True):
with mock.patch('pre_commit.color.terminal_supports_color', False):
with envcontext.envcontext([('TERM', envcontext.UNSET)]):
with envcontext.envcontext((('TERM', envcontext.UNSET),)):
assert use_color('auto') is False
def test_use_color_dumb_term():
with mock.patch.object(sys.stdout, 'isatty', return_value=True):
with mock.patch('pre_commit.color.terminal_supports_color', True):
with envcontext.envcontext([('TERM', 'dumb')]):
with envcontext.envcontext((('TERM', 'dumb'),)):
assert use_color('auto') is False

View file

@ -24,7 +24,7 @@ def test_init_templatedir(tmpdir, tempdir_factory, store, cap_out):
'[WARNING] maybe `git config --global init.templateDir',
)
with envcontext([('GIT_TEMPLATE_DIR', target)]):
with envcontext((('GIT_TEMPLATE_DIR', target),)):
path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
with cwd(path):
@ -52,7 +52,7 @@ def test_init_templatedir_already_set(tmpdir, tempdir_factory, store, cap_out):
def test_init_templatedir_not_set(tmpdir, store, cap_out):
# set HOME to ignore the current `.gitconfig`
with envcontext([('HOME', str(tmpdir))]):
with envcontext((('HOME', str(tmpdir)),)):
with tmpdir.join('tmpl').ensure_dir().as_cwd():
# we have not set init.templateDir so this should produce a warning
init_templatedir(

View file

@ -274,5 +274,5 @@ def fake_log_handler():
@pytest.fixture(scope='session', autouse=True)
def set_git_templatedir(tmpdir_factory):
tdir = str(tmpdir_factory.mktemp('git_template_dir'))
with envcontext([('GIT_TEMPLATE_DIR', tdir)]):
with envcontext((('GIT_TEMPLATE_DIR', tdir),)):
yield

View file

@ -93,7 +93,7 @@ def test_exception_safety():
env = {'hello': 'world'}
with pytest.raises(MyError):
with envcontext([('foo', 'bar')], _env=env):
with envcontext((('foo', 'bar'),), _env=env):
raise MyError()
assert env == {'hello': 'world'}
@ -101,6 +101,6 @@ def test_exception_safety():
def test_integration_os_environ():
with mock.patch.dict(os.environ, {'FOO': 'bar'}, clear=True):
assert os.environ == {'FOO': 'bar'}
with envcontext([('HERP', 'derp')]):
with envcontext((('HERP', 'derp'),)):
assert os.environ == {'FOO': 'bar', 'HERP': 'derp'}
assert os.environ == {'FOO': 'bar'}

View file

@ -1,23 +1,31 @@
import functools
import inspect
from typing import Sequence
from typing import Tuple
import pytest
from pre_commit.languages.all import all_languages
from pre_commit.languages.all import languages
from pre_commit.prefix import Prefix
ArgSpec = functools.partial(
inspect.FullArgSpec, varargs=None, varkw=None, defaults=None,
kwonlyargs=[], kwonlydefaults=None, annotations={},
)
def _argspec(annotations):
args = [k for k in annotations if k != 'return']
return inspect.FullArgSpec(
args=args, annotations=annotations,
varargs=None, varkw=None, defaults=None,
kwonlyargs=[], kwonlydefaults=None,
)
@pytest.mark.parametrize('language', all_languages)
def test_install_environment_argspec(language):
expected_argspec = ArgSpec(
args=['prefix', 'version', 'additional_dependencies'],
)
expected_argspec = _argspec({
'return': None,
'prefix': Prefix,
'version': str,
'additional_dependencies': Sequence[str],
})
argspec = inspect.getfullargspec(languages[language].install_environment)
assert argspec == expected_argspec
@ -29,20 +37,26 @@ def test_ENVIRONMENT_DIR(language):
@pytest.mark.parametrize('language', all_languages)
def test_run_hook_argspec(language):
expected_argspec = ArgSpec(args=['hook', 'file_args', 'color'])
expected_argspec = _argspec({
'return': Tuple[int, bytes],
'hook': 'Hook', 'file_args': Sequence[str], 'color': bool,
})
argspec = inspect.getfullargspec(languages[language].run_hook)
assert argspec == expected_argspec
@pytest.mark.parametrize('language', all_languages)
def test_get_default_version_argspec(language):
expected_argspec = ArgSpec(args=[])
expected_argspec = _argspec({'return': str})
argspec = inspect.getfullargspec(languages[language].get_default_version)
assert argspec == expected_argspec
@pytest.mark.parametrize('language', all_languages)
def test_healthy_argspec(language):
expected_argspec = ArgSpec(args=['prefix', 'language_version'])
expected_argspec = _argspec({
'return': bool,
'prefix': Prefix, 'language_version': str,
})
argspec = inspect.getfullargspec(languages[language].healthy)
assert argspec == expected_argspec

View file

@ -7,7 +7,7 @@ from pre_commit.util import CalledProcessError
def test_docker_is_running_process_error():
with mock.patch(
'pre_commit.languages.docker.cmd_output_b',
side_effect=CalledProcessError(None, None, None, None, None),
side_effect=CalledProcessError(1, (), 0, b'', None),
):
assert docker.docker_is_running() is False

View file

@ -17,7 +17,7 @@ def test_basic_get_default_version():
def test_basic_healthy():
assert helpers.basic_healthy(None, None) is True
assert helpers.basic_healthy(Prefix('.'), 'default') is True
def test_failed_setup_command_does_not_unicode_error():
@ -77,4 +77,6 @@ def test_target_concurrency_cpu_count_not_implemented():
def test_shuffled_is_deterministic():
assert helpers._shuffled(range(10)) == [3, 7, 8, 2, 4, 6, 5, 1, 0, 9]
seq = [str(i) for i in range(10)]
expected = ['3', '7', '8', '2', '4', '6', '5', '1', '0', '9']
assert helpers._shuffled(seq) == expected

View file

@ -1,25 +1,21 @@
import logging
from pre_commit import color
from pre_commit.logging_handler import LoggingHandler
class FakeLogRecord:
def __init__(self, message, levelname, levelno):
self.message = message
self.levelname = levelname
self.levelno = levelno
def getMessage(self):
return self.message
def _log_record(message, level):
return logging.LogRecord('name', level, '', 1, message, {}, None)
def test_logging_handler_color(cap_out):
handler = LoggingHandler(True)
handler.emit(FakeLogRecord('hi', 'WARNING', 30))
handler.emit(_log_record('hi', logging.WARNING))
ret = cap_out.get()
assert ret == color.YELLOW + '[WARNING]' + color.NORMAL + ' hi\n'
def test_logging_handler_no_color(cap_out):
handler = LoggingHandler(False)
handler.emit(FakeLogRecord('hi', 'WARNING', 30))
handler.emit(_log_record('hi', logging.WARNING))
assert cap_out.get() == '[WARNING] hi\n'

View file

@ -1,8 +1,5 @@
import argparse
import os.path
from typing import NamedTuple
from typing import Optional
from typing import Sequence
from unittest import mock
import pytest
@ -27,25 +24,24 @@ def test_append_replace_default(argv, expected):
assert parser.parse_args(argv).f == expected
class Args(NamedTuple):
command: str = 'help'
config: str = C.CONFIG_FILE
files: Sequence[str] = []
repo: Optional[str] = None
def _args(**kwargs):
kwargs.setdefault('command', 'help')
kwargs.setdefault('config', C.CONFIG_FILE)
return argparse.Namespace(**kwargs)
def test_adjust_args_and_chdir_not_in_git_dir(in_tmpdir):
with pytest.raises(FatalError):
main._adjust_args_and_chdir(Args())
main._adjust_args_and_chdir(_args())
def test_adjust_args_and_chdir_in_dot_git_dir(in_git_dir):
with in_git_dir.join('.git').as_cwd(), pytest.raises(FatalError):
main._adjust_args_and_chdir(Args())
main._adjust_args_and_chdir(_args())
def test_adjust_args_and_chdir_noop(in_git_dir):
args = Args(command='run', files=['f1', 'f2'])
args = _args(command='run', files=['f1', 'f2'])
main._adjust_args_and_chdir(args)
assert os.getcwd() == in_git_dir
assert args.config == C.CONFIG_FILE
@ -56,7 +52,7 @@ def test_adjust_args_and_chdir_relative_things(in_git_dir):
in_git_dir.join('foo/cfg.yaml').ensure()
in_git_dir.join('foo').chdir()
args = Args(command='run', files=['f1', 'f2'], config='cfg.yaml')
args = _args(command='run', files=['f1', 'f2'], config='cfg.yaml')
main._adjust_args_and_chdir(args)
assert os.getcwd() == in_git_dir
assert args.config == os.path.join('foo', 'cfg.yaml')
@ -66,7 +62,7 @@ def test_adjust_args_and_chdir_relative_things(in_git_dir):
def test_adjust_args_and_chdir_non_relative_config(in_git_dir):
in_git_dir.join('foo').ensure_dir().chdir()
args = Args()
args = _args()
main._adjust_args_and_chdir(args)
assert os.getcwd() == in_git_dir
assert args.config == C.CONFIG_FILE
@ -75,7 +71,7 @@ def test_adjust_args_and_chdir_non_relative_config(in_git_dir):
def test_adjust_args_try_repo_repo_relative(in_git_dir):
in_git_dir.join('foo').ensure_dir().chdir()
args = Args(command='try-repo', repo='../foo', files=[])
args = _args(command='try-repo', repo='../foo', files=[])
assert args.repo is not None
assert os.path.exists(args.repo)
main._adjust_args_and_chdir(args)

View file

@ -22,7 +22,7 @@ from pre_commit import output
),
)
def test_get_hook_message_raises(kwargs):
with pytest.raises(ValueError):
with pytest.raises(AssertionError):
output.get_hook_message('start', **kwargs)

View file

@ -311,7 +311,7 @@ def test_golang_hook(tempdir_factory, store):
def test_golang_hook_still_works_when_gobin_is_set(tempdir_factory, store):
gobin_dir = tempdir_factory.get()
with envcontext([('GOBIN', gobin_dir)]):
with envcontext((('GOBIN', gobin_dir),)):
test_golang_hook(tempdir_factory, store)
assert os.listdir(gobin_dir) == []

View file

@ -120,7 +120,7 @@ def test_clone_shallow_failure_fallback_to_complete(
# Force shallow clone failure
def fake_shallow_clone(self, *args, **kwargs):
raise CalledProcessError(None, None, None, None, None)
raise CalledProcessError(1, (), 0, b'', None)
store._shallow_clone = fake_shallow_clone
ret = store.clone(path, rev)

View file

@ -15,9 +15,9 @@ from pre_commit.util import tmpdir
def test_CalledProcessError_str():
error = CalledProcessError(1, ['exe'], 0, b'output', b'errors')
error = CalledProcessError(1, ('exe',), 0, b'output', b'errors')
assert str(error) == (
"command: ['exe']\n"
"command: ('exe',)\n"
'return code: 1\n'
'expected return code: 0\n'
'stdout:\n'
@ -28,9 +28,9 @@ def test_CalledProcessError_str():
def test_CalledProcessError_str_nooutput():
error = CalledProcessError(1, ['exe'], 0, b'', b'')
error = CalledProcessError(1, ('exe',), 0, b'', b'')
assert str(error) == (
"command: ['exe']\n"
"command: ('exe',)\n"
'return code: 1\n'
'expected return code: 0\n'
'stdout: (none)\n'

View file

@ -2,6 +2,7 @@ import concurrent.futures
import os
import sys
import time
from typing import Tuple
from unittest import mock
import pytest
@ -166,9 +167,8 @@ def test_xargs_concurrency():
def test_thread_mapper_concurrency_uses_threadpoolexecutor_map():
with xargs._thread_mapper(10) as thread_map:
assert isinstance(
thread_map.__self__, concurrent.futures.ThreadPoolExecutor,
) is True
_self = thread_map.__self__ # type: ignore
assert isinstance(_self, concurrent.futures.ThreadPoolExecutor)
def test_thread_mapper_concurrency_uses_regular_map():
@ -178,7 +178,7 @@ def test_thread_mapper_concurrency_uses_regular_map():
def test_xargs_propagate_kwargs_to_cmd():
env = {'PRE_COMMIT_TEST_VAR': 'Pre commit is awesome'}
cmd = ('bash', '-c', 'echo $PRE_COMMIT_TEST_VAR', '--')
cmd: Tuple[str, ...] = ('bash', '-c', 'echo $PRE_COMMIT_TEST_VAR', '--')
cmd = parse_shebang.normalize_cmd(cmd)
ret, stdout = xargs.xargs(cmd, ('1',), env=env)