mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-02-17 08:14:42 +04:00
Add types to pre-commit
This commit is contained in:
parent
fa536a8693
commit
327ed924a3
62 changed files with 911 additions and 411 deletions
|
|
@ -6,6 +6,16 @@ import stat
|
|||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from types import TracebackType
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import Generator
|
||||
from typing import IO
|
||||
from typing import Optional
|
||||
from typing import Tuple
|
||||
from typing import Type
|
||||
from typing import Union
|
||||
|
||||
from pre_commit import five
|
||||
from pre_commit import parse_shebang
|
||||
|
|
@ -17,8 +27,10 @@ else: # pragma: no cover (<PY37)
|
|||
from importlib_resources import open_binary
|
||||
from importlib_resources import read_text
|
||||
|
||||
EnvironT = Union[Dict[str, str], 'os._Environ']
|
||||
|
||||
def mkdirp(path):
|
||||
|
||||
def mkdirp(path: str) -> None:
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError:
|
||||
|
|
@ -27,7 +39,7 @@ def mkdirp(path):
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def clean_path_on_failure(path):
|
||||
def clean_path_on_failure(path: str) -> Generator[None, None, None]:
|
||||
"""Cleans up the directory on an exceptional failure."""
|
||||
try:
|
||||
yield
|
||||
|
|
@ -38,12 +50,12 @@ def clean_path_on_failure(path):
|
|||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def noop_context():
|
||||
def noop_context() -> Generator[None, None, None]:
|
||||
yield
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def tmpdir():
|
||||
def tmpdir() -> Generator[str, None, None]:
|
||||
"""Contextmanager to create a temporary directory. It will be cleaned up
|
||||
afterwards.
|
||||
"""
|
||||
|
|
@ -54,15 +66,15 @@ def tmpdir():
|
|||
rmtree(tempdir)
|
||||
|
||||
|
||||
def resource_bytesio(filename):
|
||||
def resource_bytesio(filename: str) -> IO[bytes]:
|
||||
return open_binary('pre_commit.resources', filename)
|
||||
|
||||
|
||||
def resource_text(filename):
|
||||
def resource_text(filename: str) -> str:
|
||||
return read_text('pre_commit.resources', filename)
|
||||
|
||||
|
||||
def make_executable(filename):
|
||||
def make_executable(filename: str) -> None:
|
||||
original_mode = os.stat(filename).st_mode
|
||||
os.chmod(
|
||||
filename, original_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH,
|
||||
|
|
@ -70,18 +82,23 @@ def make_executable(filename):
|
|||
|
||||
|
||||
class CalledProcessError(RuntimeError):
|
||||
def __init__(self, returncode, cmd, expected_returncode, stdout, stderr):
|
||||
super().__init__(
|
||||
returncode, cmd, expected_returncode, stdout, stderr,
|
||||
)
|
||||
def __init__(
|
||||
self,
|
||||
returncode: int,
|
||||
cmd: Tuple[str, ...],
|
||||
expected_returncode: int,
|
||||
stdout: bytes,
|
||||
stderr: Optional[bytes],
|
||||
) -> None:
|
||||
super().__init__(returncode, cmd, expected_returncode, stdout, stderr)
|
||||
self.returncode = returncode
|
||||
self.cmd = cmd
|
||||
self.expected_returncode = expected_returncode
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
|
||||
def __bytes__(self):
|
||||
def _indent_or_none(part):
|
||||
def __bytes__(self) -> bytes:
|
||||
def _indent_or_none(part: Optional[bytes]) -> bytes:
|
||||
if part:
|
||||
return b'\n ' + part.replace(b'\n', b'\n ')
|
||||
else:
|
||||
|
|
@ -97,11 +114,14 @@ class CalledProcessError(RuntimeError):
|
|||
b'stderr:', _indent_or_none(self.stderr),
|
||||
))
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return self.__bytes__().decode('UTF-8')
|
||||
|
||||
|
||||
def _cmd_kwargs(*cmd, **kwargs):
|
||||
def _cmd_kwargs(
|
||||
*cmd: str,
|
||||
**kwargs: Any,
|
||||
) -> Tuple[Tuple[str, ...], Dict[str, Any]]:
|
||||
# py2/py3 on windows are more strict about the types here
|
||||
cmd = tuple(five.n(arg) for arg in cmd)
|
||||
kwargs['env'] = {
|
||||
|
|
@ -113,7 +133,10 @@ def _cmd_kwargs(*cmd, **kwargs):
|
|||
return cmd, kwargs
|
||||
|
||||
|
||||
def cmd_output_b(*cmd, **kwargs):
|
||||
def cmd_output_b(
|
||||
*cmd: str,
|
||||
**kwargs: Any,
|
||||
) -> Tuple[int, bytes, Optional[bytes]]:
|
||||
retcode = kwargs.pop('retcode', 0)
|
||||
cmd, kwargs = _cmd_kwargs(*cmd, **kwargs)
|
||||
|
||||
|
|
@ -132,7 +155,7 @@ def cmd_output_b(*cmd, **kwargs):
|
|||
return returncode, stdout_b, stderr_b
|
||||
|
||||
|
||||
def cmd_output(*cmd, **kwargs):
|
||||
def cmd_output(*cmd: str, **kwargs: Any) -> Tuple[int, str, Optional[str]]:
|
||||
returncode, stdout_b, stderr_b = cmd_output_b(*cmd, **kwargs)
|
||||
stdout = stdout_b.decode('UTF-8') if stdout_b is not None else None
|
||||
stderr = stderr_b.decode('UTF-8') if stderr_b is not None else None
|
||||
|
|
@ -144,10 +167,11 @@ if os.name != 'nt': # pragma: windows no cover
|
|||
import termios
|
||||
|
||||
class Pty:
|
||||
def __init__(self):
|
||||
self.r = self.w = None
|
||||
def __init__(self) -> None:
|
||||
self.r: Optional[int] = None
|
||||
self.w: Optional[int] = None
|
||||
|
||||
def __enter__(self):
|
||||
def __enter__(self) -> 'Pty':
|
||||
self.r, self.w = openpty()
|
||||
|
||||
# tty flags normally change \n to \r\n
|
||||
|
|
@ -158,21 +182,29 @@ if os.name != 'nt': # pragma: windows no cover
|
|||
|
||||
return self
|
||||
|
||||
def close_w(self):
|
||||
def close_w(self) -> None:
|
||||
if self.w is not None:
|
||||
os.close(self.w)
|
||||
self.w = None
|
||||
|
||||
def close_r(self):
|
||||
def close_r(self) -> None:
|
||||
assert self.r is not None
|
||||
os.close(self.r)
|
||||
self.r = None
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
def __exit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_value: Optional[BaseException],
|
||||
traceback: Optional[TracebackType],
|
||||
) -> None:
|
||||
self.close_w()
|
||||
self.close_r()
|
||||
|
||||
def cmd_output_p(*cmd, **kwargs):
|
||||
def cmd_output_p(
|
||||
*cmd: str,
|
||||
**kwargs: Any,
|
||||
) -> Tuple[int, bytes, Optional[bytes]]:
|
||||
assert kwargs.pop('retcode') is None
|
||||
assert kwargs['stderr'] == subprocess.STDOUT, kwargs['stderr']
|
||||
cmd, kwargs = _cmd_kwargs(*cmd, **kwargs)
|
||||
|
|
@ -183,6 +215,7 @@ if os.name != 'nt': # pragma: windows no cover
|
|||
return e.to_output()
|
||||
|
||||
with open(os.devnull) as devnull, Pty() as pty:
|
||||
assert pty.r is not None
|
||||
kwargs.update({'stdin': devnull, 'stdout': pty.w, 'stderr': pty.w})
|
||||
proc = subprocess.Popen(cmd, **kwargs)
|
||||
pty.close_w()
|
||||
|
|
@ -206,9 +239,13 @@ else: # pragma: no cover
|
|||
cmd_output_p = cmd_output_b
|
||||
|
||||
|
||||
def rmtree(path):
|
||||
def rmtree(path: str) -> None:
|
||||
"""On windows, rmtree fails for readonly dirs."""
|
||||
def handle_remove_readonly(func, path, exc):
|
||||
def handle_remove_readonly(
|
||||
func: Callable[..., Any],
|
||||
path: str,
|
||||
exc: Tuple[Type[OSError], OSError, TracebackType],
|
||||
) -> None:
|
||||
excvalue = exc[1]
|
||||
if (
|
||||
func in (os.rmdir, os.remove, os.unlink) and
|
||||
|
|
@ -222,6 +259,6 @@ def rmtree(path):
|
|||
shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly)
|
||||
|
||||
|
||||
def parse_version(s):
|
||||
def parse_version(s: str) -> Tuple[int, ...]:
|
||||
"""poor man's version comparison"""
|
||||
return tuple(int(p) for p in s.split('.'))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue