Skip to content

Add types to refs #1295

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

Merged
merged 22 commits into from
Jul 19, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .flake8
Original file line number Diff line number Diff line change
@@ -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
@@ -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,
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
44 changes: 20 additions & 24 deletions git/cmd.py
Original file line number Diff line number Diff line change
@@ -15,7 +15,6 @@
PIPE
)
import subprocess
import sys
import threading
from textwrap import dedent

@@ -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()
@@ -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
@@ -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]],
*,
@@ -641,7 +640,7 @@ def execute(self,
) -> Union[str, Tuple[int, str, str]]:
...

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

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

@overload
@ overload
def execute(self,
command: Union[str, Sequence[Any]],
*,
@@ -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
@@ -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:
@@ -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::

@@ -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:
2 changes: 1 addition & 1 deletion git/compat.py
Original file line number Diff line number Diff line change
@@ -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()
20 changes: 11 additions & 9 deletions git/config.py
Original file line number Diff line number Diff line change
@@ -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]

@@ -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.

@@ -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:
@@ -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)
2 changes: 1 addition & 1 deletion git/db.py
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@

if TYPE_CHECKING:
from git.cmd import Git


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

8 changes: 4 additions & 4 deletions git/diff.py
Original file line number Diff line number Diff line change
@@ -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:
@@ -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')):
@@ -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
2 changes: 0 additions & 2 deletions git/index/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
"""Initialize the index package"""
# flake8: noqa
from __future__ import absolute_import

from .base import *
from .typ import *
Loading