|
5 | 5 | import hashlib |
6 | 6 | import logging |
7 | 7 | from json import dumps |
| 8 | +from typing import TYPE_CHECKING |
8 | 9 |
|
9 | 10 | import pytest |
10 | 11 |
|
11 | 12 | from swgoh_comlink import SwgohComlink |
12 | 13 | from swgoh_comlink._base import _SENSITIVE_KEYS, SwgohComlinkBase, param_alias, sanitize_url |
13 | 14 | from swgoh_comlink.exceptions import SwgohComlinkValueError |
14 | 15 |
|
| 16 | +if TYPE_CHECKING: |
| 17 | + # `typing.assert_type` is 3.11+; `typing_extensions` works on every |
| 18 | + # supported Python version and is already in the dev dependency closure. |
| 19 | + from typing_extensions import assert_type |
| 20 | + |
| 21 | + from swgoh_comlink import SwgohComlinkAsync |
| 22 | + |
15 | 23 | # ── sanitize_url ───────────────────────────────────────────────────────── |
16 | 24 |
|
17 | 25 |
|
@@ -79,6 +87,30 @@ def test_cannot_instantiate_base_directly(self): |
79 | 87 | SwgohComlinkBase() |
80 | 88 |
|
81 | 89 |
|
| 90 | +# ── Constructor type inference (PR #98 regression guard) ───────────────── |
| 91 | +# |
| 92 | +# `SwgohComlinkBase.__new__` must return `Self` so that subclass constructor |
| 93 | +# calls infer as the concrete subclass, not the base. Without this, type |
| 94 | +# checkers reject subclass-only attribute access such as |
| 95 | +# `SwgohComlink(...).get_player(...)`. |
| 96 | +# |
| 97 | +# The function below is intentionally never invoked at runtime — it lives |
| 98 | +# under `if TYPE_CHECKING:` so the static type checker (mypy / ty) validates |
| 99 | +# the `assert_type` calls without spinning up real httpx clients. |
| 100 | + |
| 101 | +if TYPE_CHECKING: |
| 102 | + |
| 103 | + def _typecheck_constructor_returns_concrete_subclass() -> None: |
| 104 | + sync_client = SwgohComlink() |
| 105 | + assert_type(sync_client, SwgohComlink) |
| 106 | + # Subclass-only attribute access — must resolve without error. |
| 107 | + _ = sync_client.get_player |
| 108 | + |
| 109 | + async_client = SwgohComlinkAsync() |
| 110 | + assert_type(async_client, SwgohComlinkAsync) |
| 111 | + _ = async_client.get_player |
| 112 | + |
| 113 | + |
82 | 114 | # ── Constructor ────────────────────────────────────────────────────────── |
83 | 115 |
|
84 | 116 |
|
|
0 commit comments