full script is attached.  Works in 0.9, 0.8.

On Apr 18, 2014, at 1:50 AM, Joshua Ma <[email protected]> wrote:

> I tried with the sample code, and I get the following:
> 
>   File "/Users/joshma/aurelia/benchling/models/folder.py", line 273, in 
> <module>
>     configure_mappers()
>   File 
> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py",
>  line 2560, in configure_mappers
>     mapper._post_configure_properties()
>   File 
> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py",
>  line 1673, in _post_configure_properties
>     prop.init()
>   File 
> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/interfaces.py",
>  line 143, in init
>     self.do_init()
>   File 
> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py",
>  line 1509, in do_init
>     self._process_dependent_arguments()
>   File 
> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py",
>  line 1566, in _process_dependent_arguments
>     self.target = self.mapper.mapped_table
>   File 
> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py",
>  line 712, in __get__
>     obj.__dict__[self.__name__] = result = self.fget(obj)
>   File 
> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py",
>  line 1489, in mapper
>     configure=False)
>   File 
> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/base.py",
>  line 383, in class_mapper
>     raise exc.UnmappedClassError(class_)
> UnmappedClassError: Class 'sqlalchemy.sql.schema.Sequence' is not mapped
> 
> I tried this with both mapper_configured and instrument_class. I'm using 
> postgres and primary_key, so I think the Sequence it's using is getting in 
> the way?
> 
> I understand it's not easy to debug a SQLA setup from afar; thanks in advance 
> for the responses.
> 
> - Josh
> 
> 
> On Thu, Apr 17, 2014 at 10:07 PM, Michael Bayer <[email protected]> 
> wrote:
> OK well this stage to create an Index is just not deferred enough, and text() 
> is not supported.  Declarative has to make a “name” column that is part of 
> MyModel by copying it because it’s coming from a mixin and that just hasn’t 
> happened yet, the Column is not the right object yet.   The Table isn’t 
> there.  Index wasn’t designed with this case in mind, it doesn’t support 
> string names the way UniqueConstraint does because it was intended to be 
> constructed given Table bound columns after the Table is fully assembled.  
> This is from the history of Table/Index/etc. to look just like DDL, the Index 
> is created separately.
> 
> easy enough to break out of helper methods and just use events, 
> mapper_configured requires that mappers are configured, else use 
> instrument_class and use class_.__table__.c.name instead:
> 
> class MyMixin(object):
>     name = Column('name', String(64), nullable=False)
> 
> @event.listens_for(MyMixin, "mapper_configured", propagate=True)
> def add_index(mapper, class_):
>     Index('mymodel_lower_name_idx', func.lower(class_.name),
>       postgresql_ops={'name': 'text_pattern_ops'})
> 
> class MyModel(MyMixin, Base):
>     __tablename__ = 'foo'
> 
>     id = Column(Integer, primary_key=True)
> 
> configure_mappers()
> 
> 
> https://bitbucket.org/zzzeek/sqlalchemy/issue/3028/support-text-in-index-thats-already-table
>  is added to support text()
> 
> 
> 
> 
> On Apr 18, 2014, at 12:24 AM, Joshua Ma <[email protected]> wrote:
> 
>> Hi Mike,
>> 
>> In hindsight I might have responded prematurely - got around to trying it 
>> and with text() I get the following:
>> 
>>   __table_args__ = (
>>     ...
>>     Index('folder_lower_name_idx', text('lower(name)'),
>>           postgresql_ops={'name': 'text_pattern_ops'}),
>>   )
>> 
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py",
>>  line 2798, in __init__
>>     ColumnCollectionMixin.__init__(self, *columns)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py",
>>  line 2231, in __init__
>>     for c in columns]
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py",
>>  line 2223, in _to_schema_column_or_string
>>     raise exc.ArgumentError(msg % element)
>> ArgumentError: Element <sqlalchemy.sql.elements.TextClause object at 
>> 0x108e2b910> is not a string name or column element
>> 
>> With declared_attr:
>> 
>>   @declared_attr
>>   def __table_args__(cls):
>>     return (
>>       ...
>>       Index('folder_lower_name_idx', func.lower(cls.name),
>>             postgresql_ops={'name': 'text_pattern_ops'}),
>>     )
>> 
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/flask_sqlalchemy.py",
>>  line 477, in __init__
>>     DeclarativeMeta.__init__(self, name, bases, d)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py",
>>  line 53, in __init__
>>     _as_declarative(cls, classname, cls.__dict__)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py",
>>  line 251, in _as_declarative
>>     **table_kw)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py",
>>  line 352, in __new__
>>     table._init(name, metadata, *args, **kw)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py",
>>  line 429, in _init
>>     self._init_items(*args)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py",
>>  line 72, in _init_items
>>     item._set_parent_with_dispatch(self)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/base.py",
>>  line 421, in _set_parent_with_dispatch
>>     self._set_parent(parent)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py",
>>  line 2803, in _set_parent
>>     ColumnCollectionMixin._set_parent(self, table)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py",
>>  line 2241, in _set_parent
>>     self.columns.add(col)
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/base.py",
>>  line 490, in add
>>     self[column.key] = column
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/base.py",
>>  line 499, in __setitem__
>>     if key in self:
>>   File 
>> "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/base.py",
>>  line 554, in __contains__
>>     raise exc.ArgumentError("__contains__ requires a string argument")
>> ArgumentError: __contains__ requires a string argument
>> 
>> Is the functional index supported even if I'm using postgresql_ops? I've 
>> re-installed and upgraded to SQLAlchemy 0.9.4, same errors.
>> 
>> - Josh
>> 
>> 
>> On Thu, Apr 17, 2014 at 4:57 PM, Joshua Ma <[email protected]> wrote:
>> Awesome, thanks so much for the quick response.
>> 
>> 
>> On Sun, Apr 13, 2014 at 7:00 PM, Michael Bayer <[email protected]> 
>> wrote:
>> you need to turn your __table_args__ into a callable:
>> 
>> @declared_attr
>> def __table_args__(cls):
>>     return (Index(…, func.lower(cls.name), …), )
>> 
>> or just use a string for your functional index:    Index(…, 
>> text(“LOWER(name)”), …)
>> 
>> 
>> On Apr 13, 2014, at 9:22 PM, Joshua Ma <[email protected]> wrote:
>> 
>>> Is there a way to create a functional index in a declarative model without 
>>> referencing the actual column? I currently have something like
>>> 
>>> class MyModel(db.Base):
>>>     name = db.Column('name', db.String(255))
>>>     __table_args__ = (
>>>         Index('mymodel_lower_name_idx', func.lower(name),
>>>               postgresql_ops={'name': 'text_pattern_ops'}),
>>>     )
>>> 
>>> which is slightly inconvenient because I usually declare all my columns 
>>> under __table_args__.
>>> 
>>> More importantly, though, I use a mixin for some models, with the 
>>> __table_args__ in the model and the column in the mixin:
>>> 
>>> class MyMixin(object):
>>>     name = db.Column(db.String(64), nullable=False)
>>> 
>>> class MyModel(MyMixin, db.Base):
>>>     __table_args__ = (
>>>         Index('mymodel_lower_name_idx', func.lower(MyMixin.name),
>>>               postgresql_ops={'name': 'text_pattern_ops'}),
>>>     )
>>> 
>>> but this doesn't seem to work, I get "ArgumentError: __contains__ requires 
>>> a string argument" at runtime.
>>> 
>>> The rest of my indices are just strings (e.g. Index('mymodel_name_idx', 
>>> 'name')) - is there a similar way to create functional ones? I tried 
>>> 'lower(name)' but it doesn't like that either since it's not a valid column 
>>> (KeyError: 'lower(name)').
>>> 
>>> Thanks!
>>> Josh
>>> 
>>> -- 
>>> 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 [email protected].
>>> 
>>> To post to this group, send email to [email protected].
>>> Visit this group at http://groups.google.com/group/sqlalchemy.
>>> For more options, visit https://groups.google.com/d/optout.
>> 
>> 
>> -- 
>> You received this message because you are subscribed to a topic in the 
>> Google Groups "sqlalchemy" group.
>> To unsubscribe from this topic, visit 
>> https://groups.google.com/d/topic/sqlalchemy/CgSJUlelhGs/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to 
>> [email protected].
>> To post to this group, send email to [email protected].
>> Visit this group at http://groups.google.com/group/sqlalchemy.
>> For more options, visit https://groups.google.com/d/optout.
>> 
>> 
>> 
>> -- 
>> 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 [email protected].
>> To post to this group, send email to [email protected].
>> Visit this group at http://groups.google.com/group/sqlalchemy.
>> For more options, visit https://groups.google.com/d/optout.
> 
> 
> -- 
> You received this message because you are subscribed to a topic in the Google 
> Groups "sqlalchemy" group.
> To unsubscribe from this topic, visit 
> https://groups.google.com/d/topic/sqlalchemy/CgSJUlelhGs/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to 
> [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
> 
> 
> -- 
> 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 [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

-- 
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

On Apr 18, 2014, at 1:50 AM, Joshua Ma <[email protected]> wrote:

I tried with the sample code, and I get the following:

  File "/Users/joshma/aurelia/benchling/models/folder.py", line 273, in <module>
    configure_mappers()
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2560, in configure_mappers
    mapper._post_configure_properties()
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1673, in _post_configure_properties
    prop.init()
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/interfaces.py", line 143, in init
    self.do_init()
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1509, in do_init
    self._process_dependent_arguments()
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1566, in _process_dependent_arguments
    self.target = self.mapper.mapped_table
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 712, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1489, in mapper
    configure=False)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/orm/base.py", line 383, in class_mapper
    raise exc.UnmappedClassError(class_)
UnmappedClassError: Class 'sqlalchemy.sql.schema.Sequence' is not mapped

I tried this with both mapper_configured and instrument_class. I'm using postgres and primary_key, so I think the Sequence it's using is getting in the way?

I understand it's not easy to debug a SQLA setup from afar; thanks in advance for the responses.

- Josh


On Thu, Apr 17, 2014 at 10:07 PM, Michael Bayer <[email protected]> wrote:
OK well this stage to create an Index is just not deferred enough, and text() is not supported.  Declarative has to make a “name” column that is part of MyModel by copying it because it’s coming from a mixin and that just hasn’t happened yet, the Column is not the right object yet.   The Table isn’t there.  Index wasn’t designed with this case in mind, it doesn’t support string names the way UniqueConstraint does because it was intended to be constructed given Table bound columns after the Table is fully assembled.  This is from the history of Table/Index/etc. to look just like DDL, the Index is created separately.

easy enough to break out of helper methods and just use events, mapper_configured requires that mappers are configured, else use instrument_class and use class_.__table__.c.name instead:

class MyMixin(object):
    name = Column('name', String(64), nullable=False)

@event.listens_for(MyMixin, "mapper_configured", propagate=True)
def add_index(mapper, class_):
    Index('mymodel_lower_name_idx', func.lower(class_.name),
      postgresql_ops={'name': 'text_pattern_ops'})

class MyModel(MyMixin, Base):
    __tablename__ = 'foo'

    id = Column(Integer, primary_key=True)

configure_mappers()






On Apr 18, 2014, at 12:24 AM, Joshua Ma <[email protected]> wrote:

Hi Mike,

In hindsight I might have responded prematurely - got around to trying it and with text() I get the following:

  __table_args__ = (
    ...
    Index('folder_lower_name_idx', text('lower(name)'),
          postgresql_ops={'name': 'text_pattern_ops'}),
  )

  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 2798, in __init__
    ColumnCollectionMixin.__init__(self, *columns)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 2231, in __init__
    for c in columns]
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 2223, in _to_schema_column_or_string
    raise exc.ArgumentError(msg % element)
ArgumentError: Element <sqlalchemy.sql.elements.TextClause object at 0x108e2b910> is not a string name or column element

With declared_attr:

  @declared_attr
  def __table_args__(cls):
    return (
      ...
      Index('folder_lower_name_idx', func.lower(cls.name),
            postgresql_ops={'name': 'text_pattern_ops'}),
    )

  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/flask_sqlalchemy.py", line 477, in __init__
    DeclarativeMeta.__init__(self, name, bases, d)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 53, in __init__
    _as_declarative(cls, classname, cls.__dict__)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 251, in _as_declarative
    **table_kw)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 352, in __new__
    table._init(name, metadata, *args, **kw)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 429, in _init
    self._init_items(*args)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 72, in _init_items
    item._set_parent_with_dispatch(self)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/base.py", line 421, in _set_parent_with_dispatch
    self._set_parent(parent)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 2803, in _set_parent
    ColumnCollectionMixin._set_parent(self, table)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 2241, in _set_parent
    self.columns.add(col)
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/base.py", line 490, in add
    self[column.key] = column
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/base.py", line 499, in __setitem__
    if key in self:
  File "/Users/joshma/.envs/aurelia/lib/python2.7/site-packages/sqlalchemy/sql/base.py", line 554, in __contains__
    raise exc.ArgumentError("__contains__ requires a string argument")
ArgumentError: __contains__ requires a string argument

Is the functional index supported even if I'm using postgresql_ops? I've re-installed and upgraded to SQLAlchemy 0.9.4, same errors.

- Josh


On Thu, Apr 17, 2014 at 4:57 PM, Joshua Ma <[email protected]> wrote:
Awesome, thanks so much for the quick response.


On Sun, Apr 13, 2014 at 7:00 PM, Michael Bayer <[email protected]> wrote:
you need to turn your __table_args__ into a callable:

@declared_attr
def __table_args__(cls):
    return (Index(…, func.lower(cls.name), …), )

or just use a string for your functional index:    Index(…, text(“LOWER(name)”), …)


On Apr 13, 2014, at 9:22 PM, Joshua Ma <[email protected]> wrote:

Is there a way to create a functional index in a declarative model without referencing the actual column? I currently have something like

class MyModel(db.Base):
    name = db.Column('name', db.String(255))
    __table_args__ = (
        Index('mymodel_lower_name_idx', func.lower(name),
              postgresql_ops={'name': 'text_pattern_ops'}),
    )

which is slightly inconvenient because I usually declare all my columns under __table_args__.

More importantly, though, I use a mixin for some models, with the __table_args__ in the model and the column in the mixin:

class MyMixin(object):
    name = db.Column(db.String(64), nullable=False)

class MyModel(MyMixin, db.Base):
    __table_args__ = (
        Index('mymodel_lower_name_idx', func.lower(MyMixin.name),
              postgresql_ops={'name': 'text_pattern_ops'}),
    )

but this doesn't seem to work, I get "ArgumentError: __contains__ requires a string argument" at runtime.

The rest of my indices are just strings (e.g. Index('mymodel_name_idx', 'name')) - is there a similar way to create functional ones? I tried 'lower(name)' but it doesn't like that either since it's not a valid column (KeyError: 'lower(name)').

Thanks!
Josh

--
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 [email protected].

To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


--
You received this message because you are subscribed to a topic in the Google Groups "sqlalchemy" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/sqlalchemy/CgSJUlelhGs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.



--
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


--
You received this message because you are subscribed to a topic in the Google Groups "sqlalchemy" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/sqlalchemy/CgSJUlelhGs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


--
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy import event

Base = declarative_base()

class MyMixin(object):
    name = Column('name', String(64), nullable=False)

@event.listens_for(MyMixin, "mapper_configured", propagate=True)
def add_index(mapper, class_):
    Index('mymodel_lower_name_idx', func.lower(class_.name),
      postgresql_ops={'name': 'text_pattern_ops'})

class MyModel(MyMixin, Base):
    __tablename__ = 'foo'

    id = Column(Integer, primary_key=True)

configure_mappers()
e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
Base.metadata.drop_all(e)
Base.metadata.create_all(e)

Reply via email to