Hi there,

I'm trying to use the UniqueObject recipe for my project which does
not use declarative_base(). However, I'm having trouble getting this
to work and run into this error:

sqlalchemy.orm.exc.UnmappedInstanceError: Class '__main__.Widget' is
mapped, but this instance lacks instrumentation.  This occurs when the
instance is created before sqlalchemy.orm.mapper(__main__.Widget) was
called.

Is it simply not possible to use the decorator like this when the
mapping is done module-level after the class definition? If so, is
declarative the recommended practice now? Here is my code:

# From http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject
def unique_constructor(scoped_session, hashfunc, queryfunc):
    def decorate(cls):
        def _null_init(self, *arg, **kw):
            pass
        def __new__(cls, bases, *arg, **kw):
            session = scoped_session()
            cache = getattr(session, '_unique_cache', None)
            if cache is None:
                session._unique_cache = cache = {}

            key = (cls, hashfunc(*arg, **kw))
            if key in cache:
                return cache[key]
            else:
                q = session.query(cls)
                q = queryfunc(q, *arg, **kw)
                obj = q.first()
                if not obj:
                    obj = object.__new__(cls)
                    obj._init(*arg, **kw)
                    session.add(obj)
                cache[key] = obj
                return obj

        cls._init = cls.__init__
        cls.__init__ = _null_init
        cls.__new__ = classmethod(__new__)
        return cls

    return decorate

from sqlalchemy import *
from sqlalchemy.orm import *

engine = create_engine('sqlite://', echo=True)
Session = scoped_session(sessionmaker(bind=engine))
metadata = MetaData()

@unique_constructor(Session,
    lambda name:name,
    lambda query, name:query.filter(Widget.name==name)
)
class Widget(object): pass

widget_table = Table(
    'widgets',
    metadata,

    Column('id', Integer, nullable=False, primary_key=True,
autoincrement=True),
    Column('name', String(255), nullable=False)
)

Index('idx_widgets_name', widget_table.c.name, unique=True)

mapper(Widget, widget_table)

if __name__ == '__main__':
    metadata.create_all(engine)

    session = Session()

    w1, w2, w3 = Widget(name='w1'), Widget(name='w2'),
Widget(name='w3')
    w1b = Widget(name='w1')

    assert w1 is w1b
    assert w2 is not w3
    assert w2 is not w1

    session.commit()

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to