Consider the following code from my hypothetical ORM that has three different ways of building an object
from typing import TypeVar, Type
T = TypeVar('T')
class ModelMeta(type):
def build(cls: Type[T]) -> T:
return cls()
def build_other(cls):
return cls()
class Model(metaclass=ModelMeta):
@classmethod
def new(cls: Type[T]) -> T:
return cls()
I'm having trouble defining build in a way that type checks. In this example, I get an error on build about how Type[T] is not a supertype of the class ModelMeta.
build_other passes the type checker, but usages don't seem to catch anything (implicit Any perhaps?)
class Dog(Model):
def __init__(self):
print("Built Dog")
class Cat(Model):
def __init__(self):
print("Built Cat")
c: Cat = Dog.new() # type check fails
c2: Cat = Dog.build() # type check fails
c3: Cat = Dog.build_other() # passes
Considering class methods work, it feels like metaclass methods should equally be able to "unwrap" the instance type for a class, but there might be subtleties I'm missing here.
My wish list here would be:
- have the inverse of
Type (something like Instance) so I could write something like def build(cls: T) -> Instance[T]. This would be (I think) a bit clearer.
- Have an intersection type, with which I could declare something like
def build(cls: (Type[T] & ModelMeta)) -> T. This would help with a lot of other problems as well. This seems like it would be a useful shortcut to writing subclasses
- Have a magic hook in
subtypes.is_subtype that would let me write a custom subtype check in some types
Full context: I'm writing some stubs for Django's ORM, and was hitting issues around the type of Model.objects.create. So in my case I end up needing a "class property" (hence doing things through the metaclass), which is why the simple new() call strategy hasn't been working for me.
I think this is related to #3438, but I'm having a hard time identifying the link.
Consider the following code from my hypothetical ORM that has three different ways of building an object
I'm having trouble defining
buildin a way that type checks. In this example, I get an error onbuildabout howType[T]is not a supertype of the classModelMeta.build_otherpasses the type checker, but usages don't seem to catch anything (implicit Any perhaps?)Considering class methods work, it feels like metaclass methods should equally be able to "unwrap" the instance type for a class, but there might be subtleties I'm missing here.
My wish list here would be:
Type(something likeInstance) so I could write something likedef build(cls: T) -> Instance[T]. This would be (I think) a bit clearer.def build(cls: (Type[T] & ModelMeta)) -> T. This would help with a lot of other problems as well. This seems like it would be a useful shortcut to writing subclassessubtypes.is_subtypethat would let me write a custom subtype check in some typesFull context: I'm writing some stubs for Django's ORM, and was hitting issues around the type of
Model.objects.create. So in my case I end up needing a "class property" (hence doing things through the metaclass), which is why the simplenew()call strategy hasn't been working for me.I think this is related to #3438, but I'm having a hard time identifying the link.