Replace some isinstance calls with TypeGuard.

These aren't as ergonomic as I'd hoped because of
https://www.python.org/dev/peps/pep-0647/#narrowing-of-implicit-self-and-cls-parameters.

I added a decorator `@self_type_guard` so we can avoid needing to import
the descendent types in the typeguard implementation (which wouldn't fix
any circular imports, just move them).
This commit is contained in:
Dan Albert
2022-02-12 14:57:33 -08:00
parent 85e7b1762d
commit 2e901f3586
5 changed files with 57 additions and 7 deletions

20
game/typeguard.py Normal file
View File

@@ -0,0 +1,20 @@
from __future__ import annotations
from typing import Callable, TypeGuard, TypeVar
SelfT = TypeVar("SelfT")
BaseT = TypeVar("BaseT")
GuardT = TypeVar("GuardT")
def self_type_guard(
f: Callable[[SelfT, BaseT], TypeGuard[GuardT]]
) -> Callable[[SelfT, BaseT], TypeGuard[GuardT]]:
def decorator(s: SelfT, arg: BaseT) -> TypeGuard[GuardT]:
if id(s) != id(arg):
raise ValueError(
"self type guards must be called with self as the argument"
)
return f(s, arg)
return decorator