Skip to content

Commit 597e1a6

Browse files
authored
Merge pull request #1787 from EliahKagan/deprecation
Deprecate Git.USE_SHELL
2 parents 86d0177 + 3af3d43 commit 597e1a6

File tree

6 files changed

+114
-70
lines changed

6 files changed

+114
-70
lines changed

git/cmd.py

+15-7
Original file line numberDiff line numberDiff line change
@@ -280,20 +280,20 @@ def __setstate__(self, d: Dict[str, Any]) -> None:
280280
"""Enables debugging of GitPython's git commands."""
281281

282282
USE_SHELL = False
283-
"""If True, a shell will be used when executing git commands.
283+
"""Deprecated. If set to True, a shell will be used when executing git commands.
284284
285-
This exists to avoid breaking old code that may access it, but it is no longer
286-
needed and should rarely if ever be used. Prior to GitPython 2.0.8, it had a narrow
287-
purpose in suppressing console windows in graphical Windows applications. In 2.0.8
288-
and higher, it provides no benefit, as GitPython solves that problem more robustly
289-
and safely by using the ``CREATE_NO_WINDOW`` process creation flag on Windows.
285+
Prior to GitPython 2.0.8, this had a narrow purpose in suppressing console windows
286+
in graphical Windows applications. In 2.0.8 and higher, it provides no benefit, as
287+
GitPython solves that problem more robustly and safely by using the
288+
``CREATE_NO_WINDOW`` process creation flag on Windows.
290289
291290
Code that uses ``USE_SHELL = True`` or that passes ``shell=True`` to any GitPython
292291
functions should be updated to use the default value of ``False`` instead. ``True``
293292
is unsafe unless the effect of shell expansions is fully considered and accounted
294293
for, which is not possible under most circumstances.
295294
296295
See:
296+
- :meth:`Git.execute` (on the ``shell`` parameter).
297297
- https://github.com/gitpython-developers/GitPython/commit/0d9390866f9ce42870d3116094cd49e0019a970a
298298
- https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
299299
"""
@@ -919,7 +919,15 @@ def execute(
919919
920920
:param shell:
921921
Whether to invoke commands through a shell (see `Popen(..., shell=True)`).
922-
It overrides :attr:`USE_SHELL` if it is not `None`.
922+
If this is not `None`, it overrides :attr:`USE_SHELL`.
923+
924+
Passing ``shell=True`` to this or any other GitPython function should be
925+
avoided, as it is unsafe under most circumstances. This is because it is
926+
typically not feasible to fully consider and account for the effect of shell
927+
expansions, especially when passing ``shell=True`` to other methods that
928+
forward it to :meth:`Git.execute`. Passing ``shell=True`` is also no longer
929+
needed (nor useful) to work around any known operating system specific
930+
issues.
923931
924932
:param env:
925933
A dictionary of environment variables to be passed to :class:`subprocess.Popen`.

git/compat.py

+30-7
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,41 @@
2828
# ---------------------------------------------------------------------------
2929

3030

31-
# DEPRECATED attributes providing shortcuts to operating system checks based on os.name.
32-
#
33-
# These are deprecated because it is clearer, and helps avoid bugs, to write out the
34-
# os.name or sys.platform checks explicitly, especially in cases where it matters which
35-
# is used. For example, is_win is False on Cygwin, but is often assumed True. To detect
36-
# Cygwin, use sys.platform == "cygwin". (Also, in the past, is_darwin was unreliable.)
37-
#
3831
is_win = os.name == "nt"
32+
"""Deprecated alias for ``os.name == "nt"`` to check for native Windows.
33+
34+
This is deprecated because it is clearer to write out :attr:`os.name` or
35+
:attr:`sys.platform` checks explicitly, especially in cases where it matters which is
36+
used.
37+
38+
:note: ``is_win`` is ``False`` on Cygwin, but is often wrongly assumed ``True``. To
39+
detect Cygwin, use ``sys.platform == "cygwin"``.
40+
"""
41+
3942
is_posix = os.name == "posix"
43+
"""Deprecated alias for ``os.name == "posix"`` to check for Unix-like ("POSIX") systems.
44+
45+
This is deprecated because it clearer to write out :attr:`os.name` or
46+
:attr:`sys.platform` checks explicitly, especially in cases where it matters which is
47+
used.
48+
49+
:note: For POSIX systems, more detailed information is available in
50+
:attr:`sys.platform`, while :attr:`os.name` is always ``"posix"`` on such systems,
51+
including macOS (Darwin).
52+
"""
53+
4054
is_darwin = sys.platform == "darwin"
55+
"""Deprecated alias for ``sys.platform == "darwin"`` to check for macOS (Darwin).
56+
57+
This is deprecated because it clearer to write out :attr:`os.name` or
58+
:attr:`sys.platform` checks explicitly.
59+
60+
:note: For macOS (Darwin), ``os.name == "posix"`` as in other Unix-like systems, while
61+
``sys.platform == "darwin"`.
62+
"""
4163

4264
defenc = sys.getfilesystemencoding()
65+
"""The encoding used to convert between Unicode and bytes filenames."""
4366

4467

4568
@overload

git/diff.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
55

66
import re
7+
78
from git.cmd import handle_process_output
89
from git.compat import defenc
910
from git.util import finalize_process, hex_to_bin
@@ -208,13 +209,15 @@ class DiffIndex(List[T_Diff]):
208209
The class improves the diff handling convenience.
209210
"""
210211

211-
# Change type invariant identifying possible ways a blob can have changed:
212-
# A = Added
213-
# D = Deleted
214-
# R = Renamed
215-
# M = Modified
216-
# T = Changed in the type
217212
change_type = ("A", "C", "D", "R", "M", "T")
213+
"""Change type invariant identifying possible ways a blob can have changed:
214+
215+
* ``A`` = Added
216+
* ``D`` = Deleted
217+
* ``R`` = Renamed
218+
* ``M`` = Modified
219+
* ``T`` = Changed in the type
220+
"""
218221

219222
def iter_change_type(self, change_type: Lit_change_type) -> Iterator[T_Diff]:
220223
"""

git/objects/commit.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,8 @@ def stats(self) -> Stats:
352352
def trailers(self) -> Dict[str, str]:
353353
"""Get the trailers of the message as a dictionary
354354
355-
:note: This property is deprecated, please use either ``Commit.trailers_list``
356-
or ``Commit.trailers_dict``.
355+
:note: This property is deprecated, please use either :attr:`trailers_list` or
356+
:attr:`trailers_dict``.
357357
358358
:return:
359359
Dictionary containing whitespace stripped trailer information. Only contains

git/objects/util.py

+54-44
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ class TraverseNT(NamedTuple):
6262
T_TIobj = TypeVar("T_TIobj", bound="TraversableIterableObj") # For TraversableIterableObj.traverse()
6363

6464
TraversedTup = Union[
65-
Tuple[Union["Traversable", None], "Traversable"], # For commit, submodule
66-
"TraversedTreeTup",
67-
] # for tree.traverse()
65+
Tuple[Union["Traversable", None], "Traversable"], # For Commit, Submodule.
66+
"TraversedTreeTup", # For Tree.traverse().
67+
]
6868

6969
# --------------------------------------------------------------------
7070

@@ -380,11 +380,15 @@ class Tree:: (cls, Tree) -> Tuple[Tree, ...]
380380

381381
@abstractmethod
382382
def list_traverse(self, *args: Any, **kwargs: Any) -> Any:
383-
""" """
383+
"""Traverse self and collect all items found.
384+
385+
Calling this directly only the abstract base class, including via a ``super()``
386+
proxy, is deprecated. Only overridden implementations should be called.
387+
"""
384388
warnings.warn(
385389
"list_traverse() method should only be called from subclasses."
386-
"Calling from Traversable abstract class will raise NotImplementedError in 3.1.20"
387-
"Builtin sublclasses are 'Submodule', 'Tree' and 'Commit",
390+
" Calling from Traversable abstract class will raise NotImplementedError in 4.0.0."
391+
" The concrete subclasses in GitPython itself are 'Commit', 'RootModule', 'Submodule', and 'Tree'.",
388392
DeprecationWarning,
389393
stacklevel=2,
390394
)
@@ -393,12 +397,14 @@ def list_traverse(self, *args: Any, **kwargs: Any) -> Any:
393397
def _list_traverse(
394398
self, as_edge: bool = False, *args: Any, **kwargs: Any
395399
) -> IterableList[Union["Commit", "Submodule", "Tree", "Blob"]]:
396-
"""
400+
"""Traverse self and collect all items found.
401+
397402
:return: IterableList with the results of the traversal as produced by
398-
traverse()
399-
Commit -> IterableList['Commit']
400-
Submodule -> IterableList['Submodule']
401-
Tree -> IterableList[Union['Submodule', 'Tree', 'Blob']]
403+
:meth:`traverse`::
404+
405+
Commit -> IterableList['Commit']
406+
Submodule -> IterableList['Submodule']
407+
Tree -> IterableList[Union['Submodule', 'Tree', 'Blob']]
402408
"""
403409
# Commit and Submodule have id.__attribute__ as IterableObj.
404410
# Tree has id.__attribute__ inherited from IndexObject.
@@ -421,11 +427,15 @@ def _list_traverse(
421427

422428
@abstractmethod
423429
def traverse(self, *args: Any, **kwargs: Any) -> Any:
424-
""" """
430+
"""Iterator yielding items found when traversing self.
431+
432+
Calling this directly on the abstract base class, including via a ``super()``
433+
proxy, is deprecated. Only overridden implementations should be called.
434+
"""
425435
warnings.warn(
426436
"traverse() method should only be called from subclasses."
427-
"Calling from Traversable abstract class will raise NotImplementedError in 3.1.20"
428-
"Builtin sublclasses are 'Submodule', 'Tree' and 'Commit",
437+
" Calling from Traversable abstract class will raise NotImplementedError in 4.0.0."
438+
" The concrete subclasses in GitPython itself are 'Commit', 'RootModule', 'Submodule', and 'Tree'.",
429439
DeprecationWarning,
430440
stacklevel=2,
431441
)
@@ -441,7 +451,7 @@ def _traverse(
441451
ignore_self: int = 1,
442452
as_edge: bool = False,
443453
) -> Union[Iterator[Union["Traversable", "Blob"]], Iterator[TraversedTup]]:
444-
""":return: Iterator yielding items found when traversing self
454+
"""Iterator yielding items found when traversing self.
445455
446456
:param predicate: f(i,d) returns False if item i at depth d should not be
447457
included in the result.
@@ -471,18 +481,18 @@ def _traverse(
471481
if True, return a pair of items, first being the source, second the
472482
destination, i.e. tuple(src, dest) with the edge spanning from source to
473483
destination
474-
"""
475484
476-
"""
477-
Commit -> Iterator[Union[Commit, Tuple[Commit, Commit]]
478-
Submodule -> Iterator[Submodule, Tuple[Submodule, Submodule]]
479-
Tree -> Iterator[Union[Blob, Tree, Submodule,
480-
Tuple[Union[Submodule, Tree], Union[Blob, Tree, Submodule]]]
481-
482-
ignore_self=True is_edge=True -> Iterator[item]
483-
ignore_self=True is_edge=False --> Iterator[item]
484-
ignore_self=False is_edge=True -> Iterator[item] | Iterator[Tuple[src, item]]
485-
ignore_self=False is_edge=False -> Iterator[Tuple[src, item]]
485+
:return: Iterator yielding items found when traversing self::
486+
487+
Commit -> Iterator[Union[Commit, Tuple[Commit, Commit]]
488+
Submodule -> Iterator[Submodule, Tuple[Submodule, Submodule]]
489+
Tree -> Iterator[Union[Blob, Tree, Submodule,
490+
Tuple[Union[Submodule, Tree], Union[Blob, Tree, Submodule]]]
491+
492+
ignore_self=True is_edge=True -> Iterator[item]
493+
ignore_self=True is_edge=False --> Iterator[item]
494+
ignore_self=False is_edge=True -> Iterator[item] | Iterator[Tuple[src, item]]
495+
ignore_self=False is_edge=False -> Iterator[Tuple[src, item]]
486496
"""
487497

488498
visited = set()
@@ -547,7 +557,7 @@ class Serializable(Protocol):
547557
def _serialize(self, stream: "BytesIO") -> "Serializable":
548558
"""Serialize the data of this object into the given data stream.
549559
550-
:note: A serialized object would ``_deserialize`` into the same object.
560+
:note: A serialized object would :meth:`_deserialize` into the same object.
551561
552562
:param stream: a file-like object
553563
@@ -627,24 +637,24 @@ def traverse(
627637
ignore_self: int = 1,
628638
as_edge: bool = False,
629639
) -> Union[Iterator[T_TIobj], Iterator[Tuple[T_TIobj, T_TIobj]], Iterator[TIobj_tuple]]:
630-
"""For documentation, see util.Traversable._traverse()"""
640+
"""For documentation, see :meth:`Traversable._traverse`."""
641+
642+
## To typecheck instead of using cast:
643+
#
644+
# import itertools
645+
# from git.types import TypeGuard
646+
# def is_commit_traversed(inp: Tuple) -> TypeGuard[Tuple[Iterator[Tuple['Commit', 'Commit']]]]:
647+
# for x in inp[1]:
648+
# if not isinstance(x, tuple) and len(x) != 2:
649+
# if all(isinstance(inner, Commit) for inner in x):
650+
# continue
651+
# return True
652+
#
653+
# ret = super(Commit, self).traverse(predicate, prune, depth, branch_first, visit_once, ignore_self, as_edge)
654+
# ret_tup = itertools.tee(ret, 2)
655+
# assert is_commit_traversed(ret_tup), f"{[type(x) for x in list(ret_tup[0])]}"
656+
# return ret_tup[0]
631657

632-
"""
633-
# To typecheck instead of using cast.
634-
import itertools
635-
from git.types import TypeGuard
636-
def is_commit_traversed(inp: Tuple) -> TypeGuard[Tuple[Iterator[Tuple['Commit', 'Commit']]]]:
637-
for x in inp[1]:
638-
if not isinstance(x, tuple) and len(x) != 2:
639-
if all(isinstance(inner, Commit) for inner in x):
640-
continue
641-
return True
642-
643-
ret = super(Commit, self).traverse(predicate, prune, depth, branch_first, visit_once, ignore_self, as_edge)
644-
ret_tup = itertools.tee(ret, 2)
645-
assert is_commit_traversed(ret_tup), f"{[type(x) for x in list(ret_tup[0])]}"
646-
return ret_tup[0]
647-
"""
648658
return cast(
649659
Union[Iterator[T_TIobj], Iterator[Tuple[Union[None, T_TIobj], T_TIobj]]],
650660
super()._traverse(predicate, prune, depth, branch_first, visit_once, ignore_self, as_edge), # type: ignore

git/util.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1233,10 +1233,10 @@ def __init__(cls, name: str, bases: Tuple, clsdict: Dict) -> None:
12331233
for base in bases:
12341234
if type(base) is IterableClassWatcher:
12351235
warnings.warn(
1236-
f"GitPython Iterable subclassed by {name}. "
1237-
"Iterable is deprecated due to naming clash since v3.1.18"
1238-
" and will be removed in 3.1.20, "
1239-
"Use IterableObj instead \n",
1236+
f"GitPython Iterable subclassed by {name}."
1237+
" Iterable is deprecated due to naming clash since v3.1.18"
1238+
" and will be removed in 4.0.0."
1239+
" Use IterableObj instead.",
12401240
DeprecationWarning,
12411241
stacklevel=2,
12421242
)

0 commit comments

Comments
 (0)