summaryrefslogtreecommitdiff
path: root/git
diff options
context:
space:
mode:
authorDominic <yobmod@gmail.com>2021-09-09 19:49:13 +0100
committerGitHub <noreply@github.com>2021-09-09 19:49:13 +0100
commitcfcae1d839c5dbb94745c504993c9d5baebc44b5 (patch)
tree2227e4e6931ad38e1a3c5a2c48cecbf5d57e5f01 /git
parent5da76e8b4466459a3b6a400c4750a622879acce8 (diff)
parentbb9b50ff2671cda598ff19653d3de49e03b6d163 (diff)
downloadgitpython-cfcae1d839c5dbb94745c504993c9d5baebc44b5.tar.gz
Merge pull request #1318 from Yobmod/main
General fixes for next release
Diffstat (limited to 'git')
-rw-r--r--git/cmd.py42
-rw-r--r--git/config.py11
-rw-r--r--git/objects/commit.py2
-rw-r--r--git/objects/util.py13
-rw-r--r--git/remote.py4
5 files changed, 43 insertions, 29 deletions
diff --git a/git/cmd.py b/git/cmd.py
index 7de5b9e1..642ef9ed 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -3,7 +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
from contextlib import contextmanager
import io
import logging
@@ -68,7 +68,7 @@ __all__ = ('Git',)
# Documentation
## @{
-def handle_process_output(process: Union[subprocess.Popen, 'Git.AutoInterrupt'],
+def handle_process_output(process: 'Git.AutoInterrupt' | Popen,
stdout_handler: Union[None,
Callable[[AnyStr], None],
Callable[[List[AnyStr]], None],
@@ -78,7 +78,8 @@ def handle_process_output(process: Union[subprocess.Popen, 'Git.AutoInterrupt'],
Callable[[List[AnyStr]], None]],
finalizer: Union[None,
Callable[[Union[subprocess.Popen, 'Git.AutoInterrupt']], None]] = None,
- decode_streams: bool = True) -> None:
+ decode_streams: bool = True,
+ timeout: float = 10.0) -> None:
"""Registers for notifications to learn that process output is ready to read, and dispatches lines to
the respective line handlers.
This function returns once the finalizer returns
@@ -93,9 +94,10 @@ def handle_process_output(process: Union[subprocess.Popen, 'Git.AutoInterrupt'],
their contents to handlers.
Set it to False if `universal_newline == True` (then streams are in text-mode)
or if decoding must happen later (i.e. for Diffs).
+ :param timeout: float, timeout to pass to t.join() in case it hangs. Default = 10.0 seconds
"""
# Use 2 "pump" threads and wait for both to finish.
- def pump_stream(cmdline: str, name: str, stream: Union[BinaryIO, TextIO], is_decode: bool,
+ def pump_stream(cmdline: List[str], name: str, stream: Union[BinaryIO, TextIO], is_decode: bool,
handler: Union[None, Callable[[Union[bytes, str]], None]]) -> None:
try:
for line in stream:
@@ -107,22 +109,32 @@ def handle_process_output(process: Union[subprocess.Popen, 'Git.AutoInterrupt'],
else:
handler(line)
except Exception as ex:
- log.error("Pumping %r of cmd(%s) failed due to: %r", name, remove_password_if_present(cmdline), ex)
- raise CommandError(['<%s-pump>' % name] + remove_password_if_present(cmdline), ex) from ex
+ log.error(f"Pumping {name!r} of cmd({remove_password_if_present(cmdline)}) failed due to: {ex!r}")
+ raise CommandError([f'<{name}-pump>'] + remove_password_if_present(cmdline), ex) from ex
finally:
stream.close()
- cmdline = getattr(process, 'args', '') # PY3+ only
+ if hasattr(process, 'proc'):
+ process = cast('Git.AutoInterrupt', process)
+ cmdline: str | Tuple[str, ...] | List[str] = getattr(process.proc, 'args', '')
+ p_stdout = process.proc.stdout if process.proc else None
+ p_stderr = process.proc.stderr if process.proc else None
+ else:
+ process = cast(Popen, process)
+ cmdline = getattr(process, 'args', '')
+ p_stdout = process.stdout
+ p_stderr = process.stderr
+
if not isinstance(cmdline, (tuple, list)):
cmdline = cmdline.split()
- pumps = []
- if process.stdout:
- pumps.append(('stdout', process.stdout, stdout_handler))
- if process.stderr:
- pumps.append(('stderr', process.stderr, stderr_handler))
+ pumps: List[Tuple[str, IO, Callable[..., None] | None]] = []
+ if p_stdout:
+ pumps.append(('stdout', p_stdout, stdout_handler))
+ if p_stderr:
+ pumps.append(('stderr', p_stderr, stderr_handler))
- threads = []
+ threads: List[threading.Thread] = []
for name, stream, handler in pumps:
t = threading.Thread(target=pump_stream,
@@ -134,7 +146,9 @@ def handle_process_output(process: Union[subprocess.Popen, 'Git.AutoInterrupt'],
## FIXME: Why Join?? Will block if `stdin` needs feeding...
#
for t in threads:
- t.join()
+ t.join(timeout=timeout)
+ if t.is_alive():
+ raise RuntimeError(f"Thread join() timed out in cmd.handle_process_output(). Timeout={timeout} seconds")
if finalizer:
return finalizer(process)
diff --git a/git/config.py b/git/config.py
index cf32d4ba..cbd66022 100644
--- a/git/config.py
+++ b/git/config.py
@@ -31,7 +31,7 @@ import configparser as cp
# typing-------------------------------------------------------
from typing import (Any, Callable, Generic, IO, List, Dict, Sequence,
- TYPE_CHECKING, Tuple, TypeVar, Union, cast, overload)
+ TYPE_CHECKING, Tuple, TypeVar, Union, cast)
from git.types import Lit_config_levels, ConfigLevels_Tup, PathLike, assert_never, _T
@@ -709,15 +709,6 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
""":return: True if this instance may change the configuration file"""
return self._read_only
- @overload
- def get_value(self, section: str, option: str, default: None = None) -> Union[int, float, str, bool]: ...
-
- @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/objects/commit.py b/git/objects/commit.py
index b689167f..b36cd46d 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -446,6 +446,8 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
# assume utf8 encoding
enc_section, enc_option = cls.conf_encoding.split('.')
conf_encoding = cr.get_value(enc_section, enc_option, cls.default_encoding)
+ if not isinstance(conf_encoding, str):
+ raise TypeError("conf_encoding could not be coerced to str")
# if the tree is no object, make sure we create one - otherwise
# the created commit object is invalid
diff --git a/git/objects/util.py b/git/objects/util.py
index 16d4c0ac..187318fe 100644
--- a/git/objects/util.py
+++ b/git/objects/util.py
@@ -5,7 +5,7 @@
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
"""Module for general utility functions"""
-from abc import abstractmethod
+from abc import ABC, abstractmethod
import warnings
from git.util import (
IterableList,
@@ -22,10 +22,10 @@ import calendar
from datetime import datetime, timedelta, tzinfo
# typing ------------------------------------------------------------
-from typing import (Any, Callable, Deque, Iterator, NamedTuple, overload, Sequence,
+from typing import (Any, Callable, Deque, Iterator, Generic, NamedTuple, overload, Sequence, # NOQA: F401
TYPE_CHECKING, Tuple, Type, TypeVar, Union, cast)
-from git.types import Has_id_attribute, Literal, Protocol, runtime_checkable
+from git.types import Has_id_attribute, Literal, _T # NOQA: F401
if TYPE_CHECKING:
from io import BytesIO, StringIO
@@ -35,6 +35,13 @@ if TYPE_CHECKING:
from .tree import Tree, TraversedTreeTup
from subprocess import Popen
from .submodule.base import Submodule
+ from git.types import Protocol, runtime_checkable
+else:
+ # Protocol = Generic[_T] # NNeeded for typing bug #572?
+ Protocol = ABC
+
+ def runtime_checkable(f):
+ return f
class TraverseNT(NamedTuple):
diff --git a/git/remote.py b/git/remote.py
index da08fb57..55772f4a 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -22,12 +22,12 @@ from git.util import (
join_path,
)
-from .config import (
+from git.config import (
GitConfigParser,
SectionConstraint,
cp,
)
-from .refs import (
+from git.refs import (
Head,
Reference,
RemoteReference,