Bug: Try to use SQLAlchemyFactory for model with column_property
andy-takker opened this issue · 4 comments
Description
Create model with declared column_property
and try create model object with it.
Got error AttributeError: Neither 'Label' object nor 'Comparator' object has an attribute 'nullable'
URL to code causing the issue
No response
MCVE
from sqlalchemy import Integer, String
from sqlalchemy.orm import DeclarativeBase, column_property, mapped_column
from polyfactory.factories.sqlalchemy_factory import SQLAlchemyFactory
class Base(DeclarativeBase):
...
class Student(Base):
__tablename__ = "user"
id = mapped_column(Integer(), primary_key=True)
firstname = mapped_column(String(50))
lastname = mapped_column(String(50))
fullname = column_property(firstname + " " + lastname)
class StudentFactory(SQLAlchemyFactory[Student]):
__model__ = Student
__set_relationships__ = True
__set_foreign_keys__ = False
student = StudentFactory.build()
Steps to reproduce
1. Define SQLAlchemy model with column_property
2. Define SQLAlchemyFactory with model
3. Try to create object with factory
Screenshots
No response
Logs
tests/test_api/test_student/test_change_teacher.py:100:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.11/site-packages/polyfactory/factories/base.py:1031: in build
return cast("T", cls.__model__(**cls.process_kwargs(**kwargs)))
.venv/lib/python3.11/site-packages/polyfactory/factories/base.py:931: in process_kwargs
for field_meta in cls.get_model_fields():
.venv/lib/python3.11/site-packages/polyfactory/factories/sqlalchemy_factory.py:141: in get_model_fields
fields_meta.extend(
.venv/lib/python3.11/site-packages/polyfactory/factories/sqlalchemy_factory.py:143: in <genexpr>
annotation=cls.get_type_from_column(column),
.venv/lib/python3.11/site-packages/polyfactory/factories/sqlalchemy_factory.py:131: in get_type_from_column
if column.nullable:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <sqlalchemy.sql.elements.Label at 0x1079e01d0; %(4422762960 anon)s>, key = 'nullable'
def __getattr__(self, key: str) -> Any:
try:
return getattr(self.comparator, key)
except AttributeError as err:
> raise AttributeError(
"Neither %r object nor %r object has an attribute %r"
% (
type(self).__name__,
type(self.comparator).__name__,
key,
)
) from err
E AttributeError: Neither 'Label' object nor 'Comparator' object has an attribute 'nullable'
.venv/lib/python3.11/site-packages/sqlalchemy/sql/elements.py:1604: AttributeError
----------------------------------------------------------------- Captured stderr setup -----------------------------------------------------------------
Context impl PostgresqlImpl.
Will assume transactional DDL.
----------------------------------------------------------------- Captured stdout call ------------------------------------------------------------------
student.first_name || :param_1 || student.last_name # add my print to find a column with problem
Release Version
2.9.0
Platform
- Linux
- Mac
- Windows
- Other (Please specify in the description above)
Note
While we are open for sponsoring on GitHub Sponsors and
OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.
Check out all issues funded or available for funding on our Polar.sh dashboard
- If you would like to see an issue prioritized, make a pledge towards it!
- We receive the pledge once the issue is completed & verified
- This, along with engagement in the community, helps us know which features are a priority to our users.
@andy-takker thanks for reporting this! I'm able to reproduce this and the reason for this is that we should be skipping column_properties
, but we're not.
Also, I edited your original MCVE because that was not a working program in the sense that it wouldn't even run.
Hey! I have a similar issue with the hybrid_property
decorator. I even tried to Ignore()
the field but didn't work.
Maybe something like this could work:
if getattr(column, "nullable", False):
annotation = Union[annotation, None] # type: ignore[assignment]
Maybe something like this could work:
if getattr(column, "nullable", False): annotation = Union[annotation, None] # type: ignore[assignment]
I think the fix in #510 is probably the right approach. While your approach of using getattr
works, we actually don't want polyfactory
to to set the value for column_properties
since they're computed based on other fields.