@@ -160,3 +160,52 @@ def test_private_module_alias_import() -> None:
160160
161161for target ,message in zip (_PRIVATE_MODULE_ALIAS_TARGETS ,messages ):
162162assert message .endswith (f"Use{ target .__name__ } instead." )
163+
164+
165+ def test_dir_contains_public_attributes ()-> None :
166+ """All public attributes of the git module are present when dir() is called on it.
167+
168+ This is naturally the case, but some ways of adding dynamic attribute access
169+ behavior can change it, especially if __dir__ is defined but care is not taken to
170+ preserve the contents that should already be present.
171+
172+ Note that dir() should usually automatically list non-public attributes if they are
173+ actually "physically" present as well, so the approach taken here to test it should
174+ not be reproduced if __dir__ is added (instead, a call to globals() could be used,
175+ as its keys list the automatic values).
176+ """
177+ expected_subset = set (git .__all__ )
178+ actual = set (dir (git ))
179+ assert expected_subset <= actual
180+
181+
182+ def test_dir_does_not_contain_util ()-> None :
183+ """The util attribute is absent from the dir() of git.
184+
185+ Because this behavior is less confusing than including it, where its meaning would
186+ be assumed by users examining the dir() for what is available.
187+ """
188+ assert "util" not in dir (git )
189+
190+
191+ def test_dir_does_not_contain_private_module_aliases ()-> None :
192+ """Names from inside index and refs only pretend to be there and are not in dir().
193+
194+ The reason for omitting these is not that they are private, since private members
195+ are usually included in dir() when actually present. Instead, these are only sort
196+ of even there, no longer being imported and only being resolved dynamically for the
197+ time being. In addition, it would be confusing to list these because doing so would
198+ obscure the module structure of GitPython.
199+ """
200+ expected_absent = {
201+ "head" ,
202+ "log" ,
203+ "reference" ,
204+ "symbolic" ,
205+ "tag" ,
206+ "base" ,
207+ "fun" ,
208+ "typ" ,
209+ }
210+ actual = set (dir (git ))
211+ assert not (expected_absent & actual ),"They should be completely disjoint."