From c878771e3a31c983a0c3468396ed33a532f87e98 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 22:59:11 +0100 Subject: replace more TBDs wiht runtime types --- git/repo/base.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 5581233b..07cf7adf 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -235,7 +235,7 @@ class Repo(object): def __enter__(self) -> 'Repo': return self - def __exit__(self, exc_type: TBD, exc_value: TBD, traceback: TBD) -> None: + def __exit__(self, *args: Any) -> None: self.close() def __del__(self) -> None: @@ -445,7 +445,7 @@ class Repo(object): :return: TagReference object """ return TagReference.create(self, path, ref, message, force, **kwargs) - def delete_tag(self, *tags: TBD) -> None: + def delete_tag(self, *tags: TagReference) -> None: """Delete the given tag references""" return TagReference.delete(self, *tags) @@ -795,7 +795,7 @@ class Repo(object): # reveal_type(self.head.reference) # => Reference return self.head.reference - def blame_incremental(self, rev: TBD, file: TBD, **kwargs: Any) -> Optional[Iterator['BlameEntry']]: + def blame_incremental(self, rev: Union[str, HEAD], file: str, **kwargs: Any) -> Iterator['BlameEntry']: """Iterator for blame information for the given file at the given revision. Unlike .blame(), this does not return the actual file's contents, only @@ -809,6 +809,7 @@ class Repo(object): If you combine all line number ranges outputted by this command, you should get a continuous range spanning all line numbers in the file. """ + data = self.git.blame(rev, '--', file, p=True, incremental=True, stdout_as_string=False, **kwargs) commits: Dict[str, Commit] = {} @@ -870,7 +871,7 @@ class Repo(object): safe_decode(orig_filename), range(orig_lineno, orig_lineno + num_lines)) - def blame(self, rev: TBD, file: TBD, incremental: bool = False, **kwargs: Any + def blame(self, rev: Union[str, HEAD], file: str, incremental: bool = False, **kwargs: Any ) -> Union[List[List[Union[Optional['Commit'], List[str]]]], Optional[Iterator[BlameEntry]]]: """The blame information for the given file at the given revision. -- cgit v1.2.1 From 91fce331de16de6039c94cd4d7314184a5763e61 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 14:56:03 +0100 Subject: increase mypy strictness (warn unused ignored and warn unreachable) --- git/repo/base.py | 1 - 1 file changed, 1 deletion(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 07cf7adf..2609bf55 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -200,7 +200,6 @@ class Repo(object): # END while curpath if self.git_dir is None: - self.git_dir = cast(PathLike, self.git_dir) raise InvalidGitRepositoryError(epath) self._bare = False -- cgit v1.2.1 From 481f672baab666d6e2f81e9288a5f3c42c884a8e Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 17:56:06 +0100 Subject: Add __future__.annotations to repo/base.py --- git/repo/base.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 2609bf55..6708872e 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -3,6 +3,7 @@ # # This module is part of GitPython and is released under # the BSD License: http://www.opensource.org/licenses/bsd-license.php +from __future__ import annotations import logging import os import re @@ -384,13 +385,13 @@ class Repo(object): :return: created submodules""" return Submodule.add(self, *args, **kwargs) - def iter_submodules(self, *args: Any, **kwargs: Any) -> Iterator: + def iter_submodules(self, *args: Any, **kwargs: Any) -> Iterator[Submodule]: """An iterator yielding Submodule instances, see Traversable interface for a description of args and kwargs :return: Iterator""" return RootModule(self).traverse(*args, **kwargs) - def submodule_update(self, *args: Any, **kwargs: Any) -> Iterator: + def submodule_update(self, *args: Any, **kwargs: Any) -> Iterator[Submodule]: """Update the submodules, keeping the repository consistent as it will take the previous state into consideration. For more information, please see the documentation of RootModule.update""" @@ -774,7 +775,7 @@ class Repo(object): finalize_process(proc) return untracked_files - def ignored(self, *paths: PathLike) -> List[PathLike]: + def ignored(self, *paths: PathLike) -> List[str]: """Checks if paths are ignored via .gitignore Doing so using the "git check-ignore" method. @@ -782,7 +783,7 @@ class Repo(object): :return: subset of those paths which are ignored """ try: - proc = self.git.check_ignore(*paths) + proc: str = self.git.check_ignore(*paths) except GitCommandError: return [] return proc.replace("\\\\", "\\").replace('"', "").split("\n") -- cgit v1.2.1 From f34a39f206b5e2d408d4d47b0cc2012775d00917 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 18:25:20 +0100 Subject: Test new union syntax (Pep604) --- git/repo/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 6708872e..b7eecbc3 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -795,7 +795,7 @@ class Repo(object): # reveal_type(self.head.reference) # => Reference return self.head.reference - def blame_incremental(self, rev: Union[str, HEAD], file: str, **kwargs: Any) -> Iterator['BlameEntry']: + def blame_incremental(self, rev: str | HEAD, file: str, **kwargs: Any) -> Iterator['BlameEntry']: """Iterator for blame information for the given file at the given revision. Unlike .blame(), this does not return the actual file's contents, only -- cgit v1.2.1 From 4dd06c3e43bf3ccaf592ffa30120501ab4e8b58c Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 18:33:26 +0100 Subject: Test trailing comma in args (>py3.6?) --- git/repo/base.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index b7eecbc3..b9399f62 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -38,7 +38,7 @@ import gitdb # typing ------------------------------------------------------ -from git.types import TBD, PathLike, Lit_config_levels, Commit_ish, Tree_ish +from git.types import TBD, PathLike, Lit_config_levels, Commit_ish, Tree_ish, assert_never from typing import (Any, BinaryIO, Callable, Dict, Iterator, List, Mapping, Optional, Sequence, TextIO, Tuple, Type, Union, @@ -481,10 +481,12 @@ class Repo(object): raise NotADirectoryError else: return osp.normpath(osp.join(repo_dir, "config")) + else: - raise ValueError("Invalid configuration level: %r" % config_level) + assert_never(config_level, # type:ignore[unreachable] + ValueError(f"Invalid configuration level: {config_level!r}")) - def config_reader(self, config_level: Optional[Lit_config_levels] = None + def config_reader(self, config_level: Optional[Lit_config_levels] = None, ) -> GitConfigParser: """ :return: -- cgit v1.2.1 From 94ae0c5839cf8de3b67c8dfd449ad9cef696aefb Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 22:15:18 +0100 Subject: Test Dataclass in repo.base.blame() --- git/repo/base.py | 103 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 37 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index b9399f62..bedd6a08 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -7,6 +7,7 @@ from __future__ import annotations import logging import os import re +from dataclasses import dataclass import shlex import warnings from gitdb.db.loose import LooseObjectDB @@ -41,7 +42,7 @@ import gitdb from git.types import TBD, PathLike, Lit_config_levels, Commit_ish, Tree_ish, assert_never from typing import (Any, BinaryIO, Callable, Dict, Iterator, List, Mapping, Optional, Sequence, - TextIO, Tuple, Type, Union, + TextIO, Tuple, Type, TypedDict, Union, NamedTuple, cast, TYPE_CHECKING) from git.types import ConfigLevels_Tup @@ -53,7 +54,6 @@ if TYPE_CHECKING: from git.objects.submodule.base import UpdateProgress from git.remote import RemoteProgress - # ----------------------------------------------------------- log = logging.getLogger(__name__) @@ -874,7 +874,7 @@ class Repo(object): range(orig_lineno, orig_lineno + num_lines)) def blame(self, rev: Union[str, HEAD], file: str, incremental: bool = False, **kwargs: Any - ) -> Union[List[List[Union[Optional['Commit'], List[str]]]], Optional[Iterator[BlameEntry]]]: + ) -> List[List[Commit | List[str | bytes] | None]] | Iterator[BlameEntry] | None: """The blame information for the given file at the given revision. :param rev: revision specifier, see git-rev-parse for viable options. @@ -886,25 +886,52 @@ class Repo(object): if incremental: return self.blame_incremental(rev, file, **kwargs) - data = self.git.blame(rev, '--', file, p=True, stdout_as_string=False, **kwargs) - commits: Dict[str, TBD] = {} - blames: List[List[Union[Optional['Commit'], List[str]]]] = [] - - info: Dict[str, TBD] = {} # use Any until TypedDict available + data: bytes = self.git.blame(rev, '--', file, p=True, stdout_as_string=False, **kwargs) + commits: Dict[str, Commit] = {} + blames: List[List[Commit | List[str | bytes] | None]] = [] + + class InfoTC(TypedDict, total=False): + sha: str + id: str + filename: str + summary: str + author: str + author_email: str + author_date: int + committer: str + committer_email: str + committer_date: int + + @dataclass + class InfoDC(Dict[str, Union[str, int]]): + sha: str = '' + id: str = '' + filename: str = '' + summary: str = '' + author: str = '' + author_email: str = '' + author_date: int = 0 + committer: str = '' + committer_email: str = '' + committer_date: int = 0 + + # info: InfoTD = {} + info = InfoDC() keepends = True - for line in data.splitlines(keepends): + for line_bytes in data.splitlines(keepends): try: - line = line.rstrip().decode(defenc) + line_str = line_bytes.rstrip().decode(defenc) except UnicodeDecodeError: firstpart = '' + parts = [''] is_binary = True else: # As we don't have an idea when the binary data ends, as it could contain multiple newlines # in the process. So we rely on being able to decode to tell us what is is. # This can absolutely fail even on text files, but even if it does, we should be fine treating it # as binary instead - parts = self.re_whitespace.split(line, 1) + parts = self.re_whitespace.split(line_str, 1) firstpart = parts[0] is_binary = False # end handle decode of line @@ -916,10 +943,10 @@ class Repo(object): # another line of blame with the same data digits = parts[-1].split(" ") if len(digits) == 3: - info = {'id': firstpart} + info.id = firstpart blames.append([None, []]) - elif info['id'] != firstpart: - info = {'id': firstpart} + elif info.id != firstpart: + info.id = firstpart blames.append([commits.get(firstpart), []]) # END blame data initialization else: @@ -936,9 +963,9 @@ class Repo(object): # committer-tz -0700 - IGNORED BY US role = m.group(0) if firstpart.endswith('-mail'): - info["%s_email" % role] = parts[-1] + info[f"{role}_email"] = parts[-1] elif firstpart.endswith('-time'): - info["%s_date" % role] = int(parts[-1]) + info[f"{role}_date"] = int(parts[-1]) elif role == firstpart: info[role] = parts[-1] # END distinguish mail,time,name @@ -953,38 +980,40 @@ class Repo(object): info['summary'] = parts[-1] elif firstpart == '': if info: - sha = info['id'] + sha = info.id c = commits.get(sha) if c is None: c = Commit(self, hex_to_bin(sha), - author=Actor._from_string(info['author'] + ' ' + info['author_email']), - authored_date=info['author_date'], + author=Actor._from_string(info.author + ' ' + info.author_email), + authored_date=info.author_date, committer=Actor._from_string( - info['committer'] + ' ' + info['committer_email']), - committed_date=info['committer_date']) + info.committer + ' ' + info.committer_email), + committed_date=info.committer_date) commits[sha] = c + blames[-1][0] = c # END if commit objects needs initial creation - if not is_binary: - if line and line[0] == '\t': - line = line[1:] - else: - # NOTE: We are actually parsing lines out of binary data, which can lead to the - # binary being split up along the newline separator. We will append this to the blame - # we are currently looking at, even though it should be concatenated with the last line - # we have seen. - pass - # end handle line contents - blames[-1][0] = c if blames[-1][1] is not None: - blames[-1][1].append(line) - info = {'id': sha} + if not is_binary: + if line_str and line_str[0] == '\t': + line_str = line_str[1:] + + blames[-1][1].append(line_str) + else: + # NOTE: We are actually parsing lines out of binary data, which can lead to the + # binary being split up along the newline separator. We will append this to the + # blame we are currently looking at, even though it should be concatenated with + # the last line we have seen. + blames[-1][1].append(line_bytes) + # end handle line contents + + info.id = sha # END if we collected commit info # END distinguish filename,summary,rest # END distinguish author|committer vs filename,summary,rest # END distinguish hexsha vs other information return blames - @classmethod + @ classmethod def init(cls, path: Union[PathLike, None] = None, mkdir: bool = True, odbt: Type[GitCmdObjectDB] = GitCmdObjectDB, expand_vars: bool = True, **kwargs: Any) -> 'Repo': """Initialize a git repository at the given path if specified @@ -1023,7 +1052,7 @@ class Repo(object): git.init(**kwargs) return cls(path, odbt=odbt) - @classmethod + @ classmethod def _clone(cls, git: 'Git', url: PathLike, path: PathLike, odb_default_type: Type[GitCmdObjectDB], progress: Union['RemoteProgress', 'UpdateProgress', Callable[..., 'RemoteProgress'], None] = None, multi_options: Optional[List[str]] = None, **kwargs: Any @@ -1101,7 +1130,7 @@ class Repo(object): :return: ``git.Repo`` (the newly cloned repo)""" return self._clone(self.git, self.common_dir, path, type(self.odb), progress, multi_options, **kwargs) - @classmethod + @ classmethod def clone_from(cls, url: PathLike, to_path: PathLike, progress: Optional[Callable] = None, env: Optional[Mapping[str, Any]] = None, multi_options: Optional[List[str]] = None, **kwargs: Any) -> 'Repo': -- cgit v1.2.1 From a3f5b1308f3340375832f1f2254b41c1ecbbc17e Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 22:18:28 +0100 Subject: Test Dataclass in repo.base.blame() 2 --- git/repo/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index bedd6a08..a9d2e5be 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -42,10 +42,10 @@ import gitdb from git.types import TBD, PathLike, Lit_config_levels, Commit_ish, Tree_ish, assert_never from typing import (Any, BinaryIO, Callable, Dict, Iterator, List, Mapping, Optional, Sequence, - TextIO, Tuple, Type, TypedDict, Union, + TextIO, Tuple, Type, Union, NamedTuple, cast, TYPE_CHECKING) -from git.types import ConfigLevels_Tup +from git.types import ConfigLevels_Tup, TypedDict if TYPE_CHECKING: from git.util import IterableList -- cgit v1.2.1 From a2a36e06942d7a146d6640f275d4a4ec84e187c0 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 22:26:14 +0100 Subject: Test Dataclass in repo.base.blame() 3 --- git/repo/base.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index a9d2e5be..0f231e5f 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -890,7 +890,7 @@ class Repo(object): commits: Dict[str, Commit] = {} blames: List[List[Commit | List[str | bytes] | None]] = [] - class InfoTC(TypedDict, total=False): + class InfoTD(TypedDict, total=False): sha: str id: str filename: str @@ -992,19 +992,20 @@ class Repo(object): commits[sha] = c blames[-1][0] = c # END if commit objects needs initial creation - if blames[-1][1] is not None: - if not is_binary: - if line_str and line_str[0] == '\t': - line_str = line_str[1:] - - blames[-1][1].append(line_str) - else: - # NOTE: We are actually parsing lines out of binary data, which can lead to the - # binary being split up along the newline separator. We will append this to the - # blame we are currently looking at, even though it should be concatenated with - # the last line we have seen. - blames[-1][1].append(line_bytes) + if not is_binary: + if line_str and line_str[0] == '\t': + line_str = line_str[1:] + line_AnyStr: str | bytes = line_str + else: + line_AnyStr = line_bytes + # NOTE: We are actually parsing lines out of binary data, which can lead to the + # binary being split up along the newline separator. We will append this to the + # blame we are currently looking at, even though it should be concatenated with + # the last line we have seen. + # end handle line contents + if blames[-1][1] is not None: + blames[-1][1].append(line_AnyStr) info.id = sha # END if we collected commit info -- cgit v1.2.1 From ed137cbddf69ae11e5287a9e96e1df1a6e71250d Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 22:35:03 +0100 Subject: Test TypedDict in repo.base.blame() 2 --- git/repo/base.py | 80 +++++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 44 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 0f231e5f..0a12d959 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -7,7 +7,6 @@ from __future__ import annotations import logging import os import re -from dataclasses import dataclass import shlex import warnings from gitdb.db.loose import LooseObjectDB @@ -902,21 +901,7 @@ class Repo(object): committer_email: str committer_date: int - @dataclass - class InfoDC(Dict[str, Union[str, int]]): - sha: str = '' - id: str = '' - filename: str = '' - summary: str = '' - author: str = '' - author_email: str = '' - author_date: int = 0 - committer: str = '' - committer_email: str = '' - committer_date: int = 0 - - # info: InfoTD = {} - info = InfoDC() + info: InfoTD = {} keepends = True for line_bytes in data.splitlines(keepends): @@ -943,10 +928,10 @@ class Repo(object): # another line of blame with the same data digits = parts[-1].split(" ") if len(digits) == 3: - info.id = firstpart + info = {'id': firstpart} blames.append([None, []]) - elif info.id != firstpart: - info.id = firstpart + elif info['id'] != firstpart: + info = {'id': firstpart} blames.append([commits.get(firstpart), []]) # END blame data initialization else: @@ -962,12 +947,20 @@ class Repo(object): # committer-time 1192271832 # committer-tz -0700 - IGNORED BY US role = m.group(0) - if firstpart.endswith('-mail'): - info[f"{role}_email"] = parts[-1] - elif firstpart.endswith('-time'): - info[f"{role}_date"] = int(parts[-1]) - elif role == firstpart: - info[role] = parts[-1] + if role == 'author': + if firstpart.endswith('-mail'): + info["author_email"] = parts[-1] + elif firstpart.endswith('-time'): + info["author_date"] = int(parts[-1]) + elif role == firstpart: + info["author"] = parts[-1] + elif role == 'committer': + if firstpart.endswith('-mail'): + info["committer_email"] = parts[-1] + elif firstpart.endswith('-time'): + info["committer_date"] = int(parts[-1]) + elif role == firstpart: + info["committer"] = parts[-1] # END distinguish mail,time,name else: # handle @@ -980,34 +973,33 @@ class Repo(object): info['summary'] = parts[-1] elif firstpart == '': if info: - sha = info.id + sha = info['id'] c = commits.get(sha) if c is None: c = Commit(self, hex_to_bin(sha), - author=Actor._from_string(info.author + ' ' + info.author_email), - authored_date=info.author_date, + author=Actor._from_string(info['author'] + ' ' + info['author_email']), + authored_date=info['author_date'], committer=Actor._from_string( - info.committer + ' ' + info.committer_email), - committed_date=info.committer_date) + info['committer'] + ' ' + info['committer_email']), + committed_date=info['committer_date']) commits[sha] = c blames[-1][0] = c # END if commit objects needs initial creation - if not is_binary: - if line_str and line_str[0] == '\t': - line_str = line_str[1:] - line_AnyStr: str | bytes = line_str - else: - line_AnyStr = line_bytes - # NOTE: We are actually parsing lines out of binary data, which can lead to the - # binary being split up along the newline separator. We will append this to the - # blame we are currently looking at, even though it should be concatenated with - # the last line we have seen. - - # end handle line contents if blames[-1][1] is not None: - blames[-1][1].append(line_AnyStr) + if not is_binary: + if line_str and line_str[0] == '\t': + line_str = line_str[1:] + + blames[-1][1].append(line_str) + else: + # NOTE: We are actually parsing lines out of binary data, which can lead to the + # binary being split up along the newline separator. We will append this to the + # blame we are currently looking at, even though it should be concatenated with + # the last line we have seen. + blames[-1][1].append(line_bytes) + # end handle line contents - info.id = sha + info = {'id': sha} # END if we collected commit info # END distinguish filename,summary,rest # END distinguish author|committer vs filename,summary,rest -- cgit v1.2.1 From e4761ff67ef14df27026bbe9e215b9ddf5e5b3a5 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 22:45:19 +0100 Subject: Test TypedDict in repo.base.blame() 1 --- git/repo/base.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 0a12d959..58b9d5c2 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -909,7 +909,7 @@ class Repo(object): line_str = line_bytes.rstrip().decode(defenc) except UnicodeDecodeError: firstpart = '' - parts = [''] + parts = [] is_binary = True else: # As we don't have an idea when the binary data ends, as it could contain multiple newlines @@ -983,20 +983,21 @@ class Repo(object): info['committer'] + ' ' + info['committer_email']), committed_date=info['committer_date']) commits[sha] = c - blames[-1][0] = c + blames[-1][0] = c # END if commit objects needs initial creation + if not is_binary: + if line_str and line_str[0] == '\t': + line_str = line_str[1:] + else: + pass + # NOTE: We are actually parsing lines out of binary data, which can lead to the + # binary being split up along the newline separator. We will append this to the + # blame we are currently looking at, even though it should be concatenated with + # the last line we have seen. + if blames[-1][1] is not None: - if not is_binary: - if line_str and line_str[0] == '\t': - line_str = line_str[1:] - - blames[-1][1].append(line_str) - else: - # NOTE: We are actually parsing lines out of binary data, which can lead to the - # binary being split up along the newline separator. We will append this to the - # blame we are currently looking at, even though it should be concatenated with - # the last line we have seen. - blames[-1][1].append(line_bytes) + blames[-1][1].append(line_str) + info = {'id': sha} # end handle line contents info = {'id': sha} -- cgit v1.2.1 From 1aaa7048ddecb4509e1c279e28de5ef71477e71f Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 22:50:11 +0100 Subject: Test Dataclass in repo.base.blame() 4 --- git/repo/base.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 58b9d5c2..2bfc4677 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -985,22 +985,21 @@ class Repo(object): commits[sha] = c blames[-1][0] = c # END if commit objects needs initial creation - if not is_binary: - if line_str and line_str[0] == '\t': - line_str = line_str[1:] - else: - pass - # NOTE: We are actually parsing lines out of binary data, which can lead to the - # binary being split up along the newline separator. We will append this to the - # blame we are currently looking at, even though it should be concatenated with - # the last line we have seen. if blames[-1][1] is not None: - blames[-1][1].append(line_str) + if not is_binary: + if line_str and line_str[0] == '\t': + line_str = line_str[1:] + blames[-1][1].append(line_str) + else: + blames[-1][1].append(line_bytes) + # NOTE: We are actually parsing lines out of binary data, which can lead to the + # binary being split up along the newline separator. We will append this to the + # blame we are currently looking at, even though it should be concatenated with + # the last line we have seen. info = {'id': sha} # end handle line contents - info = {'id': sha} # END if we collected commit info # END distinguish filename,summary,rest # END distinguish author|committer vs filename,summary,rest -- cgit v1.2.1 From bc9bcf51ef68385895d8cdbc76098d6b493cd1b6 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 22:52:10 +0100 Subject: Test Dataclass in repo.base.blame() 5 --- git/repo/base.py | 67 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 2bfc4677..a0aee322 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -7,6 +7,7 @@ from __future__ import annotations import logging import os import re +from dataclasses import dataclass import shlex import warnings from gitdb.db.loose import LooseObjectDB @@ -41,10 +42,10 @@ import gitdb from git.types import TBD, PathLike, Lit_config_levels, Commit_ish, Tree_ish, assert_never from typing import (Any, BinaryIO, Callable, Dict, Iterator, List, Mapping, Optional, Sequence, - TextIO, Tuple, Type, Union, + TextIO, Tuple, Type, TypedDict, Union, NamedTuple, cast, TYPE_CHECKING) -from git.types import ConfigLevels_Tup, TypedDict +from git.types import ConfigLevels_Tup if TYPE_CHECKING: from git.util import IterableList @@ -889,7 +890,7 @@ class Repo(object): commits: Dict[str, Commit] = {} blames: List[List[Commit | List[str | bytes] | None]] = [] - class InfoTD(TypedDict, total=False): + class InfoTC(TypedDict, total=False): sha: str id: str filename: str @@ -901,7 +902,21 @@ class Repo(object): committer_email: str committer_date: int - info: InfoTD = {} + @dataclass + class InfoDC(Dict[str, Union[str, int]]): + sha: str = '' + id: str = '' + filename: str = '' + summary: str = '' + author: str = '' + author_email: str = '' + author_date: int = 0 + committer: str = '' + committer_email: str = '' + committer_date: int = 0 + + # info: InfoTD = {} + info = InfoDC() keepends = True for line_bytes in data.splitlines(keepends): @@ -909,7 +924,7 @@ class Repo(object): line_str = line_bytes.rstrip().decode(defenc) except UnicodeDecodeError: firstpart = '' - parts = [] + parts = [''] is_binary = True else: # As we don't have an idea when the binary data ends, as it could contain multiple newlines @@ -928,10 +943,10 @@ class Repo(object): # another line of blame with the same data digits = parts[-1].split(" ") if len(digits) == 3: - info = {'id': firstpart} + info.id = firstpart blames.append([None, []]) - elif info['id'] != firstpart: - info = {'id': firstpart} + elif info.id != firstpart: + info.id = firstpart blames.append([commits.get(firstpart), []]) # END blame data initialization else: @@ -947,20 +962,12 @@ class Repo(object): # committer-time 1192271832 # committer-tz -0700 - IGNORED BY US role = m.group(0) - if role == 'author': - if firstpart.endswith('-mail'): - info["author_email"] = parts[-1] - elif firstpart.endswith('-time'): - info["author_date"] = int(parts[-1]) - elif role == firstpart: - info["author"] = parts[-1] - elif role == 'committer': - if firstpart.endswith('-mail'): - info["committer_email"] = parts[-1] - elif firstpart.endswith('-time'): - info["committer_date"] = int(parts[-1]) - elif role == firstpart: - info["committer"] = parts[-1] + if firstpart.endswith('-mail'): + info[f"{role}_email"] = parts[-1] + elif firstpart.endswith('-time'): + info[f"{role}_date"] = int(parts[-1]) + elif role == firstpart: + info[role] = parts[-1] # END distinguish mail,time,name else: # handle @@ -973,33 +980,33 @@ class Repo(object): info['summary'] = parts[-1] elif firstpart == '': if info: - sha = info['id'] + sha = info.id c = commits.get(sha) if c is None: c = Commit(self, hex_to_bin(sha), - author=Actor._from_string(info['author'] + ' ' + info['author_email']), - authored_date=info['author_date'], + author=Actor._from_string(info.author + ' ' + info.author_email), + authored_date=info.author_date, committer=Actor._from_string( - info['committer'] + ' ' + info['committer_email']), - committed_date=info['committer_date']) + info.committer + ' ' + info.committer_email), + committed_date=info.committer_date) commits[sha] = c blames[-1][0] = c # END if commit objects needs initial creation - if blames[-1][1] is not None: if not is_binary: if line_str and line_str[0] == '\t': line_str = line_str[1:] + blames[-1][1].append(line_str) else: - blames[-1][1].append(line_bytes) # NOTE: We are actually parsing lines out of binary data, which can lead to the # binary being split up along the newline separator. We will append this to the # blame we are currently looking at, even though it should be concatenated with # the last line we have seen. - info = {'id': sha} + blames[-1][1].append(line_bytes) # end handle line contents + info.id = sha # END if we collected commit info # END distinguish filename,summary,rest # END distinguish author|committer vs filename,summary,rest -- cgit v1.2.1 From ad417ba77c98a39c2d5b3b3a74eb0a1ca17f0ccc Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 22:54:31 +0100 Subject: Test Dataclass in repo.base.blame() 6 --- git/repo/base.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index a0aee322..54409b6a 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -42,10 +42,10 @@ import gitdb from git.types import TBD, PathLike, Lit_config_levels, Commit_ish, Tree_ish, assert_never from typing import (Any, BinaryIO, Callable, Dict, Iterator, List, Mapping, Optional, Sequence, - TextIO, Tuple, Type, TypedDict, Union, + TextIO, Tuple, Type, Union, NamedTuple, cast, TYPE_CHECKING) -from git.types import ConfigLevels_Tup +from git.types import ConfigLevels_Tup, TypedDict if TYPE_CHECKING: from git.util import IterableList @@ -984,11 +984,10 @@ class Repo(object): c = commits.get(sha) if c is None: c = Commit(self, hex_to_bin(sha), - author=Actor._from_string(info.author + ' ' + info.author_email), + author=Actor._from_string(f"{info.author} {info.author_email}"), authored_date=info.author_date, - committer=Actor._from_string( - info.committer + ' ' + info.committer_email), - committed_date=info.committer_date) + committer=Actor._from_string(f"{info.committer} {info.committer_email}"), + committed_date=info.committer_date) commits[sha] = c blames[-1][0] = c # END if commit objects needs initial creation -- cgit v1.2.1 From ecb1f79cdb5198a10e099c2b7cd27aff69105ea9 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 23:04:43 +0100 Subject: Choose TypedDict! --- git/repo/base.py | 69 ++++++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 37 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 54409b6a..e06e4eac 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -7,7 +7,6 @@ from __future__ import annotations import logging import os import re -from dataclasses import dataclass import shlex import warnings from gitdb.db.loose import LooseObjectDB @@ -890,7 +889,7 @@ class Repo(object): commits: Dict[str, Commit] = {} blames: List[List[Commit | List[str | bytes] | None]] = [] - class InfoTC(TypedDict, total=False): + class InfoTD(TypedDict, total=False): sha: str id: str filename: str @@ -902,21 +901,7 @@ class Repo(object): committer_email: str committer_date: int - @dataclass - class InfoDC(Dict[str, Union[str, int]]): - sha: str = '' - id: str = '' - filename: str = '' - summary: str = '' - author: str = '' - author_email: str = '' - author_date: int = 0 - committer: str = '' - committer_email: str = '' - committer_date: int = 0 - - # info: InfoTD = {} - info = InfoDC() + info: InfoTD = {} keepends = True for line_bytes in data.splitlines(keepends): @@ -924,7 +909,7 @@ class Repo(object): line_str = line_bytes.rstrip().decode(defenc) except UnicodeDecodeError: firstpart = '' - parts = [''] + parts = [] is_binary = True else: # As we don't have an idea when the binary data ends, as it could contain multiple newlines @@ -943,10 +928,10 @@ class Repo(object): # another line of blame with the same data digits = parts[-1].split(" ") if len(digits) == 3: - info.id = firstpart + info = {'id': firstpart} blames.append([None, []]) - elif info.id != firstpart: - info.id = firstpart + elif info['id'] != firstpart: + info = {'id': firstpart} blames.append([commits.get(firstpart), []]) # END blame data initialization else: @@ -962,12 +947,20 @@ class Repo(object): # committer-time 1192271832 # committer-tz -0700 - IGNORED BY US role = m.group(0) - if firstpart.endswith('-mail'): - info[f"{role}_email"] = parts[-1] - elif firstpart.endswith('-time'): - info[f"{role}_date"] = int(parts[-1]) - elif role == firstpart: - info[role] = parts[-1] + if role == 'author': + if firstpart.endswith('-mail'): + info["author_email"] = parts[-1] + elif firstpart.endswith('-time'): + info["author_date"] = int(parts[-1]) + elif role == firstpart: + info["author"] = parts[-1] + elif role == 'committer': + if firstpart.endswith('-mail'): + info["committer_email"] = parts[-1] + elif firstpart.endswith('-time'): + info["committer_date"] = int(parts[-1]) + elif role == firstpart: + info["committer"] = parts[-1] # END distinguish mail,time,name else: # handle @@ -980,32 +973,34 @@ class Repo(object): info['summary'] = parts[-1] elif firstpart == '': if info: - sha = info.id + sha = info['id'] c = commits.get(sha) if c is None: c = Commit(self, hex_to_bin(sha), - author=Actor._from_string(f"{info.author} {info.author_email}"), - authored_date=info.author_date, - committer=Actor._from_string(f"{info.committer} {info.committer_email}"), - committed_date=info.committer_date) + author=Actor._from_string(f"{info['author']} {info['author_email']}"), + authored_date=info['author_date'], + committer=Actor._from_string( + f"{info['committer']} {info['committer_email']}"), + committed_date=info['committer_date']) commits[sha] = c blames[-1][0] = c # END if commit objects needs initial creation + if blames[-1][1] is not None: + line: str | bytes if not is_binary: if line_str and line_str[0] == '\t': line_str = line_str[1:] - - blames[-1][1].append(line_str) + line = line_str else: + line = line_bytes # NOTE: We are actually parsing lines out of binary data, which can lead to the # binary being split up along the newline separator. We will append this to the # blame we are currently looking at, even though it should be concatenated with # the last line we have seen. - blames[-1][1].append(line_bytes) - # end handle line contents + blames[-1][1].append(line) - info.id = sha + info = {'id': sha} # END if we collected commit info # END distinguish filename,summary,rest # END distinguish author|committer vs filename,summary,rest -- cgit v1.2.1 From 5aa8c3401a860974db0126dc030e74bbddf217eb Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 23:22:04 +0100 Subject: Improve type of repo.blame_incremental() --- git/repo/base.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index e06e4eac..344e8a71 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -811,8 +811,8 @@ class Repo(object): should get a continuous range spanning all line numbers in the file. """ - data = self.git.blame(rev, '--', file, p=True, incremental=True, stdout_as_string=False, **kwargs) - commits: Dict[str, Commit] = {} + data: bytes = self.git.blame(rev, '--', file, p=True, incremental=True, stdout_as_string=False, **kwargs) + commits: Dict[bytes, Commit] = {} stream = (line for line in data.split(b'\n') if line) while True: @@ -820,15 +820,15 @@ class Repo(object): line = next(stream) # when exhausted, causes a StopIteration, terminating this function except StopIteration: return - split_line: Tuple[str, str, str, str] = line.split() - hexsha, orig_lineno_str, lineno_str, num_lines_str = split_line - lineno = int(lineno_str) - num_lines = int(num_lines_str) - orig_lineno = int(orig_lineno_str) + split_line = line.split() + hexsha, orig_lineno_b, lineno_b, num_lines_b = split_line + lineno = int(lineno_b) + num_lines = int(num_lines_b) + orig_lineno = int(orig_lineno_b) if hexsha not in commits: # Now read the next few lines and build up a dict of properties # for this commit - props = {} + props: Dict[bytes, bytes] = {} while True: try: line = next(stream) @@ -1126,7 +1126,7 @@ class Repo(object): @ classmethod def clone_from(cls, url: PathLike, to_path: PathLike, progress: Optional[Callable] = None, - env: Optional[Mapping[str, Any]] = None, + env: Optional[Mapping[str, str]] = None, multi_options: Optional[List[str]] = None, **kwargs: Any) -> 'Repo': """Create a clone from the given URL -- cgit v1.2.1 From 8b8aa16ee247c6ce403db7178d6c0f9c4ccd529c Mon Sep 17 00:00:00 2001 From: Yobmod Date: Mon, 2 Aug 2021 23:30:27 +0100 Subject: Improve type of repo.currently_rebasing_on() --- git/repo/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 344e8a71..c0229a84 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -1148,7 +1148,7 @@ class Repo(object): return cls._clone(git, url, to_path, GitCmdObjectDB, progress, multi_options, **kwargs) def archive(self, ostream: Union[TextIO, BinaryIO], treeish: Optional[str] = None, - prefix: Optional[str] = None, **kwargs: Any) -> 'Repo': + prefix: Optional[str] = None, **kwargs: Any) -> Repo: """Archive the tree at the given revision. :param ostream: file compatible stream object to which the archive will be written as bytes @@ -1195,7 +1195,7 @@ class Repo(object): clazz = self.__class__ return '<%s.%s %r>' % (clazz.__module__, clazz.__name__, self.git_dir) - def currently_rebasing_on(self) -> Union['SymbolicReference', Commit_ish, None]: + def currently_rebasing_on(self) -> Commit | None: """ :return: The commit which is currently being replayed while rebasing. -- cgit v1.2.1