|
16 | 16 | import annotationlib |
17 | 17 |
|
18 | 18 | import pytest |
| 19 | +from conftest import make_docstring_app |
19 | 20 |
|
| 21 | +from sphinx_autodoc_typehints import process_docstring |
20 | 22 | from sphinx_autodoc_typehints._annotations import MyTypeAliasForwardRef |
21 | 23 | from sphinx_autodoc_typehints._resolver._type_hints import ( |
22 | 24 | _TYPE_GUARD_IMPORTS_RESOLVED, |
|
29 | 31 | _run_guarded_import, |
30 | 32 | _should_skip_guarded_import_resolution, |
31 | 33 | get_all_type_hints, |
| 34 | + get_descriptor_type_hint, |
32 | 35 | ) |
33 | 36 |
|
34 | 37 | STUB_ROOT = Path(__file__).parent.parent / "roots" / "test-pyi-stubs" |
@@ -216,6 +219,56 @@ def test_get_all_type_hints_preserves_stub_type_aliases(c_ext_mod: Any) -> None: |
216 | 219 | assert result["callback"].name == "GreetHook" |
217 | 220 |
|
218 | 221 |
|
| 222 | +def test_descriptor_type_hint_resolves_from_stub(c_ext_mod: Any) -> None: |
| 223 | + assert get_descriptor_type_hint(c_ext_mod.Encoder.depth) is int |
| 224 | + |
| 225 | + |
| 226 | +def test_descriptor_type_hint_preserves_stub_type_aliases(c_ext_mod: Any) -> None: |
| 227 | + hint = get_descriptor_type_hint(c_ext_mod.Encoder.hook) |
| 228 | + args = get_args(hint) |
| 229 | + assert len(args) == 2 |
| 230 | + encoder_hook = args[0] if isinstance(args[0], MyTypeAliasForwardRef) else args[1] |
| 231 | + assert encoder_hook.name == "EncoderHook" |
| 232 | + |
| 233 | + |
| 234 | +def test_descriptor_type_hint_resolves_class_annotation(c_ext_mod: Any) -> None: |
| 235 | + assert get_descriptor_type_hint(c_ext_mod.Encoder.flags) is int |
| 236 | + |
| 237 | + |
| 238 | +def test_descriptor_type_hint_inside_version_guard(c_ext_mod: Any) -> None: |
| 239 | + assert get_descriptor_type_hint(c_ext_mod.Encoder.guarded) is bool |
| 240 | + |
| 241 | + |
| 242 | +def test_descriptor_type_hint_for_non_class_stub_node(c_ext_mod: Any) -> None: |
| 243 | + fake_class = type("greet", (), {"__module__": c_ext_mod.__name__, "__qualname__": "greet"}) |
| 244 | + descriptor = types.SimpleNamespace(__objclass__=fake_class, __name__="depth") |
| 245 | + assert get_descriptor_type_hint(descriptor) is None |
| 246 | + |
| 247 | + |
| 248 | +def test_descriptor_type_hint_for_name_missing_from_stub(c_ext_mod: Any) -> None: |
| 249 | + descriptor = types.SimpleNamespace(__objclass__=c_ext_mod.Encoder, __name__="missing") |
| 250 | + assert get_descriptor_type_hint(descriptor) is None |
| 251 | + |
| 252 | + |
| 253 | +def test_process_docstring_injects_descriptor_type(c_ext_mod: Any) -> None: |
| 254 | + app = make_docstring_app() |
| 255 | + lines = ["current nesting depth"] |
| 256 | + process_docstring(app, "attribute", "c_ext_mod.Encoder.depth", c_ext_mod.Encoder.depth, None, lines) |
| 257 | + assert lines[0] == "current nesting depth" |
| 258 | + assert lines[-1].startswith(":type: ") |
| 259 | + assert "int" in lines[-1] |
| 260 | + |
| 261 | + |
| 262 | +def test_descriptor_type_hint_without_stub_is_none() -> None: |
| 263 | + import array # noqa: PLC0415 |
| 264 | + |
| 265 | + assert get_descriptor_type_hint(array.array.typecode) is None |
| 266 | + |
| 267 | + |
| 268 | +def test_descriptor_type_hint_ignores_non_descriptors() -> None: |
| 269 | + assert get_descriptor_type_hint(object()) is None |
| 270 | + |
| 271 | + |
219 | 272 | def test_get_all_type_hints_resolves_c_extension_class_new(c_ext_mod: Any) -> None: |
220 | 273 | result = get_all_type_hints([], c_ext_mod.Encoder.__new__, "c_ext_mod.Encoder.__new__", {}) |
221 | 274 | default_type = result["default"] |
|
0 commit comments