8000
Skip to content

column_property breaks ORM insert from select returning model #9273

Description

@uriyyo

Describe the bug

column_property breaks ORM insert from select with returning model.

This issue was introduced in version 2.0.2`.

Optional link from https://docs.sqlalchemy.org which documents the behavior that is expected

No response

SQLAlchemy Version in Use

2.0.3

DBAPI (i.e. the database driver)

pysqlite

Database Vendor and Major Version

SQLite

Python Version

3.11

Operating system

OSX

To Reproduce

from __future__ import annotations

from sqlalchemy import create_engine, select, insert, literal
from sqlalchemy.orm import MappedAsDataclass, Mapped, mapped_column, DeclarativeBase, Session, column_property

engine = create_engine("sqlite:///:memory:", echo=True)


class Base(DeclarativeBase):
    pass


class User(MappedAsDataclass, Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(init=False, primary_key=True)

    name: Mapped[str] = mapped_column()
    age: Mapped[int] = mapped_column()

    is_adult: Mapped[int] = column_property(age >= 18, default=None)


Base.metadata.create_all(engine)

with Session(bind=engine) as session:
    stmt = select(
        literal(1).label("id"),
        literal("John").label("name"),
        literal(30).label("age"),
    )

    insert_stmt = (
        insert(User)
        .from_select(["id", "name", "age"], stmt)
        .returning(User)
    )

    result = session.scalars(insert_stmt)

Error

Traceback (most recent call last):
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/elements.py", line 1456, in __getattr__
    return getattr(self.comparator, key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Comparator' object has no attribute 'name'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/main.py", line 39, in <module>
    result = session.scalars(insert_stmt)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/session.py", line 2339, in scalars
    return self._execute_internal(
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/session.py", line 2124, in _execute_internal
    result: Result[Any] = compile_state_cls.orm_execute_statement(
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/bulk_persistence.py", line 1232, in orm_execute_statement
    return cls._return_orm_returning(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/bulk_persistence.py", line 541, in _return_orm_returning
    return loading.instances(result, querycontext)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/loading.py", line 131, in instances
    with util.safe_reraise():
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 147, in __exit__
    raise exc_value.with_traceback(exc_tb)
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/loading.py", line 112, in instances
    *[
     ^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/loading.py", line 113, in <listcomp>
    query_entity.row_processor(context, cursor)
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/context.py", line 2589, in row_processor
    _instance = loading._instance_processor(
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/loading.py", line 931, in _instance_processor
    prop.create_row_processor(
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/interfaces.py", line 1038, in create_row_processor
    strat.create_row_processor(
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/orm/strategies.py", line 276, in create_row_processor
    col = adapter.columns[col]
          ~~~~~~~~~~~~~~~^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/util/_collections.py", line 361, in __missing__
    self[key] = val = self.creator(self.weakself(), key)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/util.py", line 1389, in _locate_col
    c = ClauseAdapter.traverse(self, col)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py", line 811, in traverse
    return replacement_traverse(obj, self.__traverse_options__, replace)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py", line 1177, in replacement_traverse
    obj = clone(
          ^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py", line 1173, in clone
    newelem._copy_internals(clone=clone, **kw)
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/elements.py", line 4562, in _copy_internals
    self._element = clone(self._element, **kw)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py", line 1156, in clone
    newelem = replace(elem)
              ^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py", line 805, in replace
    e = cast(ReplacingExternalTraversal, v).replace(element)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/util.py", line 1211, in replace
    return self._corresponding_column(  # type: ignore
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/util.py", line 1139, in _corresponding_column
    newcol = self.selectable.exported_columns.get(col.name)
                                                  ^^^^^^^^
  File "/Users/yuriikarabas/PycharmProjects/sqlalchemy2-sandbox/venv/lib/python3.11/site-packages/sqlalchemy/sql/elements.py", line 1458, in __getattr__
    raise AttributeError(
AttributeError: Neither 'BinaryExpression' object nor 'Comparator' object has an attribute 'name'

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingnear-term releaseaddition to the milestone which indicates this should be in a near-term releaseormregressionsomething worked and was broken by a changesql

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    0