Hybrid attributes are under wrong name in result objects

Issue #3557 resolved
Łukasz Fidosz created an issue

When querying hybrid property it uses underlying column name instead of hybrid property name as attribute name in result object.

So code bellow (please note the commented line on the bottom):

from sqlalchemy import Integer, Column
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.types import TypeDecorator, Unicode, UnicodeText

Base = declarative_base()

class SomeClass(Base):
    __tablename__ = 'some_table'
    id = Column(Integer(), primary_key=True)
    raw_foo = Column('foo', Integer(), nullable=False, default=0)

    @hybrid_property
    def foo(self):
        if False: # some conditional code
            return self.raw_foo * 10

        return self.raw_foo

    @foo.expression
    def foo(cls):
        return cls.raw_foo

    @foo.setter
    def foo(self, value):
        self.raw_foo = value 

engine = create_engine('sqlite://', echo=True)
Session = scoped_session(sessionmaker(bind=engine))
session = Session()
Base.metadata.create_all(engine)

session.commit()
session.add_all([
    SomeClass(id=1, foo=1),
    SomeClass(id=2, foo=10),
    SomeClass(id=3, foo=30),
])
session.commit()

q = session.query(SomeClass.id, SomeClass.foo)
item = q.first()
# the commented line will work so apparently it uses
# underlying column as a name:
# print item.raw_foo
print item.foo

Will crash like this:

Traceback (most recent call last):
  File "/home/virhilo/sqlalchemy_hybrids_error.py", line 47, in <module>
    print item.foo
AttributeError: 'result' object has no attribute 'foo'

It happens on 1.0.8, 0.9.7 and latest from git (1.1.0b1)

Comments (7)

  1. Mike Bayer repo owner

    there's no special magic here, have your expression label it as desired:

    @foo.expression
    def foo(cls):
        return cls.raw_foo.label('foo')
    
  2. Mike Bayer repo owner

    consider that lots of users expect the semantics of the returned SQL expression to stay the same rather than being automatically modified. But also, hybrids are just Python descriptors in the first place, which are not provided any means of knowing what attribute name they are accessed under, so some kind of explicit "name" parameter would be needed in any case, unless you did some kind of scanning of the class after it's declared and re-decorated all the hybrids with another decorator that provides labeling.

  3. Łukasz Fidosz reporter

    Yeah, I misunderstood your previous comment initially, then edited mine as thought I was quick enough, sorry for messing.

  4. Log in to comment