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

Add types to refs #1295

Merged
merged 22 commits into from Jul 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions .flake8
Expand Up @@ -8,7 +8,7 @@ statistics = True
# W293 = Blank line contains whitespace
# W504 = Line break after operator
# E704 = multiple statements in one line - used for @override
# TC002 =
# TC002 = move third party import to TYPE_CHECKING
# ANN = flake8-annotations
# TC, TC2 = flake8-type-checking
# D = flake8-docstrings
Expand All @@ -19,7 +19,8 @@ enable-extensions = TC, TC2 # only needed for extensions not enabled by default
ignore = E265,E266,E731,E704,
W293, W504,
ANN0 ANN1 ANN2,
TC0, TC1, TC2
TC002,
# TC0, TC1, TC2
# B,
A,
D,
Expand Down
20 changes: 11 additions & 9 deletions README.md
Expand Up @@ -106,19 +106,21 @@ On *Windows*, make sure you have `git-daemon` in your PATH. For MINGW-git, the
exists in `Git\mingw64\libexec\git-core\`; CYGWIN has no daemon, but should get along fine
with MINGW's.

Ensure testing libraries are installed. In the root directory, run: `pip install test-requirements.txt`
Then,
Ensure testing libraries are installed.
In the root directory, run: `pip install -r test-requirements.txt`

To lint, run `flake8`
To typecheck, run `mypy -p git`
To test, `pytest`
To lint, run: `flake8`

Configuration for flake8 is in root/.flake8 file.
Configuration for mypy, pytest, coverage is in root/pyproject.toml.
To typecheck, run: `mypy -p git`

The same linting and testing will also be performed against different supported python versions
upon submitting a pull request (or on each push if you have a fork with a "main" branch).
To test, run: `pytest`

Configuration for flake8 is in the ./.flake8 file.

Configurations for mypy, pytest and coverage.py are in ./pyproject.toml.

The same linting and testing will also be performed against different supported python versions
upon submitting a pull request (or on each push if you have a fork with a "main" branch and actions enabled).


### Contributions
Expand Down
44 changes: 20 additions & 24 deletions git/cmd.py
Expand Up @@ -15,7 +15,6 @@
PIPE
)
import subprocess
import sys
import threading
from textwrap import dedent

Expand Down Expand Up @@ -539,7 +538,7 @@ def __iter__(self) -> 'Git.CatFileContentStream':
return self

def __next__(self) -> bytes:
return self.next()
return next(self)

def next(self) -> bytes:
line = self.readline()
Expand All @@ -566,11 +565,11 @@ def __init__(self, working_dir: Union[None, PathLike] = None):
.git directory in case of bare repositories."""
super(Git, self).__init__()
self._working_dir = expand_path(working_dir)
self._git_options = () # type: Union[List[str], Tuple[str, ...]]
self._persistent_git_options = [] # type: List[str]
self._git_options: Union[List[str], Tuple[str, ...]] = ()
self._persistent_git_options: List[str] = []

# Extra environment variables to pass to git commands
self._environment = {} # type: Dict[str, str]
self._environment: Dict[str, str] = {}

# cached command slots
self.cat_file_header = None
Expand Down Expand Up @@ -604,35 +603,35 @@ def _set_cache_(self, attr: str) -> None:
process_version = self._call_process('version') # should be as default *args and **kwargs used
version_numbers = process_version.split(' ')[2]

self._version_info = tuple(
int(n) for n in version_numbers.split('.')[:4] if n.isdigit()
) # type: Tuple[int, int, int, int] # type: ignore
self._version_info = cast(Tuple[int, int, int, int],
tuple(int(n) for n in version_numbers.split('.')[:4] if n.isdigit())
)
else:
super(Git, self)._set_cache_(attr)
# END handle version info

@property
@ property
def working_dir(self) -> Union[None, PathLike]:
""":return: Git directory we are working on"""
return self._working_dir

@property
@ property
def version_info(self) -> Tuple[int, int, int, int]:
"""
:return: tuple(int, int, int, int) tuple with integers representing the major, minor
and additional version numbers as parsed from git version.
This value is generated on demand and is cached"""
return self._version_info

@overload
@ overload
def execute(self,
command: Union[str, Sequence[Any]],
*,
as_process: Literal[True]
) -> 'AutoInterrupt':
...

@overload
@ overload
def execute(self,
command: Union[str, Sequence[Any]],
*,
Expand All @@ -641,7 +640,7 @@ def execute(self,
) -> Union[str, Tuple[int, str, str]]:
...

@overload
@ overload
def execute(self,
command: Union[str, Sequence[Any]],
*,
Expand All @@ -650,7 +649,7 @@ def execute(self,
) -> Union[bytes, Tuple[int, bytes, str]]:
...

@overload
@ overload
def execute(self,
command: Union[str, Sequence[Any]],
*,
Expand All @@ -660,7 +659,7 @@ def execute(self,
) -> str:
...

@overload
@ overload
def execute(self,
command: Union[str, Sequence[Any]],
*,
Expand Down Expand Up @@ -799,10 +798,7 @@ def execute(self,
if kill_after_timeout:
raise GitCommandError(redacted_command, '"kill_after_timeout" feature is not supported on Windows.')
else:
if sys.version_info[0] > 2:
cmd_not_found_exception = FileNotFoundError # NOQA # exists, flake8 unknown @UndefinedVariable
else:
cmd_not_found_exception = OSError
cmd_not_found_exception = FileNotFoundError # NOQA # exists, flake8 unknown @UndefinedVariable
# end handle

stdout_sink = (PIPE
Expand Down Expand Up @@ -872,8 +868,8 @@ def _kill_process(pid: int) -> None:

# Wait for the process to return
status = 0
stdout_value = b'' # type: Union[str, bytes]
stderr_value = b'' # type: Union[str, bytes]
stdout_value: Union[str, bytes] = b''
stderr_value: Union[str, bytes] = b''
newline = "\n" if universal_newlines else b"\n"
try:
if output_stream is None:
Expand Down Expand Up @@ -1070,8 +1066,8 @@ def _call_process(self, method: str, *args: Any, **kwargs: Any
It contains key-values for the following:
- the :meth:`execute()` kwds, as listed in :var:`execute_kwargs`;
- "command options" to be converted by :meth:`transform_kwargs()`;
- the `'insert_kwargs_after'` key which its value must match one of ``*args``,
and any cmd-options will be appended after the matched arg.
- the `'insert_kwargs_after'` key which its value must match one of ``*args``
and any cmd-options will be appended after the matched arg.

Examples::

Expand Down Expand Up @@ -1149,7 +1145,7 @@ def _prepare_ref(self, ref: AnyStr) -> bytes:
# required for command to separate refs on stdin, as bytes
if isinstance(ref, bytes):
# Assume 40 bytes hexsha - bin-to-ascii for some reason returns bytes, not text
refstr = ref.decode('ascii') # type: str
refstr: str = ref.decode('ascii')
elif not isinstance(ref, str):
refstr = str(ref) # could be ref-object
else:
Expand Down
2 changes: 1 addition & 1 deletion git/compat.py
Expand Up @@ -34,7 +34,7 @@
# ---------------------------------------------------------------------------


is_win = (os.name == 'nt') # type: bool
is_win: bool = (os.name == 'nt')
is_posix = (os.name == 'posix')
is_darwin = (os.name == 'darwin')
defenc = sys.getfilesystemencoding()
Expand Down
20 changes: 11 additions & 9 deletions git/config.py
Expand Up @@ -208,7 +208,7 @@ def get(self, key: str, default: Union[Any, None] = None) -> Union[Any, None]:
def getall(self, key: str) -> Any:
return super(_OMD, self).__getitem__(key)

def items(self) -> List[Tuple[str, Any]]: # type: ignore ## mypy doesn't like overwriting supertype signitures
def items(self) -> List[Tuple[str, Any]]: # type: ignore[override]
"""List of (key, last value for key)."""
return [(k, self[k]) for k in self]

Expand Down Expand Up @@ -238,7 +238,7 @@ def get_config_path(config_level: Lit_config_levels) -> str:
assert_never(config_level, ValueError(f"Invalid configuration level: {config_level!r}"))


class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, object)): # type: ignore ## mypy does not understand dynamic class creation # noqa: E501
class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser)): # type: ignore ## mypy does not understand dynamic class creation # noqa: E501

"""Implements specifics required to read git style configuration files.

Expand Down Expand Up @@ -322,7 +322,7 @@ def __init__(self, file_or_files: Union[None, PathLike, 'BytesIO', Sequence[Unio
self._is_initialized = False
self._merge_includes = merge_includes
self._repo = repo
self._lock = None # type: Union['LockFile', None]
self._lock: Union['LockFile', None] = None
self._acquire_lock()

def _acquire_lock(self) -> None:
Expand Down Expand Up @@ -545,13 +545,15 @@ def read(self) -> None:
return None
self._is_initialized = True

files_to_read = [""] # type: List[Union[PathLike, IO]] ## just for types until 3.5 dropped
if isinstance(self._file_or_files, (str)): # replace with PathLike once 3.5 dropped
files_to_read = [self._file_or_files] # for str, as str is a type of Sequence
files_to_read: List[Union[PathLike, IO]] = [""]
if isinstance(self._file_or_files, (str, os.PathLike)):
# for str or Path, as str is a type of Sequence
files_to_read = [self._file_or_files]
elif not isinstance(self._file_or_files, (tuple, list, Sequence)):
files_to_read = [self._file_or_files] # for IO or Path
else:
files_to_read = list(self._file_or_files) # for lists or tuples
# could merge with above isinstance once runtime type known
files_to_read = [self._file_or_files]
else: # for lists or tuples
files_to_read = list(self._file_or_files)
# end assure we have a copy of the paths to handle

seen = set(files_to_read)
Expand Down
2 changes: 1 addition & 1 deletion git/db.py
Expand Up @@ -17,7 +17,7 @@

if TYPE_CHECKING:
from git.cmd import Git


# --------------------------------------------------------

Expand Down
8 changes: 4 additions & 4 deletions git/diff.py
Expand Up @@ -143,7 +143,7 @@ def diff(self, other: Union[Type['Index'], 'Tree', 'Commit', None, str, object]
paths = [paths]

if hasattr(self, 'Has_Repo'):
self.repo: Repo = self.repo
self.repo: 'Repo' = self.repo

diff_cmd = self.repo.git.diff
if other is self.Index:
Expand Down Expand Up @@ -351,13 +351,13 @@ def __hash__(self) -> int:
return hash(tuple(getattr(self, n) for n in self.__slots__))

def __str__(self) -> str:
h = "%s" # type: str
h: str = "%s"
if self.a_blob:
h %= self.a_blob.path
elif self.b_blob:
h %= self.b_blob.path

msg = '' # type: str
msg: str = ''
line = None # temp line
line_length = 0 # line length
for b, n in zip((self.a_blob, self.b_blob), ('lhs', 'rhs')):
Expand Down Expand Up @@ -449,7 +449,7 @@ def _index_from_patch_format(cls, repo: 'Repo', proc: TBD) -> DiffIndex:
:return: git.DiffIndex """

## FIXME: Here SLURPING raw, need to re-phrase header-regexes linewise.
text_list = [] # type: List[bytes]
text_list: List[bytes] = []
handle_process_output(proc, text_list.append, None, finalize_process, decode_streams=False)

# for now, we have to bake the stream
Expand Down
2 changes: 0 additions & 2 deletions git/index/__init__.py
@@ -1,6 +1,4 @@
"""Initialize the index package"""
# flake8: noqa
from __future__ import absolute_import

from .base import *
from .typ import *