summaryrefslogtreecommitdiff
path: root/git
diff options
context:
space:
mode:
Diffstat (limited to 'git')
-rw-r--r--git/compat.py16
-rw-r--r--git/config.py55
-rw-r--r--git/index/typ.py3
-rw-r--r--git/objects/submodule/base.py14
-rw-r--r--git/objects/submodule/util.py2
-rw-r--r--git/remote.py3
-rw-r--r--git/repo/base.py6
7 files changed, 40 insertions, 59 deletions
diff --git a/git/compat.py b/git/compat.py
index 7a0a15d2..b3b6ab81 100644
--- a/git/compat.py
+++ b/git/compat.py
@@ -97,19 +97,3 @@ def win_encode(s: Optional[AnyStr]) -> Optional[bytes]:
elif s is not None:
raise TypeError('Expected bytes or text, but got %r' % (s,))
return None
-
-
-# type: ignore ## mypy cannot understand dynamic class creation
-def with_metaclass(meta: Type[Any], *bases: Any) -> TBD:
- """copied from https://github.com/Byron/bcore/blob/master/src/python/butility/future.py#L15"""
-
- class metaclass(meta): # type: ignore
- __call__ = type.__call__
- __init__ = type.__init__ # type: ignore
-
- def __new__(cls, name: str, nbases: Optional[Tuple[int, ...]], d: Dict[str, Any]) -> TBD:
- if nbases is None:
- return type.__new__(cls, name, (), d)
- return meta(name, bases, d)
-
- return metaclass(meta.__name__ + 'Helper', None, {}) # type: ignore
diff --git a/git/config.py b/git/config.py
index b25707b2..76200f31 100644
--- a/git/config.py
+++ b/git/config.py
@@ -14,12 +14,10 @@ import logging
import os
import re
import fnmatch
-from collections import OrderedDict
from git.compat import (
defenc,
force_text,
- with_metaclass,
is_win,
)
@@ -31,15 +29,16 @@ import configparser as cp
# 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
+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')
# -------------------------------------------------------------
__all__ = ('GitConfigParser', 'SectionConstraint')
@@ -61,7 +60,6 @@ CONDITIONAL_INCLUDE_REGEXP = re.compile(r"(?<=includeIf )\"(gitdir|gitdir/i|onbr
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:
"""
@@ -115,7 +113,7 @@ def set_dirty_and_flush_changes(non_const_func: Callable) -> Callable:
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.
@@ -128,7 +126,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
@@ -149,7 +147,7 @@ class SectionConstraint(object):
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
@@ -157,7 +155,7 @@ class SectionConstraint(object):
"""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
@@ -165,10 +163,10 @@ class SectionConstraint(object):
self._config.__exit__(exception_type, exception_value, traceback)
-class _OMD(OrderedDict):
+class _OMD(Dict[str, List[_T]]):
"""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:
@@ -177,7 +175,7 @@ class _OMD(OrderedDict):
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:
@@ -194,25 +192,17 @@ class _OMD(OrderedDict):
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]
@@ -238,7 +228,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.
@@ -298,7 +288,10 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser)): #
: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'):
@@ -424,7 +417,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser)): #
# 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:
@@ -535,7 +528,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser)): #
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
@@ -626,7 +619,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser)): #
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__']
diff --git a/git/index/typ.py b/git/index/typ.py
index 5b2ad5f6..46f1b077 100644
--- a/git/index/typ.py
+++ b/git/index/typ.py
@@ -82,7 +82,8 @@ class BaseIndexEntry(BaseIndexEntryHelper):
As the first 4 data members match exactly to the IndexEntry type, methods
expecting a BaseIndexEntry can also handle full IndexEntries even if they
- use numeric indices for performance reasons. """
+ use numeric indices for performance reasons.
+ """
def __new__(cls, inp_tuple: Union[Tuple[int, bytes, int, PathLike],
Tuple[int, bytes, int, PathLike, bytes, bytes, int, int, int, int, int]]
diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
index d5ba118f..29212167 100644
--- a/git/objects/submodule/base.py
+++ b/git/objects/submodule/base.py
@@ -965,13 +965,12 @@ class Submodule(IndexObject, TraversableIterableObj):
# now git config - need the config intact, otherwise we can't query
# information anymore
- writer: Union[GitConfigParser, SectionConstraint]
- with self.repo.config_writer() as writer:
- writer.remove_section(sm_section(self.name))
+ with self.repo.config_writer() as gcp_writer:
+ gcp_writer.remove_section(sm_section(self.name))
- with self.config_writer() as writer:
- writer.remove_section()
+ with self.config_writer() as sc_writer:
+ sc_writer.remove_section()
# END delete configuration
return self
@@ -1024,7 +1023,8 @@ class Submodule(IndexObject, TraversableIterableObj):
return self
@unbare_repo
- def config_writer(self, index: Union['IndexFile', None] = None, write: bool = True) -> SectionConstraint:
+ def config_writer(self, index: Union['IndexFile', None] = None, write: bool = True
+ ) -> SectionConstraint['SubmoduleConfigParser']:
""":return: a config writer instance allowing you to read and write the data
belonging to this submodule into the .gitmodules file.
@@ -1201,7 +1201,7 @@ class Submodule(IndexObject, TraversableIterableObj):
"""
return self._name
- def config_reader(self) -> SectionConstraint:
+ def config_reader(self) -> SectionConstraint[SubmoduleConfigParser]:
"""
:return: ConfigReader instance which allows you to qurey the configuration values
of this submodule, as provided by the .gitmodules file
diff --git a/git/objects/submodule/util.py b/git/objects/submodule/util.py
index a776af88..cc1cd60a 100644
--- a/git/objects/submodule/util.py
+++ b/git/objects/submodule/util.py
@@ -100,7 +100,7 @@ class SubmoduleConfigParser(GitConfigParser):
#} END interface
#{ Overridden Methods
- def write(self) -> None:
+ def write(self) -> None: # type: ignore[override]
rval: None = super(SubmoduleConfigParser, self).write()
self.flush_to_index()
return rval
diff --git a/git/remote.py b/git/remote.py
index 7da466e6..11007cb6 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -23,6 +23,7 @@ from git.util import (
)
from .config import (
+ GitConfigParser,
SectionConstraint,
cp,
)
@@ -911,7 +912,7 @@ class Remote(LazyMixin, IterableObj):
return self._get_push_info(proc, progress)
@ property
- def config_reader(self) -> SectionConstraint:
+ def config_reader(self) -> SectionConstraint[GitConfigParser]:
"""
:return:
GitConfigParser compatible object able to read options for only our remote.
diff --git a/git/repo/base.py b/git/repo/base.py
index 03851756..a57172c6 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -482,7 +482,8 @@ class Repo(object):
raise ValueError("Invalid configuration level: %r" % config_level)
- def config_reader(self, config_level: Optional[Lit_config_levels] = None) -> GitConfigParser:
+ def config_reader(self, config_level: Optional[Lit_config_levels] = None
+ ) -> GitConfigParser:
"""
:return:
GitConfigParser allowing to read the full git configuration, but not to write it
@@ -504,7 +505,8 @@ class Repo(object):
files = [self._get_config_path(config_level)]
return GitConfigParser(files, read_only=True, repo=self)
- def config_writer(self, config_level: Lit_config_levels = "repository") -> GitConfigParser:
+ def config_writer(self, config_level: Lit_config_levels = "repository"
+ ) -> GitConfigParser:
"""
:return:
GitConfigParser allowing to write values of the specified configuration file level.