100100
101101
102102def handle_process_output (
103- process : "Git.AutoInterrupt" | Popen ,
103+ process : Union [ "Git.AutoInterrupt" , Popen ] ,
104104 stdout_handler : Union [
105105 None ,
106106 Callable [[AnyStr ], None ],
@@ -395,9 +395,7 @@ def wait(self, stderr: Union[None, str, bytes] = b"") -> int:
395395 :raise git.exc.GitCommandError:
396396 If the return status is not 0.
397397 """
398- if stderr is None :
399- stderr_b = b""
400- stderr_b = force_bytes (data = stderr , encoding = "utf-8" )
398+ stderr_b = force_bytes (data = stderr , encoding = "utf-8" ) or b""
401399 status : Union [int , None ]
402400 if self .proc is not None :
403401 status = self .proc .wait ()
@@ -1180,52 +1178,112 @@ def version_info(self) -> Tuple[int, ...]:
11801178 def execute (
11811179 self ,
11821180 command : Union [str , Sequence [Any ]],
1181+ istream : Union [None , int , BinaryIO ] = None ,
11831182 * ,
11841183 as_process : Literal [True ],
1184+ ** subprocess_kwargs : Any ,
11851185 ) -> "AutoInterrupt" : ...
11861186
11871187 @overload
11881188 def execute (
11891189 self ,
11901190 command : Union [str , Sequence [Any ]],
1191+ istream : Union [None , int , BinaryIO ] = None ,
11911192 * ,
11921193 as_process : Literal [False ] = False ,
1193- stdout_as_string : Literal [True ],
1194- ) -> Union [str , Tuple [int , str , str ]]: ...
1194+ with_extended_output : Literal [False ] = False ,
1195+ stdout_as_string : Literal [True ] = True ,
1196+ with_stdout : Literal [True ] = True ,
1197+ ** subprocess_kwargs : Any ,
1198+ ) -> str : ...
11951199
11961200 @overload
11971201 def execute (
11981202 self ,
11991203 command : Union [str , Sequence [Any ]],
1204+ istream : Union [None , int , BinaryIO ] = None ,
12001205 * ,
12011206 as_process : Literal [False ] = False ,
1202- stdout_as_string : Literal [False ] = False ,
1203- ) -> Union [bytes , Tuple [int , bytes , str ]]: ...
1207+ with_extended_output : Literal [False ] = False ,
1208+ stdout_as_string : Literal [False ],
1209+ universal_newlines : Literal [False ] = False ,
1210+ with_stdout : Literal [True ] = True ,
1211+ ** subprocess_kwargs : Any ,
1212+ ) -> bytes : ...
12041213
12051214 @overload
12061215 def execute (
12071216 self ,
12081217 command : Union [str , Sequence [Any ]],
1218+ istream : Union [None , int , BinaryIO ] = None ,
12091219 * ,
1210- with_extended_output : Literal [False ],
1211- as_process : Literal [False ],
1212- stdout_as_string : Literal [True ],
1213- ) -> str : ...
1220+ as_process : Literal [False ] = False ,
1221+ with_extended_output : Literal [True ],
1222+ stdout_as_string : Literal [True ] = True ,
1223+ with_stdout : Literal [True ] = True ,
1224+ ** subprocess_kwargs : Any ,
1225+ ) -> Tuple [int , str , str ]: ...
12141226
12151227 @overload
12161228 def execute (
12171229 self ,
12181230 command : Union [str , Sequence [Any ]],
1231+ istream : Union [None , int , BinaryIO ] = None ,
12191232 * ,
1220- with_extended_output : Literal [False ],
1221- as_process : Literal [False ],
1233+ as_process : Literal [False ] = False ,
1234+ with_extended_output : Literal [True ],
12221235 stdout_as_string : Literal [False ],
1223- ) -> bytes : ...
1236+ universal_newlines : Literal [False ] = False ,
1237+ with_stdout : Literal [True ] = True ,
1238+ ** subprocess_kwargs : Any ,
1239+ ) -> Tuple [int , bytes , str ]: ...
1240+
1241+ @overload
1242+ def execute (
1243+ self ,
1244+ command : Union [str , Sequence [Any ]],
1245+ istream : Union [None , int , BinaryIO ] = None ,
1246+ * ,
1247+ as_process : Literal [False ] = False ,
1248+ with_extended_output : Literal [True ],
1249+ ** subprocess_kwargs : Any ,
1250+ ) -> Tuple [int , Union [str , bytes , None ], str ]: ...
1251+
1252+ @overload
1253+ def execute (
1254+ self ,
1255+ command : Union [str , Sequence [Any ]],
1256+ istream : Union [None , int , BinaryIO ] = None ,
1257+ * ,
1258+ as_process : Literal [False ] = False ,
1259+ with_extended_output : Literal [False ] = False ,
1260+ ** subprocess_kwargs : Any ,
1261+ ) -> Union [str , bytes , None ]: ...
1262+
1263+ @overload
1264+ def execute (
1265+ self ,
1266+ command : Union [str , Sequence [Any ]],
1267+ istream : Union [None , int , BinaryIO ] = None ,
1268+ with_extended_output : bool = False ,
1269+ with_exceptions : bool = True ,
1270+ as_process : bool = False ,
1271+ output_stream : Union [None , BinaryIO ] = None ,
1272+ stdout_as_string : bool = True ,
1273+ kill_after_timeout : Union [None , float ] = None ,
1274+ with_stdout : bool = True ,
1275+ universal_newlines : bool = False ,
1276+ shell : Union [None , bool ] = None ,
1277+ env : Union [None , Mapping [str , str ]] = None ,
1278+ max_chunk_size : int = io .DEFAULT_BUFFER_SIZE ,
1279+ strip_newline_in_stdout : bool = True ,
1280+ ** subprocess_kwargs : Any ,
1281+ ) -> Union [None , str , bytes , Tuple [int , Union [str , bytes , None ], str ], AutoInterrupt ]: ...
12241282
12251283 def execute (
12261284 self ,
12271285 command : Union [str , Sequence [Any ]],
1228- istream : Union [None , BinaryIO ] = None ,
1286+ istream : Union [None , int , BinaryIO ] = None ,
12291287 with_extended_output : bool = False ,
12301288 with_exceptions : bool = True ,
12311289 as_process : bool = False ,
@@ -1239,7 +1297,7 @@ def execute(
12391297 max_chunk_size : int = io .DEFAULT_BUFFER_SIZE ,
12401298 strip_newline_in_stdout : bool = True ,
12411299 ** subprocess_kwargs : Any ,
1242- ) -> Union [str , bytes , Tuple [int , Union [str , bytes ], str ], AutoInterrupt ]:
1300+ ) -> Union [None , str , bytes , Tuple [int , Union [str , bytes , None ], str ], AutoInterrupt ]:
12431301 R"""Handle executing the command, and consume and return the returned
12441302 information (stdout).
12451303
@@ -1303,9 +1361,9 @@ def execute(
13031361 carefully considered, due to the following limitations:
13041362
13051363 1. This feature is not supported at all on Windows.
1306- 2. Effectiveness may vary by operating system. ``ps --ppid`` is used to
1307- enumerate child processes, which is available on most GNU/Linux systems
1308- but not most others .
1364+ 2. Enumerating child processes requires ``pgrep -P``, or a ``ps`` command
1365+ supporting the POSIX ``-A`` and ``-o`` options if ``pgrep`` is not
1366+ installed. Effectiveness may vary on systems without these commands .
13091367 3. Deeper descendants do not receive signals, though they may sometimes
13101368 terminate as a consequence of their parent processes being killed.
13111369 4. `kill_after_timeout` uses ``SIGKILL``, which can have negative side
@@ -1465,14 +1523,24 @@ def kill_process(pid: int) -> None:
14651523
14661524 This callback implementation would be ineffective and unsafe on Windows.
14671525 """
1468- p = Popen (["ps" , "--ppid" , str (pid )], stdout = PIPE )
14691526 child_pids = []
1470- if p .stdout is not None :
1471- for line in p .stdout :
1472- if len (line .split ()) > 0 :
1473- local_pid = (line .split ())[0 ]
1474- if local_pid .isdigit ():
1475- child_pids .append (int (local_pid ))
1527+ try :
1528+ p = Popen (["pgrep" , "-P" , str (pid )], stdout = PIPE )
1529+ except FileNotFoundError :
1530+ # POSIX ps does not support selecting by parent PID.
1531+ with Popen (["ps" , "-A" , "-o" , "pid=" , "-o" , "ppid=" ], stdout = PIPE ) as p :
1532+ if p .stdout is not None :
1533+ for line in p .stdout :
1534+ fields = line .split ()
1535+ if len (fields ) == 2 and all (field .isdigit () for field in fields ):
1536+ if int (fields [1 ]) == pid :
1537+ child_pids .append (int (fields [0 ]))
1538+ else :
1539+ with p :
1540+ if p .stdout is not None :
1541+ for line in p .stdout :
1542+ if line .strip ().isdigit ():
1543+ child_pids .append (int (line ))
14761544 try :
14771545 os .kill (pid , signal .SIGKILL )
14781546 for child_pid in child_pids :
@@ -1493,7 +1561,7 @@ def make_timeout_error() -> Union[str, bytes]:
14931561 err = f'Timeout: the command "{ " " .join (redacted_command )} " did not complete in { timeout :g} secs.'
14941562 return err if universal_newlines else err .encode (defenc )
14951563
1496- def communicate () -> Tuple [AnyStr , AnyStr ]:
1564+ def communicate () -> Tuple [Union [ str , bytes , None ], Union [ str , bytes , None ] ]:
14971565 assert watchdog is not None
14981566 assert kill_check is not None
14991567 watchdog .start ()
@@ -1513,8 +1581,8 @@ def communicate() -> Tuple[AnyStr, AnyStr]:
15131581
15141582 # Wait for the process to return.
15151583 status = 0
1516- stdout_value : Union [str , bytes ] = b""
1517- stderr_value : Union [str , bytes ] = b""
1584+ stdout_value : Union [str , bytes , None ] = b""
1585+ stderr_value : Union [str , bytes , None ] = b""
15181586 newline = "\n " if universal_newlines else b"\n "
15191587 try :
15201588 if output_stream is None :
@@ -1556,7 +1624,7 @@ def communicate() -> Tuple[AnyStr, AnyStr]:
15561624 if self .GIT_PYTHON_TRACE == "full" :
15571625 cmdstr = " " .join (redacted_command )
15581626
1559- def as_text (stdout_value : Union [bytes , str ]) -> str :
1627+ def as_text (stdout_value : Union [bytes , str , None ]) -> str :
15601628 return not output_stream and safe_decode (stdout_value ) or "<OUTPUT_STREAM>"
15611629
15621630 # END as_text
@@ -1581,6 +1649,8 @@ def as_text(stdout_value: Union[bytes, str]) -> str:
15811649 if isinstance (stdout_value , bytes ) and stdout_as_string : # Could also be output_stream.
15821650 stdout_value = safe_decode (stdout_value )
15831651
1652+ # stderr is always captured through PIPE.
1653+ assert stderr_value is not None
15841654 # Allow access to the command's status code.
15851655 if with_extended_output :
15861656 return (status , stdout_value , safe_decode (stderr_value ))
@@ -1819,7 +1889,7 @@ def _parse_object_header(self, header_line: str) -> Tuple[str, str, int]:
18191889 raise ValueError ("Failed to parse header: %r" % header_line )
18201890 return (tokens [0 ], tokens [1 ], int (tokens [2 ]))
18211891
1822- def _prepare_ref (self , ref : AnyStr ) -> bytes :
1892+ def _prepare_ref (self , ref : object ) -> bytes :
18231893 # Required for command to separate refs on stdin, as bytes.
18241894 if isinstance (ref , bytes ):
18251895 # Assume 40 bytes hexsha - bin-to-ascii for some reason returns bytes, not text.
@@ -1846,15 +1916,15 @@ def _get_persistent_cmd(self, attr_name: str, cmd_name: str, *args: Any, **kwarg
18461916 cmd = cast ("Git.AutoInterrupt" , cmd )
18471917 return cmd
18481918
1849- def __get_object_header (self , cmd : "Git.AutoInterrupt" , ref : AnyStr ) -> Tuple [str , str , int ]:
1919+ def __get_object_header (self , cmd : "Git.AutoInterrupt" , ref : Union [ str , bytes ] ) -> Tuple [str , str , int ]:
18501920 if cmd .stdin and cmd .stdout :
18511921 cmd .stdin .write (self ._prepare_ref (ref ))
18521922 cmd .stdin .flush ()
18531923 return self ._parse_object_header (cmd .stdout .readline ())
18541924 else :
18551925 raise ValueError ("cmd stdin was empty" )
18561926
1857- def get_object_header (self , ref : str ) -> Tuple [str , str , int ]:
1927+ def get_object_header (self , ref : Union [ str , bytes ] ) -> Tuple [str , str , int ]:
18581928 """Use this method to quickly examine the type and size of the object behind the
18591929 given ref.
18601930
@@ -1868,7 +1938,7 @@ def get_object_header(self, ref: str) -> Tuple[str, str, int]:
18681938 cmd = self ._get_persistent_cmd ("cat_file_header" , "cat_file" , batch_check = True )
18691939 return self .__get_object_header (cmd , ref )
18701940
1871- def get_object_data (self , ref : str ) -> Tuple [str , str , int , bytes ]:
1941+ def get_object_data (self , ref : Union [ str , bytes ] ) -> Tuple [str , str , int , bytes ]:
18721942 """Similar to :meth:`get_object_header`, but returns object data as well.
18731943
18741944 :return:
@@ -1882,7 +1952,7 @@ def get_object_data(self, ref: str) -> Tuple[str, str, int, bytes]:
18821952 del stream
18831953 return (hexsha , typename , size , data )
18841954
1885- def stream_object_data (self , ref : str ) -> Tuple [str , str , int , "Git.CatFileContentStream" ]:
1955+ def stream_object_data (self , ref : Union [ str , bytes ] ) -> Tuple [str , str , int , "Git.CatFileContentStream" ]:
18861956 """Similar to :meth:`get_object_data`, but returns the data as a stream.
18871957
18881958 :return:
0 commit comments