Skip to content

Issue and test deprecation warnings #1886

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 89 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
2382891
Test that deprecated Diff.renamed property warns
EliahKagan Mar 27, 2024
e7dec7d
Have the deprecated Diff.renamed property issue a warning
EliahKagan Mar 27, 2024
a8f109c
Fix exception in Popen.__del__ in test on Windows
EliahKagan Mar 28, 2024
fffa6ce
Test that the preferred renamed_file property does not warn
EliahKagan Mar 28, 2024
bc111b7
Add a TODO for simplifying the single_diff fixture
EliahKagan Mar 28, 2024
e3728c3
Decompose new fixture logic better
EliahKagan Mar 28, 2024
ff4b58d
Extract no-deprecation-warning asserter as a context manager
EliahKagan Mar 28, 2024
2c52696
Test that the deprecated Commit.trailers property warns
EliahKagan Mar 28, 2024
03464d9
Have the deprecated Commit.trailers property issue a warning
EliahKagan Mar 28, 2024
9d096e0
Test that Traversable.{list_,}traverse, but not overrides, warn
EliahKagan Mar 28, 2024
21c2b72
Use the :exc: Sphinx role for DeprecationWarning
EliahKagan Mar 28, 2024
ca385a5
Test that subclassing deprecated git.util.Iterable warns
EliahKagan Mar 28, 2024
8bbcb26
Call repo.close() instead of manually collecting
EliahKagan Mar 28, 2024
b8ce990
Better name and document the basic deprecation test module
EliahKagan Mar 28, 2024
61273aa
Annotate basic deprecation tests; have mypy scan it
EliahKagan Mar 29, 2024
b7a3d8c
Start on top-level module attribute access regression tests
EliahKagan Mar 19, 2024
105f500
Test attribute access and importing separately
EliahKagan Mar 19, 2024
859e38c
Expand to test top-level deprecated names
EliahKagan Mar 21, 2024
46a739d
Hoist `import git` to module level in test module
EliahKagan Mar 21, 2024
a2df3a8
Test static typing of private module aliases
EliahKagan Mar 21, 2024
a15a830
Improve a couple test case docstrings
EliahKagan Mar 21, 2024
dbaa535
Add a couple missing assert keywords
EliahKagan Mar 21, 2024
d00c843
Clarify how test_private_module_aliases is statically checkable
EliahKagan Mar 21, 2024
983fda7
Move mark-sharing tests into a class
EliahKagan Mar 21, 2024
19acd4c
Add FIXME for what to do next
EliahKagan Mar 22, 2024
f39bbb5
Fix a test docstring
EliahKagan Mar 22, 2024
aee7078
Test resolution into git.index.util using git.util
EliahKagan Mar 22, 2024
7f4a191
Fix brittle way of checking warning messages
EliahKagan Mar 22, 2024
d08a576
Clarify todo
EliahKagan Mar 22, 2024
9d58e6d
Start reorganizing new tests more in the GitPython style
EliahKagan Mar 23, 2024
45c128b
Finish reorganizing; fix assertion for duplicated messages
EliahKagan Mar 23, 2024
247dc15
Add imports so pyright recognizes refs and index
EliahKagan Mar 23, 2024
b05963c
Expand and clarify test module docstring
EliahKagan Mar 23, 2024
074bbc7
Tiny import tweak
EliahKagan Mar 23, 2024
18608e4
Pick a better name for _MODULE_ALIAS_TARGETS
EliahKagan Mar 23, 2024
1f290f1
Use typing_extensions only if needed
EliahKagan Mar 23, 2024
7a4f7eb
Fix zip calls
EliahKagan Mar 23, 2024
5977a6e
Fix (and improve wording) of docstrings
EliahKagan Mar 23, 2024
5b1fa58
Remove extra import "from typing_extensions"
EliahKagan Mar 23, 2024
a07be0e
Start on test_compat
EliahKagan Mar 23, 2024
d4917d0
Expand to test all three is_<platform> aliases
EliahKagan Mar 23, 2024
f4e5f42
Slightly improve docstrings
EliahKagan Mar 23, 2024
d54f851
Add test of dir() on git.compat
EliahKagan Mar 23, 2024
aaf046a
Add static type assertions to is_platform test
EliahKagan Mar 23, 2024
84d734d
Refactor test_compat.test_dir for clarity
EliahKagan Mar 23, 2024
3a621b3
Add top-level dir() tests
EliahKagan Mar 23, 2024
05e0878
Remove old comment meant as todo (that was done)
EliahKagan Mar 23, 2024
3fe2f15
Test that top-level aliases point to modules with normal __name__
EliahKagan Mar 23, 2024
246cc17
Use names directly on other tests
EliahKagan Mar 23, 2024
d7b6b31
Fix a small docstring typo
EliahKagan Mar 23, 2024
96089c8
Improve description in test module docstrings
EliahKagan Mar 23, 2024
a0ef537
Start on test_types
EliahKagan Mar 24, 2024
52e7360
Explain substring assertions in test_toplevel
EliahKagan Mar 24, 2024
e3675a0
Expand Lit_commit_ish test name and write docstring
EliahKagan Mar 24, 2024
4857ff0
Clarify test_compat.test_dir
EliahKagan Mar 24, 2024
488cc13
Add test of dir() on git.types
EliahKagan Mar 24, 2024
19b3c08
Clarify comment about is_<platform> value assertions
EliahKagan Mar 24, 2024
28bd4a3
Issue warnings for some deprecated attributes of modules
EliahKagan Mar 20, 2024
dffa930
Refine deprecated module attributes and their warnings
EliahKagan Mar 24, 2024
7ab27c5
Start on test module about Git.USE_SHELL and Git attributes
EliahKagan Mar 24, 2024
af723d5
Make test_use_shell_on_class more robust
EliahKagan Mar 25, 2024
bf13888
Write most remaining Git attribute/deprecation tests
EliahKagan Mar 25, 2024
602de0c
Begin multiprocessing misadventure
EliahKagan Mar 25, 2024
d4b50c9
Somewhat clarify multiprocessing misadventure
EliahKagan Mar 25, 2024
02c2f00
Discuss multiprocessing in test module docstring; remove bad test
EliahKagan Mar 26, 2024
46df79f
Discuss metaclass conflicts in test module docstring
EliahKagan Mar 26, 2024
40ed842
Revise test module docstring for clarity
EliahKagan Mar 26, 2024
6a35261
Test that USE_SHELL is unittest.mock.patch patchable
EliahKagan Mar 27, 2024
e725c82
Make the restore_use_shell_state fixture more robust
EliahKagan Mar 27, 2024
436bcaa
Add `type: ignore` in test that we can't set USE_SHELL on instances
EliahKagan Mar 27, 2024
febda6f
Clarify unittest.mock.patch patchability test docstring
EliahKagan Mar 27, 2024
4037108
Test that Git.execute's own read of USE_SHELL does not warn
EliahKagan Mar 27, 2024
0e311bf
Suppress type errors in restore_use_shell_state _USE_SHELL branches
EliahKagan Mar 27, 2024
df4c5c0
Fix wrong/unclear grammar in test_instance_dir docstring
EliahKagan Mar 28, 2024
d38e721
Issue warnings whenever Git.USE_SHELL is accessed
EliahKagan Mar 27, 2024
05de5c0
Implement instance USE_SHELL lookup in __getattr__
EliahKagan Mar 27, 2024
04eb09c
Have USE_SHELL warn but work like normal via super()
EliahKagan Mar 27, 2024
c6f518b
Keep mypy from thinking Git has arbitrary class attributes
EliahKagan Mar 27, 2024
c5d5b16
Clarify that the private name mangling is intentional
EliahKagan Mar 27, 2024
84bf2ca
Read USE_SHELL in Git.execute without DeprecationWarning
EliahKagan Mar 27, 2024
5bef7ed
Add GitPython project top comments to new test modules
EliahKagan Mar 29, 2024
3da47c2
Hide `del util` from type checkers
EliahKagan Mar 29, 2024
bdabb21
Expand USE_SHELL docstring; clarify a test usage
EliahKagan Mar 29, 2024
b51b080
Explain the approach in test.deprecation to static checking
EliahKagan Mar 29, 2024
7cd3aa9
Make test.performance.lib docstring more specific
EliahKagan Mar 30, 2024
cf2576e
Make/use test.deprecation.lib; abandon idea to filter by module
EliahKagan Mar 30, 2024
f92f4c3
Clarify security risk in USE_SHELL doc and warnings
EliahKagan Mar 31, 2024
8327b45
Test GitMeta alias
EliahKagan Mar 27, 2024
f6060df
Add GitMeta alias
EliahKagan Mar 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Issue warnings for some deprecated attributes of modules
  • Loading branch information
EliahKagan committed Mar 29, 2024
commit 28bd4a3f6e562eadc1018ee7c4d561a3c4352fb5
97 changes: 71 additions & 26 deletions git/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@

__version__ = "git"

from typing import List, Optional, Sequence, TYPE_CHECKING, Tuple, Union
from typing import Any, List, Optional, Sequence, TYPE_CHECKING, Tuple, Union

if TYPE_CHECKING:
from types import ModuleType

from gitdb.util import to_hex_sha

Expand Down Expand Up @@ -144,11 +147,6 @@
SymbolicReference,
Tag,
TagReference,
head, # noqa: F401 # Nonpublic. May disappear! Use git.refs.head.
log, # noqa: F401 # Nonpublic. May disappear! Use git.refs.log.
reference, # noqa: F401 # Nonpublic. May disappear! Use git.refs.reference.
symbolic, # noqa: F401 # Nonpublic. May disappear! Use git.refs.symbolic.
tag, # noqa: F401 # Nonpublic. May disappear! Use git.refs.tag.
)
from git.diff import ( # @NoMove
INDEX,
Expand All @@ -169,21 +167,6 @@
IndexEntry,
IndexFile,
StageType,
base, # noqa: F401 # Nonpublic. May disappear! Use git.index.base.
fun, # noqa: F401 # Nonpublic. May disappear! Use git.index.fun.
typ, # noqa: F401 # Nonpublic. May disappear! Use git.index.typ.
#
# NOTE: The expression `git.util` evaluates to git.index.util, and the import
# `from git import util` imports git.index.util, NOT git.util. It may not be
# feasible to change this until the next major version, to avoid breaking code
# inadvertently relying on it. If git.index.util really is what you want, use or
# import from that name, to avoid confusion. To use the "real" git.util module,
# write `from git.util import ...`, or access it as `sys.modules["git.util"]`.
# (This differs from other historical indirect-submodule imports that are
# unambiguously nonpublic and are subject to immediate removal. Here, the public
# git.util module, even though different, makes it less discoverable that the
# expression `git.util` refers to a non-public attribute of the git module.)
util, # noqa: F401
)
from git.util import ( # @NoMove
Actor,
Expand All @@ -196,7 +179,72 @@
except GitError as _exc:
raise ImportError("%s: %s" % (_exc.__class__.__name__, _exc)) from _exc


# NOTE: The expression `git.util` evaluates to git.index.util and `from git import util`
# imports git.index.util, NOT git.util. It may not be feasible to change this until the
# next major version, to avoid breaking code inadvertently relying on it.
#
# - If git.index.util *is* what you want, use or import from that, to avoid confusion.
#
# - To use the "real" git.util module, write `from git.util import ...`, or if necessary
# access it as `sys.modules["git.util"]`.
#
# (This differs from other indirect-submodule imports that are unambiguously non-public
# and subject to immediate removal. Here, the public git.util module, though different,
# makes less discoverable that the expression `git.util` refers to a non-public
# attribute of the git module.)
#
# This had come about by a wildcard import. Now that all intended imports are explicit,
# the intuitive but potentially incompatible binding occurs due to the usual rules for
# Python submodule bindings. So for now we delete that and let __getattr__ handle it.
#
del util # type: ignore[name-defined] # noqa: F821


def _warned_import(message: str, fullname: str) -> "ModuleType":
import importlib
import warnings

warnings.warn(message, DeprecationWarning, stacklevel=3)
return importlib.import_module(fullname)


def _getattr(name: str) -> Any:
# TODO: If __version__ is made dynamic and lazily fetched, put that case right here.

if name == "util":
return _warned_import(
"The expression `git.util` and the import `from git import util` actually "
"reference git.index.util, and not the git.util module accessed in "
'`from git.util import XYZ` or `sys.modules["git.util"]`. This potentially '
"confusing behavior is currently preserved for compatibility, but may be "
"changed in the future and should not be relied on.",
fullname="git.index.util",
)

for names, prefix in (
({"head", "log", "reference", "symbolic", "tag"}, "git.refs"),
({"base", "fun", "typ"}, "git.index"),
):
if name not in names:
continue

fullname = f"{prefix}.{name}"

return _warned_import(
f"{__name__}.{name} is a private alias of {fullname} and subject to "
f"immediate removal. Use {fullname} instead.",
fullname=fullname,
)

raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


if not TYPE_CHECKING: # Preserve static checking for undefined/misspelled attributes.
__getattr__ = _getattr

# { Initialize git executable path

GIT_OK = None


Expand Down Expand Up @@ -232,12 +280,9 @@ def refresh(path: Optional[PathLike] = None) -> None:
GIT_OK = True


# } END initialize git executable path


#################
try:
refresh()
except Exception as _exc:
raise ImportError("Failed to initialize: {0}".format(_exc)) from _exc
#################

# } END initialize git executable path
40 changes: 37 additions & 3 deletions git/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
AnyStr,
Dict, # noqa: F401
IO, # noqa: F401
List,
Optional,
TYPE_CHECKING,
Tuple, # noqa: F401
Type, # noqa: F401
Union,
Expand All @@ -33,7 +35,39 @@
# ---------------------------------------------------------------------------


is_win = os.name == "nt"
_deprecated_platform_aliases = {
"is_win": os.name == "nt",
"is_posix": os.name == "posix",
"is_darwin": sys.platform == "darwin",
}


def _getattr(name: str) -> Any:
try:
value = _deprecated_platform_aliases[name]
except KeyError:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None

import warnings

warnings.warn(
f"{__name__}.{name} and other is_<platform> aliases are deprecated. "
"Write the desired os.name or sys.platform check explicitly instead.",
DeprecationWarning,
stacklevel=2,
)
return value


if not TYPE_CHECKING: # Preserve static checking for undefined/misspelled attributes.
__getattr__ = _getattr


def __dir__() -> List[str]:
return [*globals(), *_deprecated_platform_aliases]


is_win: bool
"""Deprecated alias for ``os.name == "nt"`` to check for native Windows.

This is deprecated because it is clearer to write out :attr:`os.name` or
Expand All @@ -45,7 +79,7 @@
Cygwin, use ``sys.platform == "cygwin"``.
"""

is_posix = os.name == "posix"
is_posix: bool
"""Deprecated alias for ``os.name == "posix"`` to check for Unix-like ("POSIX") systems.

This is deprecated because it clearer to write out :attr:`os.name` or
Expand All @@ -58,7 +92,7 @@
(Darwin).
"""

is_darwin = sys.platform == "darwin"
is_darwin: bool
"""Deprecated alias for ``sys.platform == "darwin"`` to check for macOS (Darwin).

This is deprecated because it clearer to write out :attr:`os.name` or
Expand Down
39 changes: 30 additions & 9 deletions git/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
Any,
Callable,
Dict,
List,
NoReturn,
Optional,
Sequence as Sequence,
Tuple,
TYPE_CHECKING,
Type,
TypeVar,
Union,
)
Expand Down Expand Up @@ -127,21 +129,40 @@
https://git-scm.com/docs/gitglossary#def_object_type
"""

Lit_commit_ish = Literal["commit", "tag"]
"""Deprecated. Type of literal strings identifying sometimes-commitish git object types.
Lit_commit_ish: Type[Literal["commit", "tag"]]
"""Deprecated. Type of literal strings identifying typically-commitish git object types.

Prior to a bugfix, this type had been defined more broadly. Any usage is in practice
ambiguous and likely to be incorrect. Instead of this type:
ambiguous and likely to be incorrect. This type has therefore been made a static type
error to appear in annotations. It is preserved, with a deprecated status, to avoid
introducing runtime errors in code that refers to it, but it should not be used.

Instead of this type:

* For the type of the string literals associated with :class:`Commit_ish`, use
``Literal["commit", "tag"]`` or create a new type alias for it. That is equivalent to
this type as currently defined.
this type as currently defined (but usable in statically checked type annotations).

* For the type of all four string literals associated with :class:`AnyGitObject`, use
:class:`GitObjectTypeString`. That is equivalent to the old definition of this type
prior to the bugfix.
prior to the bugfix (and is also usable in statically checked type annotations).
"""


def _getattr(name: str) -> Any:
if name == "Lit_commit_ish":
return Literal["commit", "tag"]
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


if not TYPE_CHECKING: # Preserve static checking for undefined/misspelled attributes.
__getattr__ = _getattr


def __dir__() -> List[str]:
return [*globals(), "Lit_commit_ish"]


# Config_levels ---------------------------------------------------------

Lit_config_levels = Literal["system", "global", "user", "repository"]
Expand Down Expand Up @@ -188,12 +209,12 @@ def assert_never(inp: NoReturn, raise_error: bool = True, exc: Union[Exception,

:param inp:
If all members are handled, the argument for `inp` will have the
:class:`~typing.Never`/:class:`~typing.NoReturn` type. Otherwise, the type will
mismatch and cause a mypy error.
:class:`~typing.Never`/:class:`~typing.NoReturn` type.
Otherwise, the type will mismatch and cause a mypy error.

:param raise_error:
If ``True``, will also raise :exc:`ValueError` with a general "unhandled
literal" message, or the exception object passed as `exc`.
If ``True``, will also raise :exc:`ValueError` with a general
"unhandled literal" message, or the exception object passed as `exc`.

:param exc:
It not ``None``, this should be an already-constructed exception object, to be
Expand Down