summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYobmod <yobmod@gmail.com>2021-07-01 10:35:11 +0100
committerYobmod <yobmod@gmail.com>2021-07-01 10:35:11 +0100
commit02b8ef0f163ca353e27f6b4a8c2120444739fde5 (patch)
tree0c8bad344c8111c0081ba70ec2688318abd795dd
parent8fd5414697724feff782e952a42ca5d9651418bc (diff)
downloadgitpython-02b8ef0f163ca353e27f6b4a8c2120444739fde5.tar.gz
Add missed types to Commit, uncomment to_native_path_linux()
-rw-r--r--git/cmd.py4
-rw-r--r--git/config.py10
-rw-r--r--git/index/base.py5
-rw-r--r--git/objects/commit.py82
-rw-r--r--git/objects/submodule/base.py6
-rw-r--r--git/objects/tree.py2
-rw-r--r--git/objects/util.py16
-rw-r--r--git/repo/base.py2
-rw-r--r--git/util.py12
9 files changed, 85 insertions, 54 deletions
diff --git a/git/cmd.py b/git/cmd.py
index e078e4a1..7df85581 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -342,11 +342,11 @@ class Git(LazyMixin):
@overload
@classmethod
- def polish_url(cls, url: PathLike, is_cygwin: Union[None, bool] = None) -> str:
+ def polish_url(cls, url: str, is_cygwin: Union[None, bool] = None) -> str:
...
@classmethod
- def polish_url(cls, url: PathLike, is_cygwin: Union[None, bool] = None) -> PathLike:
+ def polish_url(cls, url: str, is_cygwin: Union[None, bool] = None) -> PathLike:
if is_cygwin is None:
is_cygwin = cls.is_cygwin()
diff --git a/git/config.py b/git/config.py
index 7982baa3..5c5ceea8 100644
--- a/git/config.py
+++ b/git/config.py
@@ -694,6 +694,16 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
""":return: True if this instance may change the configuration file"""
return self._read_only
+ @overload
+ def get_value(self, section: str, option: str, default: str
+ ) -> str:
+ ...
+
+ @overload
+ def get_value(self, section: str, option: str, default: float
+ ) -> float:
+ ...
+
def get_value(self, section: str, option: str, default: Union[int, float, str, bool, None] = None
) -> Union[int, float, str, bool]:
# can default or return type include bool?
diff --git a/git/index/base.py b/git/index/base.py
index debd710f..f4ffba7b 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -75,6 +75,7 @@ if TYPE_CHECKING:
from subprocess import Popen
from git.repo import Repo
from git.refs.reference import Reference
+ from git.util import Actor
StageType = int
@@ -967,8 +968,8 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
return out
- def commit(self, message: str, parent_commits=None, head: bool = True, author: str = None,
- committer: str = None, author_date: str = None, commit_date: str = None,
+ def commit(self, message: str, parent_commits=None, head: bool = True, author: Union[None, 'Actor'] = None,
+ committer: Union[None, 'Actor'] = None, author_date: str = None, commit_date: str = None,
skip_hooks: bool = False) -> Commit:
"""Commit the current default index file, creating a commit object.
For more information on the arguments, see tree.commit.
diff --git a/git/objects/commit.py b/git/objects/commit.py
index 7d3ea4fa..0461f0e5 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -3,6 +3,8 @@
#
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
+import datetime
+from subprocess import Popen
from gitdb import IStream
from git.util import (
hex_to_bin,
@@ -37,9 +39,9 @@ import logging
# typing ------------------------------------------------------------------
-from typing import Any, Iterator, List, Sequence, Tuple, Union, TYPE_CHECKING
+from typing import Any, IO, Iterator, List, Sequence, Tuple, Union, TYPE_CHECKING
-from git.types import PathLike
+from git.types import PathLike, TypeGuard
if TYPE_CHECKING:
from git.repo import Repo
@@ -78,11 +80,17 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
"message", "parents", "encoding", "gpgsig")
_id_attribute_ = "hexsha"
- def __init__(self, repo, binsha, tree=None, author: Union[Actor, None] = None,
- authored_date=None, author_tz_offset=None,
- committer=None, committed_date=None, committer_tz_offset=None,
- message=None, parents: Union[Tuple['Commit', ...], List['Commit'], None] = None,
- encoding=None, gpgsig=None):
+ def __init__(self, repo: 'Repo', binsha: bytes, tree: 'Tree' = None,
+ author: Union[Actor, None] = None,
+ authored_date: Union[int, None] = None,
+ author_tz_offset: Union[None, float] = None,
+ committer: Union[Actor, None] = None,
+ committed_date: Union[int, None] = None,
+ committer_tz_offset: Union[None, float] = None,
+ message: Union[str, None] = None,
+ parents: Union[Sequence['Commit'], None] = None,
+ encoding: Union[str, None] = None,
+ gpgsig: Union[str, None] = None) -> None:
"""Instantiate a new Commit. All keyword arguments taking None as default will
be implicitly set on first query.
@@ -164,7 +172,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
istream = repo.odb.store(IStream(cls.type, streamlen, stream))
return istream.binsha
- def replace(self, **kwargs):
+ def replace(self, **kwargs: Any) -> 'Commit':
'''Create new commit object from existing commit object.
Any values provided as keyword arguments will replace the
@@ -183,7 +191,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
return new_commit
- def _set_cache_(self, attr):
+ def _set_cache_(self, attr: str) -> None:
if attr in Commit.__slots__:
# read the data in a chunk, its faster - then provide a file wrapper
_binsha, _typename, self.size, stream = self.repo.odb.stream(self.binsha)
@@ -193,19 +201,19 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
# END handle attrs
@property
- def authored_datetime(self):
+ def authored_datetime(self) -> 'datetime.datetime':
return from_timestamp(self.authored_date, self.author_tz_offset)
@property
- def committed_datetime(self):
+ def committed_datetime(self) -> 'datetime.datetime':
return from_timestamp(self.committed_date, self.committer_tz_offset)
@property
- def summary(self):
+ def summary(self) -> str:
""":return: First line of the commit message"""
return self.message.split('\n', 1)[0]
- def count(self, paths='', **kwargs):
+ def count(self, paths: Union[PathLike, Sequence[PathLike]] = '', **kwargs: Any) -> int:
"""Count the number of commits reachable from this commit
:param paths:
@@ -223,7 +231,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
return len(self.repo.git.rev_list(self.hexsha, **kwargs).splitlines())
@property
- def name_rev(self):
+ def name_rev(self) -> str:
"""
:return:
String describing the commits hex sha based on the closest Reference.
@@ -231,7 +239,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
return self.repo.git.name_rev(self)
@classmethod
- def iter_items(cls, repo: 'Repo', rev, # type: ignore
+ def iter_items(cls, repo: 'Repo', rev: str, # type: ignore
paths: Union[PathLike, Sequence[PathLike]] = '', **kwargs: Any
) -> Iterator['Commit']:
"""Find all commits matching the given criteria.
@@ -254,7 +262,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
# use -- in any case, to prevent possibility of ambiguous arguments
# see https://github.com/gitpython-developers/GitPython/issues/264
- args_list: List[Union[PathLike, Sequence[PathLike]]] = ['--']
+ args_list: List[PathLike] = ['--']
if paths:
paths_tup: Tuple[PathLike, ...]
@@ -286,7 +294,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
return self.iter_items(self.repo, self, paths, **kwargs)
@ property
- def stats(self):
+ def stats(self) -> Stats:
"""Create a git stat from changes between this commit and its first parent
or from all changes done if this is the very first commit.
@@ -303,16 +311,25 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
return Stats._list_from_string(self.repo, text)
@ classmethod
- def _iter_from_process_or_stream(cls, repo, proc_or_stream):
+ def _iter_from_process_or_stream(cls, repo: 'Repo', proc_or_stream: Union[Popen, IO]) -> Iterator['Commit']:
"""Parse out commit information into a list of Commit objects
We expect one-line per commit, and parse the actual commit information directly
from our lighting fast object database
:param proc: git-rev-list process instance - one sha per line
:return: iterator returning Commit objects"""
- stream = proc_or_stream
- if not hasattr(stream, 'readline'):
- stream = proc_or_stream.stdout
+
+ def is_proc(inp) -> TypeGuard[Popen]:
+ return hasattr(proc_or_stream, 'wait') and not hasattr(proc_or_stream, 'readline')
+
+ def is_stream(inp) -> TypeGuard[IO]:
+ return hasattr(proc_or_stream, 'readline')
+
+ if is_proc(proc_or_stream):
+ if proc_or_stream.stdout is not None:
+ stream = proc_or_stream.stdout
+ elif is_stream(proc_or_stream):
+ stream = proc_or_stream
readline = stream.readline
while True:
@@ -330,19 +347,21 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
# END for each line in stream
# TODO: Review this - it seems process handling got a bit out of control
# due to many developers trying to fix the open file handles issue
- if hasattr(proc_or_stream, 'wait'):
+ if is_proc(proc_or_stream):
finalize_process(proc_or_stream)
@ classmethod
- def create_from_tree(cls, repo, tree, message, parent_commits=None, head=False, author=None, committer=None,
- author_date=None, commit_date=None):
+ def create_from_tree(cls, repo: 'Repo', tree: Union['Tree', str], message: str,
+ parent_commits: Union[None, List['Commit']] = None, head: bool = False,
+ author: Union[None, Actor] = None, committer: Union[None, Actor] = None,
+ author_date: Union[None, str] = None, commit_date: Union[None, str] = None):
"""Commit the given tree, creating a commit object.
:param repo: Repo object the commit should be part of
:param tree: Tree object or hex or bin sha
the tree of the new commit
:param message: Commit message. It may be an empty string if no message is provided.
- It will be converted to a string in any case.
+ It will be converted to a string , in any case.
:param parent_commits:
Optional Commit objects to use as parents for the new commit.
If empty list, the commit will have no parents at all and become
@@ -476,7 +495,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
write(("encoding %s\n" % self.encoding).encode('ascii'))
try:
- if self.__getattribute__('gpgsig') is not None:
+ if self.__getattribute__('gpgsig'):
write(b"gpgsig")
for sigline in self.gpgsig.rstrip("\n").split("\n"):
write((" " + sigline + "\n").encode('ascii'))
@@ -526,7 +545,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
# now we can have the encoding line, or an empty line followed by the optional
# message.
self.encoding = self.default_encoding
- self.gpgsig = None
+ self.gpgsig = ""
# read headers
enc = next_line
@@ -555,7 +574,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
# decode the authors name
try:
- self.author, self.authored_date, self.author_tz_offset = \
+ (self.author, self.authored_date, self.author_tz_offset) = \
parse_actor_and_date(author_line.decode(self.encoding, 'replace'))
except UnicodeDecodeError:
log.error("Failed to decode author line '%s' using encoding %s", author_line, self.encoding,
@@ -571,11 +590,12 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
# a stream from our data simply gives us the plain message
# The end of our message stream is marked with a newline that we strip
- self.message = stream.read()
+ self.message_bytes = stream.read()
try:
- self.message = self.message.decode(self.encoding, 'replace')
+ self.message = self.message_bytes.decode(self.encoding, 'replace')
except UnicodeDecodeError:
- log.error("Failed to decode message '%s' using encoding %s", self.message, self.encoding, exc_info=True)
+ log.error("Failed to decode message '%s' using encoding %s",
+ self.message_bytes, self.encoding, exc_info=True)
# END exception handling
return self
diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
index 9b6ef6eb..a15034df 100644
--- a/git/objects/submodule/base.py
+++ b/git/objects/submodule/base.py
@@ -380,8 +380,8 @@ class Submodule(IndexObject, TraversableIterableObj):
# assure we never put backslashes into the url, as some operating systems
# like it ...
- # if url is not None:
- # url = to_native_path_linux(url) to_native_path_linux does nothing??
+ if url is not None:
+ url = to_native_path_linux(url)
# END assure url correctness
# INSTANTIATE INTERMEDIATE SM
@@ -993,7 +993,7 @@ class Submodule(IndexObject, TraversableIterableObj):
# If check is False, we might see a parent-commit that doesn't even contain the submodule anymore.
# in that case, mark our sha as being NULL
try:
- self.binsha = pctree[self.path].binsha
+ self.binsha = pctree[str(self.path)].binsha
except KeyError:
self.binsha = self.NULL_BIN_SHA
# end
diff --git a/git/objects/tree.py b/git/objects/tree.py
index f61a4a87..2e8d8a79 100644
--- a/git/objects/tree.py
+++ b/git/objects/tree.py
@@ -321,7 +321,7 @@ class Tree(IndexObject, diff.Diffable, util.Traversable, util.Serializable):
# assert is_tree_traversed(ret_tup), f"Type is {[type(x) for x in list(ret_tup[0])]}"
# return ret_tup[0]"""
return cast(Union[Iterator[IndexObjUnion], Iterator[TraversedTreeTup]],
- super(Tree, self).traverse(predicate, prune, depth, # type: ignore
+ super(Tree, self).traverse(predicate, prune, depth, # type: ignore
branch_first, visit_once, ignore_self))
# List protocol
diff --git a/git/objects/util.py b/git/objects/util.py
index ec81f87e..0b449b7b 100644
--- a/git/objects/util.py
+++ b/git/objects/util.py
@@ -99,7 +99,7 @@ def utctz_to_altz(utctz: str) -> int:
return -1 * int(float(utctz) / 100 * 3600)
-def altz_to_utctz_str(altz: int) -> str:
+def altz_to_utctz_str(altz: float) -> str:
"""As above, but inverses the operation, returning a string that can be used
in commit objects"""
utci = -1 * int((float(altz) / 3600) * 100)
@@ -323,8 +323,8 @@ class Traversable(object):
return out
def traverse(self,
- predicate: Callable[[Union['Traversable', TraversedTup], int], bool] = lambda i, d: True,
- prune: Callable[[Union['Traversable', TraversedTup], int], bool] = lambda i, d: False,
+ predicate: Callable[[Union['Traversable', 'Blob', TraversedTup], int], bool] = lambda i, d: True,
+ prune: Callable[[Union['Traversable', 'Blob', TraversedTup], int], bool] = lambda i, d: False,
depth: int = -1, branch_first: bool = True, visit_once: bool = True,
ignore_self: int = 1, as_edge: bool = False
) -> Union[Iterator[Union['Traversable', 'Blob']],
@@ -371,7 +371,7 @@ class Traversable(object):
ignore_self=False is_edge=False -> Iterator[Tuple[src, item]]"""
class TraverseNT(NamedTuple):
depth: int
- item: 'Traversable'
+ item: Union['Traversable', 'Blob']
src: Union['Traversable', None]
visited = set()
@@ -401,7 +401,7 @@ class Traversable(object):
if visit_once:
visited.add(item)
- rval: Union['Traversable', Tuple[Union[None, 'Traversable'], 'Traversable']]
+ rval: Union[TraversedTup, 'Traversable', 'Blob']
if as_edge: # if as_edge return (src, item) unless rrc is None (e.g. for first item)
rval = (src, item)
else:
@@ -478,15 +478,15 @@ class TraversableIterableObj(Traversable, IterableObj):
...
def traverse(self: T_TIobj,
- predicate: Callable[[Union[T_TIobj, Tuple[Union[T_TIobj, None], T_TIobj]], int],
+ predicate: Callable[[Union[T_TIobj, TIobj_tuple], int],
bool] = lambda i, d: True,
- prune: Callable[[Union[T_TIobj, Tuple[Union[T_TIobj, None], T_TIobj]], int],
+ prune: Callable[[Union[T_TIobj, TIobj_tuple], int],
bool] = lambda i, d: False,
depth: int = -1, branch_first: bool = True, visit_once: bool = True,
ignore_self: int = 1, as_edge: bool = False
) -> Union[Iterator[T_TIobj],
Iterator[Tuple[T_TIobj, T_TIobj]],
- Iterator[Tuple[Union[T_TIobj, None], T_TIobj]]]:
+ Iterator[TIobj_tuple]]:
"""For documentation, see util.Traversable._traverse()"""
"""
diff --git a/git/repo/base.py b/git/repo/base.py
index fd20deed..d77b19c1 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -1036,7 +1036,7 @@ class Repo(object):
multi = None
if multi_options:
multi = ' '.join(multi_options).split(' ')
- proc = git.clone(multi, Git.polish_url(url), clone_path, with_extended_output=True, as_process=True,
+ proc = git.clone(multi, Git.polish_url(str(url)), clone_path, with_extended_output=True, as_process=True,
v=True, universal_newlines=True, **add_progress(kwargs, git, progress))
if progress:
handle_process_output(proc, None, to_progress_instance(progress).new_message_handler(),
diff --git a/git/util.py b/git/util.py
index ebb119b9..abc82bd3 100644
--- a/git/util.py
+++ b/git/util.py
@@ -41,8 +41,8 @@ from .types import (Literal, Protocol, SupportsIndex, # becau
PathLike, HSH_TD, Total_TD, Files_TD) # aliases
T_IterableObj = TypeVar('T_IterableObj', bound='IterableObj', covariant=True)
-
# So IterableList[Head] is subtype of IterableList[IterableObj]
+
# ---------------------------------------------------------------------
@@ -175,7 +175,7 @@ if is_win:
path = str(path)
return path.replace('/', '\\')
- def to_native_path_linux(path: PathLike) -> PathLike:
+ def to_native_path_linux(path: PathLike) -> str:
path = str(path)
return path.replace('\\', '/')
@@ -183,8 +183,8 @@ if is_win:
to_native_path = to_native_path_windows
else:
# no need for any work on linux
- def to_native_path_linux(path: PathLike) -> PathLike:
- return path
+ def to_native_path_linux(path: PathLike) -> str:
+ return str(path)
to_native_path = to_native_path_linux
@@ -241,7 +241,7 @@ def py_where(program: str, path: Optional[PathLike] = None) -> List[str]:
return progs
-def _cygexpath(drive: Optional[str], path: PathLike) -> str:
+def _cygexpath(drive: Optional[str], path: str) -> str:
if osp.isabs(path) and not drive:
## Invoked from `cygpath()` directly with `D:Apps\123`?
# It's an error, leave it alone just slashes)
@@ -290,7 +290,7 @@ _cygpath_parsers = (
) # type: Tuple[Tuple[Pattern[str], Callable, bool], ...]
-def cygpath(path: PathLike) -> PathLike:
+def cygpath(path: str) -> str:
"""Use :meth:`git.cmd.Git.polish_url()` instead, that works on any environment."""
path = str(path) # ensure is str and not AnyPath.
#Fix to use Paths when 3.5 dropped. or to be just str if only for urls?