On Fri, 11 Nov 2016 13:27:09 -0500
mike bayer <mike...@zzzcomputing.com> wrote:

> 
> 
> On 11/11/2016 12:18 PM, Michael Williamson wrote:
> >
> > That still requires the repetition of the name of the attribute,
> > which I'd rather avoid. I've put together a variation on
> > hybrid_property which automatically assigns the label by scanning
> > through the class dict. It could probably do with a bit of
> > memoization and and proper handling of subtyping (i.e. checking
> > __dict__ of supertypes), but does this seem sane to you? Is there a
> > neater way?
> >
> > class hybrid_property2(hybrid_property):
> >     def __get__(self, instance, owner):
> >         if instance is None:
> >             expression = self.expr(owner)
> >             for key, value in owner.__dict__.items():
> >                 if value == self:
> >                     return expression.label(key)
> >
> >             return expression
> >         else:
> >             return self.fget(instance)
> >
> > Thanks for the suggestions so far, Mike and Simon.
> 
> Getting the name of the attribute you're set on is not something I
> know that there's any way to do without the kind of thing you're
> doing. Decorators usually work out because fn.__name__ is there to
> give us that info.

Thanks Mike, in the end I defined my own metatype that inherits from
DeclarativeMeta, and set __name__ on each property in __new__.

> 
> 
> >
> >>
> >>
> >>
> >>
> >>
> >>>
> >>> Is there a sensible way to do this? Or am I going about the
> >>> problem the wrong way? In practice, I'm using this to define
> >>> properties backed by a JSON field. In case it makes any
> >>> different, here's the actual use-case I have:
> >>>
> >>> from __future__ import unicode_literals
> >>>
> >>> import os
> >>>
> >>> from sqlalchemy import create_engine, Column, Integer
> >>> from sqlalchemy.dialects.postgresql import JSONB
> >>> from sqlalchemy.event import listens_for
> >>> from sqlalchemy.ext.hybrid import hybrid_property
> >>> from sqlalchemy.ext.declarative import declarative_base
> >>> from sqlalchemy.orm import Session
> >>> from sqlalchemy.pool import StaticPool
> >>>
> >>>
> >>> def json_property(json_column, name, type_=None):
> >>>     def instance_get(self):
> >>>         return getattr(self, json_column.key)[name]
> >>>
> >>>     def instance_set(self, value):
> >>>         json_obj = getattr(self, json_column.key)
> >>>         if json_obj is None:
> >>>             setattr(self, json_column.key, {})
> >>>         getattr(self, json_column.key)[name] = value
> >>>
> >>>     def cls_get(cls):
> >>>         expression = json_column[name]
> >>>         if type_:
> >>>             return expression.astext.cast(type_)
> >>>         else:
> >>>             return expression
> >>>
> >>>     return hybrid_property(fget=instance_get, expr=cls_get,
> >>> fset=instance_set)
> >>>
> >>>
> >>> Base = declarative_base()
> >>>
> >>> class Person(Base):
> >>>     __tablename__ = "person"
> >>>
> >>>     id = Column(Integer, primary_key=True)
> >>>     data = Column(JSONB, nullable=False)
> >>>     born = json_property(data, "born", Integer())
> >>>
> >>>
> >>> engine = create_engine(os.environ["TEST_DATABASE"],
> >>> poolclass=StaticPool) engine.execute("SET search_path TO pg_temp")
> >>>
> >>> @listens_for(engine, "engine_connect")
> >>> def set_search_path(connection, branch):
> >>>     connection.execute("SET search_path TO pg_temp")
> >>>
> >>>
> >>> Base.metadata.create_all(engine)
> >>> session = Session(engine)
> >>>
> >>> session.add(Person(born=1881))
> >>> session.commit()
> >>>
> >>> assert session.query(Person.born).one() == (1881, ) # Works fine
> >>> assert session.query(Person.born).one().born == 1881 # Raises
> >>> AttributeError since hybrid_property uses instance_get as the name
> >>>
> >>> --
> >>> SQLAlchemy -
> >>> The Python SQL Toolkit and Object Relational Mapper
> >>>
> >>> http://www.sqlalchemy.org/
> >>>
> >>> To post example code, please provide an MCVE: Minimal, Complete,
> >>> and Verifiable Example. See http://stackoverflow.com/help/mcve
> >>> for a full description.
> >>> ---
> >>> You received this message because you are subscribed to the Google
> >>> Groups "sqlalchemy" group.
> >>> To unsubscribe from this group and stop receiving emails from it,
> >>> send an email to sqlalchemy+unsubscr...@googlegroups.com
> >>> <mailto:sqlalchemy+unsubscr...@googlegroups.com>.
> >>> To post to this group, send email to sqlalchemy@googlegroups.com
> >>> <mailto:sqlalchemy@googlegroups.com>.
> >>> Visit this group at https://groups.google.com/group/sqlalchemy.
> >>> For more options, visit https://groups.google.com/d/optout.
> >>
> >

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to