afaiknow these traits are like my own static_types, i.e. descriptors 
holding metadata and applying it to attribute access.
i have been combining SA with static_type for more than 2 years now, 
since SA 3.0.

The approach i did in the beginning was to replace the object's 
__dict__ by something smart that is static_type-aware. When 
InstrumentionManager framework came into place, i did not find it any 
different, as SA still uses the __dict__ for data access. The 
difference is that now my  __dict__ replacement is created once and 
not at every attr.access. 

i did suggest one patch about replaceing the SA's 
obj.__dict__.whatever usage with an explicit set of methods (so one 
knows what access to mime), and that was making SA 1-2% faster, but 
it wasn't accepted.

basicaly now there's a thin layer on top of SA, then SA itself, then a 
thick layer underneath managing the data (the fake __dict__).

declarative+traits... u'll end up where i was. dbcook.sf.net is doing 
that - since beginning. and it's switchable on/off.
It all works well and stable, in project with 250-300 classes, 
although about 15% slower than without it (-:)

The sa2static code:
svn co 
http://dbcook.svn.sourceforge.net/svnroot/dbcook/trunk/dbcook/usage/static_type/

The static_type itself:
svn co https://dbcook.svn.sourceforge.net/svnroot/dbcook/static_type

whole dbcook: 
svn co https://dbcook.svn.sourceforge.net/svnroot/dbcook/trunk

i have quite some experience fighting this field, ask if u want.

ciao
svilen
www.svilendobrev.com

On Sunday 08 February 2009 01:51:20 cputter wrote:
> Hi guys and girls,
>
> I've recently discovered the joys of using sqlalchemy and would
> love to using it together with Traits.  A few months back there was
> an attempt to integrate sqlalchemy into traits, though it wasn't
> really comprehensive in exploiting all of sqlalchemy's potential.
>
> So I'm trying to work on that and combine ext.Declarative with
> traits. The basic idea is to use the DeclarativeMeta type to
> generate Columns from Traits and pass those on for the Declarative
> extension to do its magic.  This would allow mixing of sqlalchemy
> attributes and trait attributes in a single class so that we could
> still make use of all the relational setup sqlalchemy does in any
> case.
>
> Reading through several threads and looking at Elixir's SA
> integration helped me a bit though I couldn't find any
> documentation on how to implement the InstrumentationManager
> interface.  I'm assuming this would be essential for letting Traits
> and SQLAlchemy play well together.
>
> There's still a lot of work to do, and I'm not really sure what
> needs to be done for everything to work properly.  Would really
> appreciate it if someone could help me out.
>
>
> Here's an example of how it's working at the moment, I'll add the
> actual implementation at the end.
>
> #####################################
> class User(HasTraitsORM):
>     __tablename__ = 'users'
>
>     id = Column('id', Integer, primary_key=True)
>     name = Str(sqldb=True)
>
>     def _name_changed(self, old, new):
>         print 'Changed name from %s to %s.' % (old, new)
>
>     def __repr__(self):
>         return '<User(%s, %s)>' % (self.id, self.name)
>
> people = ['John', 'Charls','Steve','Smith','Jane']
>
> for per in people:
>     obj = User(name=per)
>     sess = sqlservice.Session()
>     sess.add(obj)
>     sess.commit()
>     sess.close()
>     print obj
>
> session = sqlservice.Session()
> print '\nQuery all users\n'
> for user in session.query(User).order_by(User.name).all():
>     print user
>
> session.close()
>
>
> ############################
>
> Which spits out:
> ###############################
> Changed name from  to John.
> <User(users.id, )>
> Changed name from  to Charls.
> <User(users.id, )>
> Changed name from  to Steve.
> <User(users.id, Steve)>
> Changed name from  to Smith.
> <User(users.id, Smith)>
> Changed name from  to Jane.
> <User(users.id, Jane)>
>
> Query all users
>
> <User(2, Charls)>
> <User(1, John)>
>
> ##############################
>
> Which is really strange behaviour.  There's obviously something
> wrong in my implementation of HasTraitsORM but why the different
> results within the same loop???  Why add only two instances?
>
> Totally baffles me.
>
> Here's the rest of my code, hope somehow can help me out.  It's
> very messy, I've been hacking at it like crazy with no success :-)
>
> Hope you're all having a great weekend.
> -Chris
>
>
> ##############################
>
> # Standard library imports.
> import logging
>
> # Enthought library imports
> from enthought.preferences.api import Preferences
> from enthought.traits.api import \
>     HasTraits, MetaHasTraits, Int, Str, Bool, Float, Any,\
>     String, Enum, Python, \
>     on_trait_change, TraitListObject
>
> # Package imports
> import sqlalchemy
> from sqlalchemy import Column, Integer
> from sqlalchemy.schema import MetaData
> from sqlalchemy.orm.interfaces import MapperProperty,
> InstrumentationManager
> from sqlalchemy.orm.attributes import get_attribute, set_attribute,
> is_instrumented
> from sqlalchemy.orm.collections import InstrumentedList,
> collection_adapter
> from sqlalchemy.ext.declarative import _as_declarative
>
>
> # Setup a logger for this module.
> logger = logging.getLogger(__name__)
>
>
> TRAIT_MAPPING = {
>          Int : 'sqlalchemy.Integer',
>          Str : 'sqlalchemy.Text',
>          Enum : 'sqlalchemy.Text',
>          String : 'sqlalchemy.Text',
>          Float : 'sqlalchemy.Float',
>          Bool : 'sqlalchemy.Boolean',
>          }
>
>
> class HasTraitsORMState(InstrumentationManager):
>     def __init__(self, cls):
>         self.states = {}
>
>     def instrument_attribute(self, class_, key, attr):
>         pass
>
>     def install_descriptor(self, class_, key, attr):
>         pass
>
>     def uninstall_descriptor(self, class_, key, attr):
>         pass
>
>     def instrument_collection_class(self, class_, key,
> collection_class):
>         return ObjectCollection
>
>     def get_instance_dict(self, class_, instance):
>         return instance.__dict__
>
>     def initialize_instance_dict(self, class_, instance):
>         instance.reset_traits()
>
>     def initialize_collection(self, key, state, factory):
>         data = factory()
>         return ObjectCollectionAdapter(key, state, data), data
>
>     def install_state(self, class_, instance, state):
>         self.states[id(instance)] = state
>
>     def state_getter(self, class_):
>         def find(instance):
>             return self.states[id(instance)]
>         return find
>
>
> class ObjectCollectionAdapter(object):
>     """
>         An adapter for SQLAlchemy for TraitsListObject which is the
> collection
>         we use for storing instances of classes within attributes
> of other
>         classes.
>
>         TODO:  Think of a way to get this to behave like a normal
> traited
>         attribute of objects.
>         At the moment collection attributes are set through the
> mapper by SA
>         when using relations or backref.
>
>     """
>     def __init__(self, key, state, collection):
>         self.key = key
>         self.state = state
>         self.collection = collection
>         setattr(collection, '_sa_adapter', self)
>
>     def unlink(self, data):
>         setattr(data, '_sa_adapter', None)
>
>     def adapt_like_to_iterable(self, obj):
>         return iter(obj)
>
>     def append_with_event(self, item, initiator=None):
>         self.collection.append(item, emit=initiator)
>
>     def append_without_event(self, item):
>         self.collection.append(item, emit=False)
>
>     def remove_with_event(self, item, initiator=None):
>         self.collection.remove(item, emit=initiator)
>
>     def remove_without_event(self, item):
>         self.collection.remove(item, emit=False)
>
>     def clear_with_event(self, initiator=None):
>         for item in list(self):
>             self.remove_with_event(item, initiator)
>
>     def clear_without_event(self):
>         for item in list(self):
>             self.remove_without_event(item)
>
>     def __iter__(self):
>         return iter(self.collection)
>
>     def fire_append_event(self, item, initiator=None):
>         if initiator is not False and item is not None:
>             self.state.get_impl(self.key).fire_append_event
> (self.state, item,
>                                                            
> initiator)
>
>     def fire_remove_event(self, item, initiator=None):
>         if initiator is not False and item is not None:
>             self.state.get_impl(self.key).fire_remove_event
> (self.state, item,
>                                                            
> initiator)
>
>     def fire_pre_remove_event(self, initiator=None):
>         self.state.get_impl(self.key).fire_pre_remove_event
> (self.state,
>                                                            
> initiator)
>
> class ObjectCollection(TraitListObject):
>     __emulates__ = list
>
>     def __init__( self, trait, object, name, value ):
>         pass
>
>     def __init__(self):
>         self.members = list()
>     def append(self, object, emit=None):
>         self.members.append(object)
>         #collection_adapter(self).fire_append_event(object, emit)
>     def remove(self, object, emit=None):
>         #collection_adapter(self).fire_pre_remove_event(object)
>         self.members.remove(object)
>         #collection_adapter(self).fire_remove_event(object, emit)
>     def __getitem__(self, index):
>         return self.members[index]
>     def __iter__(self):
>         return iter(self.members)
>     def __len__(self):
>         return len(self.members)
>     def __repr__(self):
>         if len(self.members) == 0:
>             return '[empty collection]'
>         s = '['
>         for item in self.members[0:max(5, len(self.members))]:
>             s += '%s,' % item
>         s += '...]'
>         return s
>
>
> class DeclarativeMetaTraits(MetaHasTraits):
>     pass
>
> #    def __new__(cls, classname, bases, dict_):
> #        return MetaHasTraits.__new__(cls, classname, bases, dict_)
>
>     def __init__(cls, classname, bases, dict_):
>
>         if '_decl_class_registry' in cls.__dict__:
>             super(DeclarativeMetaTraits, cls).__init__(cls,
> classname, bases, dict_)
>             return
>
>         if '__tablename__' not in dict_:
>             setattr(cls, '__tablename__', cls.__name__)
>
>         # create sql columns from flagged traits
>         if '__class_traits__' in cls.__dict__:
>             traits = cls.__dict__['__class_traits__']
>             for key, trait in traits.iteritems():
>                 if getattr( trait, 'sqldb' ):
>                     args = getattr( trait, 'col_args' ) or ()
>                     kwargs = getattr( trait, 'col_kwargs' ) or {}
>                     if 'name' not in kwargs:
>                         kwargs['name'] = key
>                     if 'type_' not in kwargs:
>                         kwargs['type_'] = eval(TRAIT_MAPPING[type
> (trait.trait_type)])
>
>                     if getattr(trait, 'sqlpk'):
>                         kwargs['primary_key'] = True
>
>                     c = Column(*args, **kwargs)
>                     dict_[key] = c
>                     setattr(cls, key, c)
>
>         # Pass this along to SA's declarative mapper stuff
>         _as_declarative(cls, classname, dict_)
>
>         super(DeclarativeMetaTraits, cls).__init__(cls, classname,
> bases, dict_)
>
>
> class HasTraitsORM(HasTraits):
>     __metaclass__ = DeclarativeMetaTraits
>
>     # some SA hacking
>     __sa_instrumentation_manager__ = HasTraitsORMState
>
>     _decl_class_registry = dict()
>     metadata = MetaData()
>
>     # Any implicit traits added by SQLAlchemy are transient and
> should not be
>     # copied through .clone_traits(), copy.copy(), or pickling.
>     _ = Python(transient=True)
>
>
>     # For some reason we need to override these, our superclass
> screws things up
>
>     def __getattr__(self, key):
>         if is_instrumented(self, key):
>             return get_attribute(self, key)
>         else:
>             try:
>                 return getattr(self, key)
>             except:
>                 pass
>
>     def __setattr__(self, key, value):
>         if is_instrumented(self, key):
>             set_attribute(self, key, value)
>         else:
>             setattr(self, key, value)
>
>
> #################################################
>
>
> 


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@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