[SQL-CVS] r583 - trunk/SQLObject/sqlobject
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
From: <sub...@co...> - 2005-02-09 05:40:25
|
Author: ianb Date: 2005-02-09 05:40:19 +0000 (Wed, 09 Feb 2005) New Revision: 583 Modified: trunk/SQLObject/sqlobject/main.py Log: Removed SQLObjectMeta and use DeclarativeMeta, with all the logic in __classinit__. __classinit__ looks almost exactly like DeclarativeMeta.__new__, except newClass renamed to cls and d to new_attrs Modified: trunk/SQLObject/sqlobject/main.py =================================================================== --- trunk/SQLObject/sqlobject/main.py 2005-02-09 05:27:03 UTC (rev 582) +++ trunk/SQLObject/sqlobject/main.py 2005-02-09 05:40:19 UTC (rev 583) @@ -30,6 +30,7 @@ import joins import index import classregistry +import declarative import sys if sys.version_info[:3] < (2, 2, 0): @@ -42,167 +43,6 @@ True, False = 1==1, 0==1 -# This is the metaclass. It essentially takes a dictionary -# of all the attributes (and thus methods) defined in the -# class definition. It futzes with them, and spits out the -# new class definition. -class MetaSQLObject(type): - - def __new__(cls, className, bases, d): - - # We fix up the columns here -- replacing any strings with - # simply-contructed Col objects, and searching the class - # variables for instances of Col objects (which get put into - # the _columns instance variable and deleted). - columns = [] - for column in d.get('_columns', []): - if isinstance(column, str): - column = col.Col(column) - columns.append(column) - if columns: - d['_columns'] = columns - - implicitColumns = [] - implicitJoins = [] - implicitIndexes = [] - for attr, value in d.items(): - if isinstance(value, col.Col): - value.name = attr - implicitColumns.append(value) - del d[attr] - continue - if isinstance(value, joins.Join): - value.joinMethodName = attr - implicitJoins.append(value) - del d[attr] - continue - if isinstance(value, index.DatabaseIndex): - value.setName(attr) - implicitIndexes.append(value) - del d[attr] - continue - - # We *don't* want to inherit _table, so we make sure it - # is defined in this class (not a superclass) - if not d.has_key('_table'): - d['_table'] = None - - - if d.has_key('_connection'): - connection = d['_connection'] - del d['_connection'] - assert not d.has_key('connection') - elif d.has_key('connection'): - connection = d['connection'] - del d['connection'] - else: - connection = None - - # We actually create the class. - newClass = type.__new__(cls, className, bases, d) - newClass._SO_finishedClassCreation = False - - # We append to _columns, but we don't want to change the - # superclass's _columns list, so we make a copy if necessary - if not d.has_key('_columns'): - newClass._columns = newClass._columns[:] - newClass._columns.extend(implicitColumns) - if not d.has_key('_joins'): - newClass._joins = newClass._joins[:] - newClass._joins.extend(implicitJoins) - if not d.has_key('_indexes'): - newClass._indexes = newClass._indexes[:] - newClass._indexes.extend(implicitIndexes) - - ###################################################### - # Set some attributes to their defaults, if necessary. - # First we get the connection: - if not connection and not getattr(newClass, '_connection', None): - mod = sys.modules[newClass.__module__] - # See if there's a __connection__ global in - # the module, use it if there is. - if hasattr(mod, '__connection__'): - connection = mod.__connection__ - - if connection or not hasattr(newClass, '_connection'): - newClass.setConnection(connection) - - # The style object tells how to map between Python - # identifiers and Database identifiers: - if not newClass._style: - if newClass._connection and newClass._connection.style: - newClass._style = newClass._connection.style - else: - newClass._style = styles.defaultStyle - - # plainSetters are columns that haven't been overridden by the - # user, so we can contact the database directly to set them. - # Note that these can't set these in the SQLObject class - # itself, because they specific to this subclass of SQLObject, - # and cannot be shared among classes. - newClass._SO_plainSetters = {} - newClass._SO_plainGetters = {} - newClass._SO_plainForeignSetters = {} - newClass._SO_plainForeignGetters = {} - newClass._SO_plainJoinGetters = {} - newClass._SO_plainJoinAdders = {} - newClass._SO_plainJoinRemovers = {} - - # This is a dictionary of columnName: columnObject - newClass._SO_columnDict = {} - newClass._SO_columns = [] - - # If _table isn't given, use style default - if not newClass._table: - newClass._table = newClass._style.pythonClassToDBTable(className) - - # If _idName isn't given, use style default - if not d.has_key('_idName'): - newClass._idName = newClass._style.idForTable(newClass._table) - - # We use the magic "q" attribute for accessing lazy - # SQL where-clause generation. See the sql module for - # more. - newClass.q = sqlbuilder.SQLObjectTable(newClass) - - # We have to check if there are columns in the inherited - # _columns where the attribute has been set to None in this - # class. If so, then we need to remove that column from - # _columns. - for column in newClass._columns[:]: - if d.has_key(column.name) and d[column.name] is None: - newClass._columns.remove(column) - - for column in newClass._columns: - newClass.addColumn(column) - if newClass._fromDatabase: - newClass.addColumnsFromDatabase() - - ######################################## - # Now we do the joins: - - # We keep track of the different joins by index, - # putting them in this list. - newClass._SO_joinList = [] - newClass._SO_joinDict = {} - - for join in newClass._joins: - newClass.addJoin(join) - - # We don't setup the properties until we're finished with the - # batch adding of all the columns... - newClass._SO_finishedClassCreation = True - makeProperties(newClass) - - newClass._SO_indexList = [] - for idx in newClass._indexes: - newClass.addIndex(idx) - - classregistry.registry(newClass._registry).addClass(newClass) - - # And return the class - return newClass - def makeProperties(obj): """ This function takes a dictionary of methods and finds @@ -302,7 +142,7 @@ # MetaSQLObject. class SQLObject(object): - __metaclass__ = MetaSQLObject + __metaclass__ = declarative.DeclarativeMeta # When an object is being created, it has an instance # variable _SO_creating, which is true. This way all the @@ -352,6 +192,155 @@ # aren't using integer IDs _idType = int + def __classinit__(cls, new_attrs): + implicitColumns = [] + implicitJoins = [] + implicitIndexes = [] + for attr, value in new_attrs.items(): + if isinstance(value, col.Col): + value.name = attr + implicitColumns.append(value) + delattr(cls, attr) + continue + if isinstance(value, joins.Join): + value.joinMethodName = attr + implicitJoins.append(value) + delattr(cls, attr) + continue + if isinstance(value, index.DatabaseIndex): + value.setName(attr) + implicitIndexes.append(value) + delattr(cls, attr) + continue + + # We *don't* want to inherit _table, so we make sure it + # is defined in this class (not a superclass) + if not new_attrs.has_key('_table'): + cls._table = None + + if new_attrs.has_key('_connection'): + connection = new_attrs['_connection'] + del cls._connection + assert not new_attrs.has_key('connection') + elif new_attrs.has_key('connection'): + connection = new_attrs['connection'] + del cls.connection + else: + connection = None + + cls._SO_finishedClassCreation = False + + # We fix up the columns here -- replacing any strings with + # simply-contructed Col objects, and searching the class + # variables for instances of Col objects (which get put into + # the _columns instance variable and deleted). + columns = [] + for column in new_attrs.get('_columns', []): + if isinstance(column, str): + column = col.Col(column) + columns.append(column) + if columns: + cls._columns = columns + + # We append to _columns, but we don't want to change the + # superclass's _columns list, so we make a copy if necessary + if not new_attrs.has_key('_columns'): + cls._columns = cls._columns[:] + cls._columns.extend(implicitColumns) + if not new_attrs.has_key('_joins'): + cls._joins = cls._joins[:] + cls._joins.extend(implicitJoins) + if not new_attrs.has_key('_indexes'): + cls._indexes = cls._indexes[:] + cls._indexes.extend(implicitIndexes) + + ###################################################### + # Set some attributes to their defaults, if necessary. + # First we get the connection: + if not connection and not getattr(cls, '_connection', None): + mod = sys.modules[cls.__module__] + # See if there's a __connection__ global in + # the module, use it if there is. + if hasattr(mod, '__connection__'): + connection = mod.__connection__ + + if connection or not hasattr(cls, '_connection'): + cls.setConnection(connection) + + # The style object tells how to map between Python + # identifiers and Database identifiers: + if not cls._style: + if cls._connection and cls._connection.style: + cls._style = cls._connection.style + else: + cls._style = styles.defaultStyle + + # plainSetters are columns that haven't been overridden by the + # user, so we can contact the database directly to set them. + # Note that these can't set these in the SQLObject class + # itself, because they specific to this subclass of SQLObject, + # and cannot be shared among classes. + cls._SO_plainSetters = {} + cls._SO_plainGetters = {} + cls._SO_plainForeignSetters = {} + cls._SO_plainForeignGetters = {} + cls._SO_plainJoinGetters = {} + cls._SO_plainJoinAdders = {} + cls._SO_plainJoinRemovers = {} + + # This is a dictionary of columnName: columnObject + cls._SO_columnDict = {} + cls._SO_columns = [] + + # If _table isn't given, use style default + if not cls._table: + cls._table = cls._style.pythonClassToDBTable(cls.__name__) + + # If _idName isn't given, use style default + if not new_attrs.has_key('_idName'): + cls._idName = cls._style.idForTable(cls._table) + + # We use the magic "q" attribute for accessing lazy + # SQL where-clause generation. See the sql module for + # more. + cls.q = sqlbuilder.SQLObjectTable(cls) + + # We have to check if there are columns in the inherited + # _columns where the attribute has been set to None in this + # class. If so, then we need to remove that column from + # _columns. + for column in cls._columns[:]: + if (new_attrs.has_key(column.name) + and new_attrs[column.name] is None): + cls._columns.remove(column) + + for column in cls._columns: + cls.addColumn(column) + if cls._fromDatabase: + cls.addColumnsFromDatabase() + + ######################################## + # Now we do the joins: + + # We keep track of the different joins by index, + # putting them in this list. + cls._SO_joinList = [] + cls._SO_joinDict = {} + + for join in cls._joins: + cls.addJoin(join) + + # We don't setup the properties until we're finished with the + # batch adding of all the columns... + cls._SO_finishedClassCreation = True + makeProperties(cls) + + cls._SO_indexList = [] + for idx in cls._indexes: + cls.addIndex(idx) + + classregistry.registry(cls._registry).addClass(cls) + def get(cls, id, connection=None, selectResults=None): assert id is not None, 'None is not a possible id for %s' % cls.__name |