Skip to content

Revert use of Typeguard and therefore typing-extensions==3.10.0.0 #1298

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 10 commits into from
Jul 25, 2021
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ignore = E265,E266,E731,E704,
W293, W504,
ANN0 ANN1 ANN2,
TC002,
# TC0, TC1, TC2
TC0, TC1, TC2
# B,
A,
D,
Expand Down
69 changes: 36 additions & 33 deletions git/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""Module containing module parser implementation able to properly read and write
configuration files"""

import sys
import abc
from functools import wraps
import inspect
Expand All @@ -14,12 +15,10 @@
import os
import re
import fnmatch
from collections import OrderedDict

from git.compat import (
defenc,
force_text,
with_metaclass,
is_win,
)

Expand All @@ -31,15 +30,24 @@

# typing-------------------------------------------------------

from typing import (Any, Callable, IO, List, Dict, Sequence,
TYPE_CHECKING, Tuple, Union, cast, overload)
from typing import (Any, Callable, Generic, IO, List, Dict, Sequence,
TYPE_CHECKING, Tuple, TypeVar, Union, cast, overload)

from git.types import Lit_config_levels, ConfigLevels_Tup, PathLike, TBD, assert_never, is_config_level
from git.types import Lit_config_levels, ConfigLevels_Tup, PathLike, TBD, assert_never, _T

if TYPE_CHECKING:
from git.repo.base import Repo
from io import BytesIO

T_ConfigParser = TypeVar('T_ConfigParser', bound='GitConfigParser')

if sys.version_info[:2] < (3, 7):
from collections import OrderedDict
OrderedDict_OMD = OrderedDict
else:
from typing import OrderedDict
OrderedDict_OMD = OrderedDict[str, List[_T]]

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

__all__ = ('GitConfigParser', 'SectionConstraint')
Expand All @@ -61,7 +69,6 @@


class MetaParserBuilder(abc.ABCMeta):

"""Utlity class wrapping base-class methods into decorators that assure read-only properties"""
def __new__(cls, name: str, bases: TBD, clsdict: Dict[str, Any]) -> TBD:
"""
Expand Down Expand Up @@ -115,7 +122,7 @@ def flush_changes(self, *args: Any, **kwargs: Any) -> Any:
return flush_changes


class SectionConstraint(object):
class SectionConstraint(Generic[T_ConfigParser]):

"""Constrains a ConfigParser to only option commands which are constrained to
always use the section we have been initialized with.
Expand All @@ -128,7 +135,7 @@ class SectionConstraint(object):
_valid_attrs_ = ("get_value", "set_value", "get", "set", "getint", "getfloat", "getboolean", "has_option",
"remove_section", "remove_option", "options")

def __init__(self, config: 'GitConfigParser', section: str) -> None:
def __init__(self, config: T_ConfigParser, section: str) -> None:
self._config = config
self._section_name = section

Expand All @@ -149,26 +156,26 @@ def _call_config(self, method: str, *args: Any, **kwargs: Any) -> Any:
return getattr(self._config, method)(self._section_name, *args, **kwargs)

@property
def config(self) -> 'GitConfigParser':
def config(self) -> T_ConfigParser:
"""return: Configparser instance we constrain"""
return self._config

def release(self) -> None:
"""Equivalent to GitConfigParser.release(), which is called on our underlying parser instance"""
return self._config.release()

def __enter__(self) -> 'SectionConstraint':
def __enter__(self) -> 'SectionConstraint[T_ConfigParser]':
self._config.__enter__()
return self

def __exit__(self, exception_type: str, exception_value: str, traceback: str) -> None:
self._config.__exit__(exception_type, exception_value, traceback)


class _OMD(OrderedDict):
class _OMD(OrderedDict_OMD):
"""Ordered multi-dict."""

def __setitem__(self, key: str, value: Any) -> None:
def __setitem__(self, key: str, value: _T) -> None: # type: ignore[override]
super(_OMD, self).__setitem__(key, [value])

def add(self, key: str, value: Any) -> None:
Expand All @@ -177,7 +184,7 @@ def add(self, key: str, value: Any) -> None:
return None
super(_OMD, self).__getitem__(key).append(value)

def setall(self, key: str, values: Any) -> None:
def setall(self, key: str, values: List[_T]) -> None:
super(_OMD, self).__setitem__(key, values)

def __getitem__(self, key: str) -> Any:
Expand All @@ -194,25 +201,17 @@ def setlast(self, key: str, value: Any) -> None:
prior = super(_OMD, self).__getitem__(key)
prior[-1] = value

@overload
def get(self, key: str, default: None = ...) -> None:
...

@overload
def get(self, key: str, default: Any = ...) -> Any:
...

def get(self, key: str, default: Union[Any, None] = None) -> Union[Any, None]:
return super(_OMD, self).get(key, [default])[-1]
def get(self, key: str, default: Union[_T, None] = None) -> Union[_T, None]: # type: ignore
return super(_OMD, self).get(key, [default])[-1] # type: ignore

def getall(self, key: str) -> Any:
def getall(self, key: str) -> List[_T]:
return super(_OMD, self).__getitem__(key)

def items(self) -> List[Tuple[str, Any]]: # type: ignore[override]
def items(self) -> List[Tuple[str, _T]]: # type: ignore[override]
"""List of (key, last value for key)."""
return [(k, self[k]) for k in self]

def items_all(self) -> List[Tuple[str, List[Any]]]:
def items_all(self) -> List[Tuple[str, List[_T]]]:
"""List of (key, list of values for key)."""
return [(k, self.getall(k)) for k in self]

Expand All @@ -238,7 +237,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)): # type: ignore ## mypy does not understand dynamic class creation # noqa: E501
class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):

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

Expand Down Expand Up @@ -298,7 +297,10 @@ def __init__(self, file_or_files: Union[None, PathLike, 'BytesIO', Sequence[Unio
:param repo: Reference to repository to use if [includeIf] sections are found in configuration files.

"""
cp.RawConfigParser.__init__(self, dict_type=_OMD)
cp.RawConfigParser.__init__(self, dict_type=_OMD) # type: ignore[arg-type]
self._dict: Callable[..., _OMD] # type: ignore[assignment] # mypy/typeshed bug
self._defaults: _OMD # type: ignore[assignment] # mypy/typeshed bug
self._sections: _OMD # type: ignore[assignment] # mypy/typeshed bug

# Used in python 3, needs to stay in sync with sections for underlying implementation to work
if not hasattr(self, '_proxies'):
Expand All @@ -309,9 +311,9 @@ def __init__(self, file_or_files: Union[None, PathLike, 'BytesIO', Sequence[Unio
else:
if config_level is None:
if read_only:
self._file_or_files = [get_config_path(f)
self._file_or_files = [get_config_path(cast(Lit_config_levels, f))
for f in CONFIG_LEVELS
if is_config_level(f) and f != 'repository']
if f != 'repository']
else:
raise ValueError("No configuration level or configuration files specified")
else:
Expand Down Expand Up @@ -424,7 +426,7 @@ def string_decode(v: str) -> str:
# is it a section header?
mo = self.SECTCRE.match(line.strip())
if not is_multi_line and mo:
sectname = mo.group('header').strip()
sectname: str = mo.group('header').strip()
if sectname in self._sections:
cursect = self._sections[sectname]
elif sectname == cp.DEFAULTSECT:
Expand Down Expand Up @@ -535,7 +537,7 @@ def _included_paths(self) -> List[Tuple[str, str]]:

return paths

def read(self) -> None:
def read(self) -> None: # type: ignore[override]
"""Reads the data stored in the files we have been initialized with. It will
ignore files that cannot be read, possibly leaving an empty configuration

Expand Down Expand Up @@ -623,10 +625,11 @@ def write_section(name, section_dict):

if self._defaults:
write_section(cp.DEFAULTSECT, self._defaults)
value: TBD
for name, value in self._sections.items():
write_section(name, value)

def items(self, section_name: str) -> List[Tuple[str, str]]:
def items(self, section_name: str) -> List[Tuple[str, str]]: # type: ignore[override]
""":return: list((option, value), ...) pairs of all items in the given section"""
return [(k, v) for k, v in super(GitConfigParser, self).items(section_name) if k != '__name__']

Expand Down
14 changes: 7 additions & 7 deletions git/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

# typing ------------------------------------------------------------------

from typing import Any, Iterator, List, Match, Optional, Tuple, Type, TypeVar, Union, TYPE_CHECKING
from git.types import PathLike, TBD, Literal, TypeGuard
from typing import Any, Iterator, List, Match, Optional, Tuple, Type, TypeVar, Union, TYPE_CHECKING, cast
from git.types import PathLike, TBD, Literal

if TYPE_CHECKING:
from .objects.tree import Tree
Expand All @@ -28,9 +28,9 @@
Lit_change_type = Literal['A', 'D', 'C', 'M', 'R', 'T', 'U']


def is_change_type(inp: str) -> TypeGuard[Lit_change_type]:
# return True
return inp in ['A', 'D', 'C', 'M', 'R', 'T', 'U']
# def is_change_type(inp: str) -> TypeGuard[Lit_change_type]:
# # return True
# return inp in ['A', 'D', 'C', 'M', 'R', 'T', 'U']

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

Expand Down Expand Up @@ -517,8 +517,8 @@ def _handle_diff_line(lines_bytes: bytes, repo: 'Repo', index: DiffIndex) -> Non
# Change type can be R100
# R: status letter
# 100: score (in case of copy and rename)
assert is_change_type(_change_type[0]), f"Unexpected value for change_type received: {_change_type[0]}"
change_type: Lit_change_type = _change_type[0]
# assert is_change_type(_change_type[0]), f"Unexpected value for change_type received: {_change_type[0]}"
change_type: Lit_change_type = cast(Lit_change_type, _change_type[0])
score_str = ''.join(_change_type[1:])
score = int(score_str) if score_str.isdigit() else None
path = path.strip()
Expand Down
28 changes: 15 additions & 13 deletions git/index/fun.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@

from typing import (Dict, IO, List, Sequence, TYPE_CHECKING, Tuple, Type, Union, cast)

from git.types import PathLike, TypeGuard
from git.types import PathLike

if TYPE_CHECKING:
from .base import IndexFile
from git.db import GitCmdObjectDB
from git.objects.tree import TreeCacheTup
# from git.objects.fun import EntryTupOrNone

Expand Down Expand Up @@ -149,15 +150,15 @@ def write_cache(entries: Sequence[Union[BaseIndexEntry, 'IndexEntry']], stream:
# body
for entry in entries:
beginoffset = tell()
write(entry[4]) # ctime
write(entry[5]) # mtime
path_str: str = entry[3]
write(entry.ctime_bytes) # ctime
write(entry.mtime_bytes) # mtime
path_str = str(entry.path)
path: bytes = force_bytes(path_str, encoding=defenc)
plen = len(path) & CE_NAMEMASK # path length
assert plen == len(path), "Path %s too long to fit into index" % entry[3]
flags = plen | (entry[2] & CE_NAMEMASK_INV) # clear possible previous values
write(pack(">LLLLLL20sH", entry[6], entry[7], entry[0],
entry[8], entry[9], entry[10], entry[1], flags))
assert plen == len(path), "Path %s too long to fit into index" % entry.path
flags = plen | (entry.flags & CE_NAMEMASK_INV) # clear possible previous values
write(pack(">LLLLLL20sH", entry.dev, entry.inode, entry.mode,
entry.uid, entry.gid, entry.size, entry.binsha, flags))
write(path)
real_size = ((tell() - beginoffset + 8) & ~7)
write(b"\0" * ((beginoffset + real_size) - tell()))
Expand Down Expand Up @@ -188,15 +189,16 @@ def entry_key(*entry: Union[BaseIndexEntry, PathLike, int]) -> Tuple[PathLike, i
""":return: Key suitable to be used for the index.entries dictionary
:param entry: One instance of type BaseIndexEntry or the path and the stage"""

def is_entry_key_tup(entry_key: Tuple) -> TypeGuard[Tuple[PathLike, int]]:
return isinstance(entry_key, tuple) and len(entry_key) == 2
# def is_entry_key_tup(entry_key: Tuple) -> TypeGuard[Tuple[PathLike, int]]:
# return isinstance(entry_key, tuple) and len(entry_key) == 2

if len(entry) == 1:
entry_first = entry[0]
assert isinstance(entry_first, BaseIndexEntry)
return (entry_first.path, entry_first.stage)
else:
assert is_entry_key_tup(entry)
# assert is_entry_key_tup(entry)
entry = cast(Tuple[PathLike, int], entry)
return entry
# END handle entry

Expand Down Expand Up @@ -244,7 +246,7 @@ def read_cache(stream: IO[bytes]) -> Tuple[int, Dict[Tuple[PathLike, int], 'Inde
content_sha = extension_data[-20:]

# truncate the sha in the end as we will dynamically create it anyway
extension_data = extension_data[:-20]
extension_data = extension_data[: -20]

return (version, entries, extension_data, content_sha)

Expand Down Expand Up @@ -310,7 +312,7 @@ def _tree_entry_to_baseindexentry(tree_entry: 'TreeCacheTup', stage: int) -> Bas
return BaseIndexEntry((tree_entry[1], tree_entry[0], stage << CE_STAGESHIFT, tree_entry[2]))


def aggressive_tree_merge(odb, tree_shas: Sequence[bytes]) -> List[BaseIndexEntry]:
def aggressive_tree_merge(odb: 'GitCmdObjectDB', tree_shas: Sequence[bytes]) -> List[BaseIndexEntry]:
"""
:return: list of BaseIndexEntries representing the aggressive merge of the given
trees. All valid entries are on stage 0, whereas the conflicting ones are left
Expand Down
Loading