-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Checks
- I added a descriptive title to this issue
- I have searched (google, github) for similar issues and couldn't find anything
- I have read and followed the docs and still think this is a bug
Bug
Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":
root@20116b25f897:/[REDACTED] # python -c "import pydantic.utils; print(pydantic.utils.version_info())"
pydantic version: 1.8.2
pydantic compiled: False
install path: /usr/local/lib/python3.10/site-packages/pydantic
python version: 3.10.5 (main, Jun 7 2022, 18:49:47) [GCC 10.2.1 20210110]
platform: Linux-5.10.104-linuxkit-x86_64-with-glibc2.31
optional deps. installed: ['dotenv', 'email-validator', 'typing-extensions']
"""Base class for all database models."""
from typing import Any, Dict, Optional
from uuid import UUID, uuid4
import sqlalchemy as sa
import sqlalchemy.dialects.postgresql as pg
from inflection import underscore
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import declared_attr
from sqlalchemy_utils import Timestamp
from pydantic import BaseModel as _BaseModel
class CommonBase(_BaseModel, Timestamp):
"""SQLAlchemy Base common base class for all database models."""
id: UUID = sa.Column(pg.UUID(as_uuid=True), primary_key=True, default=uuid4)
@declared_attr
def __tablename__(cls) -> Optional[str]: # pylint: disable=no-self-argument
"""Define table name for all models as the snake case of the model's name."""
return underscore(cls.__name__)
def as_dict(self) -> Dict[str, Any]:
"""Return python dictionary of SQLAlchemy model."""
return self.__dict__
BaseModel = declarative_base(cls=CommonBase)On import of this BaseModel, we are getting a hard to track down error that seems to be related to sqlalchemy boolean expressions, but stemming from the smart_deepcopy line in pydantic and I am not quite sure what the real issue is, and whether it is caused by pydantic, sqlalchemy, or my setup (most likely).
The stack trace received on import is:
app/models/base_model.py:15: in <module>
class CommonBase(_BaseModel, Timestamp):
/usr/local/lib/python3.10/site-packages/pydantic/main.py:299: in __new__
fields[ann_name] = ModelField.infer(
/usr/local/lib/python3.10/site-packages/pydantic/fields.py:411: in infer
return cls(
/usr/local/lib/python3.10/site-packages/pydantic/fields.py:342: in __init__
self.prepare()
/usr/local/lib/python3.10/site-packages/pydantic/fields.py:445: in prepare
self._set_default_and_type()
/usr/local/lib/python3.10/site-packages/pydantic/fields.py:473: in _set_default_and_type
default_value = self.get_default()
/usr/local/lib/python3.10/site-packages/pydantic/fields.py:345: in get_default
return smart_deepcopy(self.default) if self.default_factory is None else self.default_factory()
/usr/local/lib/python3.10/site-packages/pydantic/utils.py:627: in smart_deepcopy
elif not obj and obj_type in BUILTIN_COLLECTIONS:
/usr/local/lib/python3.10/site-packages/sqlalchemy/sql/elements.py:582: in __bool__
raise TypeError("Boolean value of this clause is not defined")
E TypeError: Boolean value of this clause is not defined
I placed a debugger just before the raise and found that:
(Pdb) self
Column(None, UUID(as_uuid=True), table=None, primary_key=True, nullable=False, default=ColumnDefault(<function uuid4 at 0x7f99d085e200>))
(Pdb) self.__dict__
{'key': None, 'name': None, 'table': None, 'type': UUID(as_uuid=True), 'is_literal': False, 'primary_key': True, '_user_defined_nullable': symbol('NULL_UNSPECIFIED'), 'nullable': False, 'default': ColumnDefault(<function uuid4 at 0x7f99d085e200>), 'server_default': None, 'server_onupdate': None, 'index': None, 'unique': None, 'system': False, 'doc': None, 'onupdate': None, 'autoincrement': 'auto', 'constraints': set(), 'foreign_keys': set(), 'comment': None, 'computed': None, 'identity': None, '_creation_order': 88, 'comparator': <sqlalchemy.sql.type_api.TypeEngine.Comparator object at 0x7f99d07f0a00>, '_memoized_keys': frozenset({'comparator'})}
This is not new code in pydantic, and it also seems this check in sqlalchemy was added almost a decade ago so I am sure that is must be something wrong with either my expectatins or setup here. While investigating, it seems that this indeed is the correct way to setup a postgres UUID pk column within a pydantic model backed by sqlalchemy, but I am clearly missing something.
Thanks for the incredible work you do on this library!