activemapper.py :  » Web-Frameworks » Spyce » spyce-2.1 » sqlalchemy » ext » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Web Frameworks » Spyce 
Spyce » spyce 2.1 » sqlalchemy » ext » activemapper.py
from sqlalchemy import create_session,relation,mapper,\
                                   join, DynamicMetaData, class_mapper, \
                                   util, Integer
from sqlalchemy import and_,or_
from sqlalchemy import Table,Column,ForeignKey
from sqlalchemy.ext.sessioncontext import SessionContext
from sqlalchemy.ext.assignmapper import assign_mapper
from sqlalchemy import backref
import sqlalchemy

import inspect
import sys

#
# the "proxy" to the database engine... this can be swapped out at runtime
#
metadata = DynamicMetaData("activemapper")

try:
    objectstore = sqlalchemy.objectstore
except AttributeError:
    # thread local SessionContext
    class Objectstore(object):
        def __init__(self, *args, **kwargs):
            self.context = SessionContext(*args, **kwargs)
        def __getattr__(self, name):
            return getattr(self.context.current, name)
        session = property(lambda s:s.context.current)
    
    objectstore = Objectstore(create_session)


#
# declarative column declaration - this is so that we can infer the colname
#
class column(object):
    def __init__(self, coltype, colname=None, foreign_key=None,
                 primary_key=False, *args, **kwargs):
        if isinstance(foreign_key, basestring): 
            foreign_key = ForeignKey(foreign_key)
        
        self.coltype     = coltype
        self.colname     = colname
        self.foreign_key = foreign_key
        self.primary_key = primary_key
        self.kwargs      = kwargs
        self.args        = args

#
# declarative relationship declaration
#
class relationship(object):
    def __init__(self, classname, colname=None, backref=None, private=False,
                 lazy=True, uselist=True, secondary=None, order_by=False):
        self.classname = classname
        self.colname   = colname
        self.backref   = backref
        self.private   = private
        self.lazy      = lazy
        self.uselist   = uselist
        self.secondary = secondary
        self.order_by  = order_by
    
    def process(self, klass, propname, relations):
        relclass = ActiveMapperMeta.classes[self.classname]
        
        if isinstance(self.order_by, str):
            self.order_by = [ self.order_by ]
        
        if isinstance(self.order_by, list):
            for itemno in range(len(self.order_by)):
                if isinstance(self.order_by[itemno], str):
                    self.order_by[itemno] = \
                        getattr(relclass.c, self.order_by[itemno])
        
        backref = self.create_backref(klass)
        relations[propname] = relation(relclass.mapper,
                                       secondary=self.secondary,
                                       backref=backref, 
                                       private=self.private, 
                                       lazy=self.lazy, 
                                       uselist=self.uselist,
                                       order_by=self.order_by)
    
    def create_backref(self, klass):
        if self.backref is None:
            return None
        
        relclass = ActiveMapperMeta.classes[self.classname]
        
        if klass.__name__ == self.classname:
            br_fkey = getattr(relclass.c, self.colname)
        else:
            br_fkey = None
        
        return create_backref(self.backref, foreignkey=br_fkey)


class one_to_many(relationship):
    def __init__(self, classname, colname=None, backref=None, private=False,
                 lazy=True, order_by=False):
        relationship.__init__(self, classname, colname, backref, private, 
                              lazy, uselist=True, order_by=order_by)


class one_to_one(relationship):
    def __init__(self, classname, colname=None, backref=None, private=False,
                 lazy=True, order_by=False):
        relationship.__init__(self, classname, colname, backref, private, 
                              lazy, uselist=False, order_by=order_by)
    
    def create_backref(self, klass):
        if self.backref is None:
            return None
        
        relclass = ActiveMapperMeta.classes[self.classname]
        
        if klass.__name__ == self.classname:
            br_fkey = getattr(relclass.c, self.colname)
        else:
            br_fkey = None
        
        return create_backref(self.backref, foreignkey=br_fkey, uselist=False)


class many_to_many(relationship):
    def __init__(self, classname, secondary, backref=None, lazy=True,
                 order_by=False):
        relationship.__init__(self, classname, None, backref, False, lazy,
                              uselist=True, secondary=secondary,
                              order_by=order_by)


# 
# SQLAlchemy metaclass and superclass that can be used to do SQLAlchemy 
# mapping in a declarative way, along with a function to process the 
# relationships between dependent objects as they come in, without blowing
# up if the classes aren't specified in a proper order
# 

__deferred_classes__ = {}
__processed_classes__ = {}
def process_relationships(klass, was_deferred=False):
    # first, we loop through all of the relationships defined on the
    # class, and make sure that the related class already has been
    # completely processed and defer processing if it has not
    defer = False
    for propname, reldesc in klass.relations.items():
        found = (reldesc.classname == klass.__name__ or reldesc.classname in __processed_classes__)
        if not found:
            defer = True
            break
    
    # next, we loop through all the columns looking for foreign keys
    # and make sure that we can find the related tables (they do not 
    # have to be processed yet, just defined), and we defer if we are 
    # not able to find any of the related tables
    if not defer:
        for col in klass.columns:
            if col.foreign_key is not None:
                found = False
                table_name = col.foreign_key._colspec.rsplit('.', 1)[0]
                for other_klass in ActiveMapperMeta.classes.values():
                    if other_klass.table.fullname.lower() == table_name.lower():
                        found = True
                        
                if not found:
                    defer = True
                    break

    if defer and not was_deferred:
        __deferred_classes__[klass.__name__] = klass
        
    # if we are able to find all related and referred to tables, then
    # we can go ahead and assign the relationships to the class
    if not defer:
        relations = {}
        for propname, reldesc in klass.relations.items():
            reldesc.process(klass, propname, relations)
        
        class_mapper(klass).add_properties(relations)
        if klass.__name__ in __deferred_classes__: 
            del __deferred_classes__[klass.__name__]
        __processed_classes__[klass.__name__] = klass
    
    # finally, loop through the deferred classes and attempt to process
    # relationships for them
    if not was_deferred:
        # loop through the list of deferred classes, processing the
        # relationships, until we can make no more progress
        last_count = len(__deferred_classes__) + 1
        while last_count > len(__deferred_classes__):
            last_count = len(__deferred_classes__)
            deferred = __deferred_classes__.copy()
            for deferred_class in deferred.values():
                process_relationships(deferred_class, was_deferred=True)


class ActiveMapperMeta(type):
    classes = {}
    metadatas = util.Set()
    def __init__(cls, clsname, bases, dict):
        table_name = clsname.lower()
        columns    = []
        relations  = {}
        autoload   = False
        _metadata  = getattr(sys.modules[cls.__module__], 
                             "__metadata__", metadata)
        version_id_col = None
        version_id_col_object = None

        if 'mapping' in dict:
            found_pk = False
            
            members = inspect.getmembers(dict.get('mapping'))
            for name, value in members:
                if name == '__table__':
                    table_name = value
                    continue
                
                if '__metadata__' == name:
                    _metadata= value
                    continue
                
                if '__autoload__' == name:
                    autoload = True
                    continue
                
                if '__version_id_col__' == name:
                    version_id_col = value

                if name.startswith('__'): continue
                
                if isinstance(value, column):
                    if value.primary_key == True: found_pk = True
                        
                    if value.foreign_key:
                        col = Column(value.colname or name, 
                                     value.coltype,
                                     value.foreign_key, 
                                     primary_key=value.primary_key,
                                     *value.args, **value.kwargs)
                    else:
                        col = Column(value.colname or name,
                                     value.coltype,
                                     primary_key=value.primary_key,
                                     *value.args, **value.kwargs)
                    columns.append(col)
                    continue
                
                if isinstance(value, relationship):
                    relations[name] = value
            
            if not found_pk and not autoload:
                col = Column('id', Integer, primary_key=True)
                cls.mapping.id = col
                columns.append(col)
            
            assert _metadata is not None, "No MetaData specified"
            
            ActiveMapperMeta.metadatas.add(_metadata)
            
            if not autoload:
                cls.table = Table(table_name, _metadata, *columns)
                cls.columns = columns
            else:
                cls.table = Table(table_name, _metadata, autoload=True)
                cls.columns = cls.table._columns
            
            # check for inheritence
            if version_id_col is not None:
                version_id_col_object = getattr(cls.table.c, version_id_col, None)
                assert(version_id_col_object is not None, "version_id_col (%s) does not exist." % version_id_col)

            if hasattr(bases[0], "mapping"):
                cls._base_mapper= bases[0].mapper
                assign_mapper(objectstore.context, cls, cls.table, 
                              inherits=cls._base_mapper, version_id_col=version_id_col_object)
            else:
                assign_mapper(objectstore.context, cls, cls.table, version_id_col=version_id_col_object)
            cls.relations = relations
            ActiveMapperMeta.classes[clsname] = cls
            
            process_relationships(cls)
        
        super(ActiveMapperMeta, cls).__init__(clsname, bases, dict)



class ActiveMapper(object):
    __metaclass__ = ActiveMapperMeta
    
    def set(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)


#
# a utility function to create all tables for all ActiveMapper classes
#

def create_tables():
    for metadata in ActiveMapperMeta.metadatas:
        metadata.create_all()

def drop_tables():
    for metadata in ActiveMapperMeta.metadatas:
        metadata.drop_all()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.