You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
"Dynamic metaclass not supported" false positive on generics #11672
I am not sure that generic metaclasses is even a thing 🤔
I've never seen any references in PEPs / docs. Can you please check that it can be used this way?
Pyright should generate an error in the first example above. The fact that it doesn't is an oversight / bug. FooMetaclass[T] shouldn't be allowed because TypeVar T doesn't have a defined scope in this case.
Pyright does support the use of a specialized metaclass, as in your second example above. I don't see any reason why this shouldn't work from a type-checking standpoint. That said, it's a use case that isn't well tested, so you may run into issues.
There's an interesting case not covered in either of the above two samples:
In this variant, TypeVar T does have a well-defined scope (since it's bound to class Foo), so theoretically, this variant could be valid. I'm not sure it's something we'd want to support though.
@DetachHead, is there a real use case here, or are you just playing around with ideas?
Pyright does support the use of a specialized metaclass, as in your second example above. I don't see any reason why this shouldn't work from a type-checking standpoint. That said, it's a use case that isn't well tested, so you may run into issues.
yeah i found this issue:
classFooMetaclass(type, Generic[T]):
metaclass_value: TclassFoo(metaclass=FooMetaclass[int]):
value: int# wrong error message:# Cannot assign member "value" for type "Type[Foo]"# Member "value" is unknownFoo.metaclass_value="1"# it should be more like this error instead:# Cannot assign member "value" for type "Type[Foo]"# Expression of type "Literal['1']" cannot be assigned to member "value" of class "Foo"# "Literal['1']" is incompatible with "int"Foo.value="1"
There's an interesting case not covered in either of the above two samples:
In this variant, TypeVar T does have a well-defined scope (since it's bound to class Foo), so theoretically, this variant could be valid. I'm not sure it's something we'd want to support though.
yeah that's what i intended to put as my original example, i just forgot to include Generic[T] in the bases.
however it doesn't seem to work in this case:
classFooMetaclass(type, Generic[T]):
metaclass_value: TclassFoo(Generic[T], metaclass=FooMetaclass[T]):
value: T# should be `int` but is still the unbound genericreveal_type(Foo[int].metaclass_value) # Type of "Foo[int].metaclass_value" is "T@Foo"Foo[int].metaclass_value=1# errorFoo[int].value=1# no error
@DetachHead, is there a real use case here, or are you just playing around with ideas?
i stubled across this while trying to learn how metaclasses work, but i was basically trying to make a ReifiedGeneric class that looks something like this:
Those dymanic metaclasses would be really useful for factory-boy. I'm trying to add typing support for it, and i've managed to get if work for some cases, but one unsolved issue remains, here's minimal example based on factory_boy/factory/base.py
fromtypingimportGeneric, TypeVarT=TypeVar("T")
classFactoryMetaClass(type):
"""Factory metaclass for handling ordered declarations."""def__call__(cls, **kwargs):
"""Override the default Factory() syntax to call the default strategy. Returns an instance of the associated class. """returncls.create(**kwargs) # type: ignoredef__new__(cls, class_name, bases, attrs):
returnsuper().__new__(cls, class_name, bases, attrs)
classBaseFactory(Generic[T]):
"""Factory base support for sequences, attributes and stubs."""@classmethoddefcreate(cls, **kwargs) ->T:
...
classFactory(BaseFactory[T], metaclass=FactoryMetaClass):
"""Factory base with build and create support. This class has the ability to support multiple ORMs by using custom creation functions. """# ------------------------------classBook:
name: strauthor: strclassBookFactory(Factory[Book]):
...
book1=BookFactory.create()
reveal_type(book1)
book2=BookFactory()
reveal_type(book2)
Both mypy and pyright correctly handling first case, but i have no idea how to get it to return Book for second case.
mypy basic_example.py
basic_example.py:40:13: note: Revealed type is "basic_example.Book*"
basic_example.py:43:13: note: Revealed type is "basic_example.BookFactory"
@erictraut maybe you have idea how to solve this without generic metaclasses?
Reacted by Dan Strokirk, Claudio Catterina, Alexandre Morignot, Meiyer, Semyon Pupkov and STofone
I need classproperty with generic. And i've found so many needs for Generic metaclass.
fromfunctoolsimportcached_propertyfromtypingimportCallable, Literal, LiteralString, TypeclassSetFunc[T: LiteralString]:
def__init__(self, id: T):
self.id=iddef__call__(self, func: Callable):
...
returnfuncclassMETA_A[T: LiteralString](type):
@cached_propertydefset_func(cls) ->Type[SetFunc[T]]:
...# extend SetFunc and change META_A class attributes in __init__ of SetFuncreturnSetFuncclassA[T: LiteralString](metaclass=META_A[T]):
passclassB(A[Literal["1", "2", "3"]]):
pass# type checking for id does not work with pyright@B.set_func("1")deffunc():
pass
Activity
sobolevn commentedon Dec 8, 2021
I am not sure that generic metaclasses is even a thing 🤔
I've never seen any references in PEPs / docs. Can you please check that it can be used this way?
DetachHead commentedon Dec 8, 2021
pyright supports it and it works at runtime, so i see no reason these two features shouldn't work together for this to emerge.
erictraut commentedon Dec 9, 2021
Pyright should generate an error in the first example above. The fact that it doesn't is an oversight / bug.
FooMetaclass[T]shouldn't be allowed because TypeVarTdoesn't have a defined scope in this case.Pyright does support the use of a specialized metaclass, as in your second example above. I don't see any reason why this shouldn't work from a type-checking standpoint. That said, it's a use case that isn't well tested, so you may run into issues.
There's an interesting case not covered in either of the above two samples:
In this variant, TypeVar
Tdoes have a well-defined scope (since it's bound to classFoo), so theoretically, this variant could be valid. I'm not sure it's something we'd want to support though.@DetachHead, is there a real use case here, or are you just playing around with ideas?
DetachHead commentedon Dec 9, 2021
yeah i found this issue:
yeah that's what i intended to put as my original example, i just forgot to include
Generic[T]in the bases.however it doesn't seem to work in this case:
i stubled across this while trying to learn how metaclasses work, but i was basically trying to make a
ReifiedGenericclass that looks something like this:last-partizan commentedon Jun 10, 2022
Those dymanic metaclasses would be really useful for
factory-boy. I'm trying to add typing support for it, and i've managed to get if work for some cases, but one unsolved issue remains, here's minimal example based on factory_boy/factory/base.pyBoth mypy and pyright correctly handling first case, but i have no idea how to get it to return
Bookfor second case.@erictraut maybe you have idea how to solve this without generic metaclasses?
erictraut commentedon Jun 10, 2022
Yeah, use classes rather than metaclasses. This is the normal way to implement the factory pattern.
erdnaxeli commentedon Aug 21, 2023
That's not how FactoryBoy works. It works like this:
You don't instantiate the factory.
STofone commentedon May 10, 2025
I need
classpropertywithgeneric. And i've found so many needs forGeneric metaclass.