diff options
author | Yobmod <yobmod@gmail.com> | 2021-07-01 10:35:11 +0100 |
---|---|---|
committer | Yobmod <yobmod@gmail.com> | 2021-07-01 10:35:11 +0100 |
commit | 02b8ef0f163ca353e27f6b4a8c2120444739fde5 (patch) | |
tree | 0c8bad344c8111c0081ba70ec2688318abd795dd | |
parent | 8fd5414697724feff782e952a42ca5d9651418bc (diff) | |
download | gitpython-02b8ef0f163ca353e27f6b4a8c2120444739fde5.tar.gz |
Add missed types to Commit, uncomment to_native_path_linux()
-rw-r--r-- | git/cmd.py | 4 | ||||
-rw-r--r-- | git/config.py | 10 | ||||
-rw-r--r-- | git/index/base.py | 5 | ||||
-rw-r--r-- | git/objects/commit.py | 82 | ||||
-rw-r--r-- | git/objects/submodule/base.py | 6 | ||||
-rw-r--r-- | git/objects/tree.py | 2 | ||||
-rw-r--r-- | git/objects/util.py | 16 | ||||
-rw-r--r-- | git/repo/base.py | 2 | ||||
-rw-r--r-- | git/util.py | 12 |
9 files changed, 85 insertions, 54 deletions
@@ -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? |