Bug: Recursive Dependency Needed for SQLAlchemyFactory Definitions?
Description
Hi,
I am confused when defining a 1-to-many relationship between two tables and factories on how to let the factories reference each other.
For example
class BaseFactory(SQLAlchemyFactory[T]):
__is_base_factory__ = True
__min_collection_length__ = 1
__set_relationships__ = True
class companyFactory(BaseFactory):
__model__ = Company
id = Use(lambda: companyFactory.__faker__.password(length=10, special_chars=False, digits=True))
company_name = Use(lambda: companyFactory.__faker__.company())
class employeeFactory(BaseFactory):
__model__ = Employee
employee_id = Use(lambda: employeeFactory.__faker__.password(length=10, special_chars=False, digits=True))
company_id = Use(lambda: employeeFactory.__faker__.password(length=10, special_chars=False, digits=True))
employee_name = Use(lambda: employeeFactory.__faker__.name())
salary = Use(lambda: employeeFactory.__faker__.pyfloat(5, 1, True))
addr_state = Use(lambda: employeeFactory.__faker__.state())
company_rel = companyFactory
companyFactory.employee_rel = employeeFactory
The _rel is a relationship sqlalchemy var that defines a 1-to-many relationship between the two tables.
This leads to a max recursion depth exceeded error since there is a circular dependency within the class definitions...
Let's say I take the employeeFactory rel out and run this:
def test_sqla_factory_persistence() -> None:
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
session = Session(engine)
BaseFactory.__session__ = session
companyFactory.create_factory(Company).create_sync()
employeeFactory.create_factory(Employee).create_sync()
query = session.query(Company).all()
for row in query:
print(row.__dict__)
query = session.query(Employee).all()
for row in query:
print(row.__dict__)
I get:
{'company_name': 'White Inc', 'id': '5wD2g6Laz7'}
{ 'company_name': 'ZpxESJXfkUxmPWkUvXkd', 'id': 'jfKYEXYSZqOLelUPlRPW'}
{'salary': 45381.1, 'employee_id': 'sFfu0QVpp3', 'addr_state': 'North Dakota', 'company_id': '5wD2g6Laz7', 'employee_name': 'Daniel Johnson'}
{ 'salary': 86034.4, 'employee_id': 'SPf2GVqjS2', 'addr_state': 'Tennessee', 'company_id': 'jfKYEXYSZqOLelUPlRPW', 'employee_name': 'Ryan Bennett'}
As you can see, the 2nd company created when I called the employeeFactory create_sync() command creates a company that no longer respects the definitions I want of my companyFactory. However, the employees created do follow the rules since they use the employeeFactory. This is not what I want. I want to be able to have the created company follow the companyFactory I defined.
It's unclear to me how to do this since if I try to add the factory to the rel definition, I get the circular dependency. Please let me know if I'm missing anything obvious
URL to code causing the issue
No response
MCVE
# Your MCVE code here
Steps to reproduce
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
Screenshots
"In the format of: "
Logs
E RecursionError: maximum recursion depth exceeded while calling a Python object
!!! Recursion detected (same locals & position)
=========================================================================================== short test summary info ============================================================================================
FAILED test_factories.py::test_sqla_factory_persistence - RecursionError: maximum recursion depth exceeded while calling a Python object
Release Version
2.18.1
Platform
- [ ] Linux
- [x] Mac
- [ ] Windows
- [ ] Other (Please specify in the description above)
There is a feature in polyfactory to guard against recursive relationships where possible but this is not applied to explicitly defined factory as fields.
Potential workaround would be __set_as_default_type__ docs here and remove explicitly linking to get around this. Would this work for your use case?