Skip to content

Commit 9d58e6d

Browse files
committed
Start reorganizing new tests more in the GitPython style
1 parent d08a576 commit 9d58e6d

File tree

1 file changed

+77
-65
lines changed

1 file changed

+77
-65
lines changed

test/deprecation/test_attributes.py

+77-65
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
"""Tests for dynamic and static attribute errors."""
1+
"""Tests for dynamic and static attribute errors in GitPython's top-level git module.
2+
3+
Provided mypy has ``warn_unused_ignores = true`` set, running mypy on these test cases
4+
checks static typing of the code under test. (Running pytest checks dynamic behavior.)
5+
"""
26

37
import importlib
48
from typing import Type
@@ -18,17 +22,6 @@ def test_cannot_import_undefined() -> None:
1822
from git import foo # type: ignore[attr-defined] # noqa: F401
1923

2024

21-
def test_util_alias_access_resolves() -> None:
22-
"""These resolve for now, though they're private and we do not guarantee this."""
23-
assert git.util is git.index.util
24-
25-
26-
def test_util_alias_import_resolves() -> None:
27-
from git import util
28-
29-
assert util is git.index.util
30-
31-
3225
def test_util_alias_members_resolve() -> None:
3326
"""git.index.util members can be accessed via git.util, and mypy recognizes it."""
3427
gu_tfs = git.util.TemporaryFileSwap
@@ -68,59 +61,78 @@ def test_util_alias_import_warns() -> None:
6861
assert "should not be relied on" in message
6962

7063

71-
def test_private_module_aliases_exist_dynamically() -> None:
72-
"""These exist at runtime (for now) but mypy treats them as absent (intentionally).
73-
74-
This code verifies the effect of static type checking when analyzed by mypy, if mypy
75-
is configured with ``warn_unused_ignores = true``.
76-
77-
More detailed dynamic behavior is examined in the subsequent test cases.
78-
"""
79-
git.head # type: ignore[attr-defined]
80-
git.log # type: ignore[attr-defined]
81-
git.reference # type: ignore[attr-defined]
82-
git.symbolic # type: ignore[attr-defined]
83-
git.tag # type: ignore[attr-defined]
84-
git.base # type: ignore[attr-defined]
85-
git.fun # type: ignore[attr-defined]
86-
git.typ # type: ignore[attr-defined]
87-
88-
89-
@pytest.mark.parametrize(
90-
"name, fullname",
91-
[
92-
("head", "git.refs.head"),
93-
("log", "git.refs.log"),
94-
("reference", "git.refs.reference"),
95-
("symbolic", "git.refs.symbolic"),
96-
("tag", "git.refs.tag"),
97-
("base", "git.index.base"),
98-
("fun", "git.index.fun"),
99-
("typ", "git.index.typ"),
100-
],
64+
# Split out util and have all its tests be separate, above.
65+
_MODULE_ALIAS_TARGETS = (
66+
git.refs.head,
67+
git.refs.log,
68+
git.refs.reference,
69+
git.refs.symbolic,
70+
git.refs.tag,
71+
git.index.base,
72+
git.index.fun,
73+
git.index.typ,
74+
git.index.util,
10175
)
102-
class TestPrivateModuleAliases:
103-
"""Tests of the private module aliases' shared specific runtime behaviors."""
10476

105-
def test_private_module_alias_access_resolves(self, name: str, fullname: str) -> None:
106-
"""These resolve for now, though they're private and we do not guarantee this."""
107-
assert getattr(git, name) is importlib.import_module(fullname)
10877

109-
def test_private_module_alias_import_resolves(self, name: str, fullname: str) -> None:
110-
exec(f"from git import {name}")
111-
assert locals()[name] is importlib.import_module(fullname)
112-
113-
def test_private_module_alias_access_warns(self, name: str, fullname: str) -> None:
114-
with pytest.deprecated_call() as ctx:
115-
getattr(git, name)
116-
117-
assert len(ctx) == 1
118-
message = str(ctx[0].message)
119-
assert message.endswith(f"Use {fullname} instead.")
120-
121-
def test_private_module_alias_import_warns(self, name: str, fullname: str) -> None:
122-
with pytest.deprecated_call() as ctx:
123-
exec(f"from git import {name}")
124-
125-
message = str(ctx[0].message)
126-
assert message.endswith(f"Use {fullname} instead.")
78+
def test_private_module_alias_access_on_git_module() -> None:
79+
"""Private alias access works, warns, and except for util is a mypy error."""
80+
with pytest.deprecated_call() as ctx:
81+
assert (
82+
git.head, # type: ignore[attr-defined]
83+
git.log, # type: ignore[attr-defined]
84+
git.reference, # type: ignore[attr-defined]
85+
git.symbolic, # type: ignore[attr-defined]
86+
git.tag, # type: ignore[attr-defined]
87+
git.base, # type: ignore[attr-defined]
88+
git.fun, # type: ignore[attr-defined]
89+
git.typ, # type: ignore[attr-defined]
90+
git.util,
91+
) == _MODULE_ALIAS_TARGETS
92+
93+
messages = [str(w.message) for w in ctx]
94+
for target, message in zip(_MODULE_ALIAS_TARGETS[:-1], messages[:-1], strict=True):
95+
assert message.endswith(f"Use {target.__name__} instead.")
96+
97+
util_message = messages[-1]
98+
assert "git.util" in util_message
99+
assert "git.index.util" in util_message
100+
assert "should not be relied on" in util_message
101+
102+
103+
def test_private_module_alias_import_from_git_module() -> None:
104+
"""Private alias import works, warns, and except for util is a mypy error."""
105+
with pytest.deprecated_call() as ctx:
106+
from git import head # type: ignore[attr-defined]
107+
from git import log # type: ignore[attr-defined]
108+
from git import reference # type: ignore[attr-defined]
109+
from git import symbolic # type: ignore[attr-defined]
110+
from git import tag # type: ignore[attr-defined]
111+
from git import base # type: ignore[attr-defined]
112+
from git import fun # type: ignore[attr-defined]
113+
from git import typ # type: ignore[attr-defined]
114+
from git import util
115+
116+
assert (
117+
head,
118+
log,
119+
reference,
120+
symbolic,
121+
tag,
122+
base,
123+
fun,
124+
typ,
125+
util,
126+
) == _MODULE_ALIAS_TARGETS
127+
128+
# FIXME: This fails because, with imports, multiple consecutive accesses may occur.
129+
# In practice, with CPython, it is always exactly two accesses, the first from the
130+
# equivalent of a hasattr, and the second to fetch the attribute intentionally.
131+
messages = [str(w.message) for w in ctx]
132+
for target, message in zip(_MODULE_ALIAS_TARGETS[:-1], messages[:-1], strict=True):
133+
assert message.endswith(f"Use {target.__name__} instead.")
134+
135+
util_message = messages[-1]
136+
assert "git.util" in util_message
137+
assert "git.index.util" in util_message
138+
assert "should not be relied on" in util_message

0 commit comments

Comments
 (0)