So we are working with some existing code where there is an implementation of factories classes from the factory_boy project which create instances of other classes for example
class TableFactory(Factory):
class Meta:
model = Table
id = LazyAttribute(lambda x: uuid4())
color = SubFactory(ColorFactory)
reference = 'WT9034'
weight = 120
height = 50
length = 3
width = 1
where the Factory
base meta-class has a logic in its __new__
method to dynamically instantiate a class using the model provided in the Meta
class of the TableFactory
. The Table
model is a simple SQLAlchemy class/model.
Since the produced classes are made dynamically I guess we cannot have static type hinting for the produced class types? Or can we somehow add this?
I am assuming OP's concrete problem is that he is getting errors from the type checker when trying to use instances of the factory in his test code.
Example:
obj = TableFactory()
print(obj.reference)
This will create a type error like this with pylance:
Can not access member "reference" for type TableFactory.
A quick solution is to type annotate the assignment with the correct type. However, this does not work with the class alone, you need to also use one of the instantiation methods like create() or build() to create the object:
obj: Table = TableFactory.create()
print(obj.reference)
This works fine, but requires you to annotate all factory assignments in that particular way, which can get repetitive and make the code harder to read.
A better solution is add the type annotation to the factory class itself. This can be done by creating a mixin which has the generic type annotation and use it to compose a new factory class.
Here is how this would work:
from typing import Generic, TypeVar
import factory
T = TypeVar('T')
class BaseMetaFactory(Generic[T], factory.base.FactoryMetaClass):
def __call__(cls, *args, **kwargs) -> T:
return super().__call__(*args, **kwargs)
class TableFactory(factory.Factory, metaclass=BaseMetaFactory[Table]):
class Meta:
model = Table
...
As added bonus this mixin can be used create annotated version of all our factory classes.
For a more in depth discussion on different workarounds for this problem please also see the related issue on the factory boy repo.