I'm trying to add good #Python type annotations to #Lisien
Everything stored in it needs to be serializable in messagepack, so I've annotated all its function signatures with one of the type aliases
Key: TypeAlias = (
str | int | float | None | tuple["Key", ...] | frozenset["Key"]
)
Value: TypeAlias = (
Key
| dict[Key, "Value"]
| tuple["Value", ...]
| list["Value"]
| set["Value"]
| frozenset["Value"]
)
Works ok so far.
But now I'm trying to use NewType to distinguish generic keys from those that name a Lisien entity, such as a node, edge, or graph.
You can't use NewType on type annotations, so I have to make a class for it. I did it like this:
def is_valid_key(obj) -> TypeGuard[Key]:
return (
obj is None
or isinstance(obj, (str, int, float))
or (
isinstance(obj, (tuple, frozenset))
and all(is_valid_key(elem) for elem in obj)
)
)
class KeyClass:
def __new__(cls, that: Key) -> Key:
return that
def __instancecheck__(self, instance) -> bool:
return is_valid_key(instance)
Having to pick whether to use Key or KeyClass kinda sucks and I want to use just the class everywhere, but it seems like #PyCharm 's type checker can't tell that, when I annotate something KeyClass, that means it shouldn't complain when I pass in a string.
Is this a PyCharm limitation, or am I using types wrong?