summaryrefslogtreecommitdiff
path: root/git/objects/commit.py
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 /git/objects/commit.py
parent8fd5414697724feff782e952a42ca5d9651418bc (diff)
downloadgitpython-02b8ef0f163ca353e27f6b4a8c2120444739fde5.tar.gz
Add missed types to Commit, uncomment to_native_path_linux()
Diffstat (limited to 'git/objects/commit.py')
-rw-r--r--git/objects/commit.py82
1 files changed, 51 insertions, 31 deletions
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