[Modeling-cvs] ProjectModeling/Modeling dynamic.py,NONE,1.1 ClassDescription.py,1.14,1.15 CustomObje
Status: Abandoned
Brought to you by:
sbigaret
From: <sbi...@us...> - 2004-02-16 20:09:24
|
Update of /cvsroot/modeling/ProjectModeling/Modeling In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19962/Modeling Modified Files: ClassDescription.py CustomObject.py Database.py EditingContext.py Entity.py SQLExpression.py SnapshotsHandling.py utils.py Added Files: dynamic.py Log Message: Integrated patch #814055: Dynamic creation of packages/modules/classes --- NEW FILE: dynamic.py --- #! /usr/bin/env python # -*- coding: iso-8859-1 -*- #----------------------------------------------------------------------------- # # Modeling Framework: an Object-Relational Bridge for python # (c) 2001, 2002, 2003 Sébastien Bigaret # # This file is part of the Modeling Framework. # # The Modeling Framework is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as published # by the Free Software Foundation; either version 2 of the License, or (at # your option) any later version. # # The Modeling Framework is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License along # with the Modeling Framework; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # #----------------------------------------------------------------------------- """ Documentation not written yet --see doc/README.dynamic.txt for details. """ import code, new, sys from Modeling.CustomObject import CustomObject from Modeling.ModelSet import defaultModelSet from Modeling.utils import capitalizeFirstLetter def function_for_code(c, func_name): c+='\nfunc='+func_name+'\n' exec(c) return func def instance_method(aClass, c, func_name): func=function_for_code(c, func_name) meth=new.instancemethod(func, None, aClass) return meth def init_code(entity, init=None): """ init: the original __init__, if available """ c="def __init__(self, **kw):\n" for p in entity.classProperties(): c+=" self._"+p.name()+"=" if hasattr(p,'isToMany'): # rel if p.isToMany(): c+="()" else: c+="None" else: c+=repr(p.defaultValue()) c+="\n" c+=""" for k,v in kw.items(): self.takeValueForKey(v, k) """ if init: c+=" apply(self.%s, (), kw)"%init return c def add_init(aClass, entity): "Adds to the class the method __init__() suitable for entity" c=init_code(entity) m=instance_method(aClass, c, "__init__") setattr(aClass,'__init__',m) def define_entityName(aClass, entity): c="""def entityName(self): "Used by the framework to link this object to its entity" return "%s" # do not change """%entity.name() return c def add_entityName(aClass, entity): "Adds to the new class the method entityName() suitable for entity" c=define_entityName(aClass, entity) m=instance_method(aClass, c, "entityName") setattr(aClass,'entityName',m) def add_getters(aClass, entity): "Adds getters to aClass, one for each entity.classProperties()" for p in entity.classProperties(): add_getter(aClass, p) def add_setters(aClass, entity): "Adds setters to aClass, one for each entity.classProperties()" for p in entity.classProperties(): add_setter(aClass, p) def getter_code(prop): func_name="get"+capitalizeFirstLetter(prop.name()) c='def %s(self):\n self.willRead()\n'%func_name c+=" return self._"+prop.name() return func_name, c def add_getter(aClass, prop): "Builds and adds to aClass the getter for property prop" func_name, c=getter_code(prop) m=instance_method(aClass, c, func_name) setattr(aClass, m.__name__, m) def setters_code(prop): "returns: ( (name, code_string), ... )" names_n_funcs=[] part_func_name=capitalizeFirstLetter(prop.name()) if hasattr(prop,'isToMany') and prop.isToMany(): func_name="addTo"+part_func_name c='''def %(func_name)s(self, obj): if obj not in self._%(name)s: self.willChange() _list=list(self._%(name)s) _list.append(obj) self._%(name)s=tuple(_list) '''%{'func_name': func_name, 'name': prop.name()} names_n_funcs.append( (func_name, c) ) func_name="removeFrom"+part_func_name c='''def %(func_name)s(self, obj): self.willChange() _list=list(self._%(name)s) _list.remove(obj) self._%(name)s=tuple(_list) '''%{'func_name': func_name, 'name': prop.name()} names_n_funcs.append( (func_name, c) ) func_name="set"+part_func_name c='def %s(self, obj):\n self.willChange()\n'%func_name c+=" self._"+prop.name()+"=obj" names_n_funcs.append( (func_name, c) ) return names_n_funcs def add_setter(aClass, prop): "Builds and adds to aClass the setter for property prop" names_n_funcs=setters_code(prop) for func_name, c in names_n_funcs: m=instance_method(aClass, c, func_name) setattr(aClass, m.__name__, m) def add_properties(aClass, entity): for p in entity.classProperties(): #print 'defining prop: ', p.name() part_func_name=capitalizeFirstLetter(p.name()) prop=property(getattr(aClass, 'get'+part_func_name), getattr(aClass, 'set'+part_func_name), None) setattr(aClass, p.name(), prop) def build(model, define_properties=0): module_name=model.packageName() classes={} modules={} for e in model.entities(): c=new.classobj(e.name(), (CustomObject,), {}) m=new.module(e.name()) setattr(m, e.name(),c) classes[e.name()]=c modules[e.name()]=m m.__name__='AB.'+e.name() # Not required? but in accordance to observations add_init(c, e) add_entityName(c, e) add_getters(c, e) add_setters(c, e) if define_properties: add_properties(c, e) p=new.module(module_name) #m.Book=classes['Book'] import sys for name,m in modules.items(): setattr(p,name,m) sys.modules[module_name]=p # the following is needed if we want to "from AB.Book import Book" for name,m in modules.items(): sys.modules[module_name+'.'+name]=m ## ## Examples of use follow ## if __name__ == "__main__": from Modeling import ModelSet, Model model_name="AuthorBooks" if ModelSet.defaultModelSet().modelNamed(model_name) is None: import os model=Model.searchModel(model_name, 'xmlmodels', verbose=1) if not model: raise RuntimeError, "Couldn't load model '%s'"%model_name else: ModelSet.defaultModelSet().addModel(model) build(model) from Modeling.EditingContext import EditingContext ec=EditingContext() print [b.getTitle() for b in ec.fetch('Book')] from AuthorBooks import Book from AuthorBooks.Book import Book print Book b=Book(title='mon titre') print repr(b.getTitle()) sys.exit(0) ######################################################################## # metaclass # def info(classdict, msg): if classdict.get('mdl_verbose_metaclass', None): sys.stderr.write("[CustomObjectMeta] "+msg+'\n') def checkEntityName(classname, bases, classdict): entityName=classdict.get('entityName', None) if entityName is None: info(classdict, 'entityName is not present: searching base classes') for b in bases: if b==CustomObject: continue; entityName=getattr(b, 'entityName',None) if entityName: info(classdict, 'Found in %s'%b.__name__) if entityName is None: info(classdict, 'entityName is not present: using default: %s'%classname) entityName=classname if not callable(entityName): classdict['entityName']=lambda self, n=entityName: n else: entityName=entityName.im_func(None) return entityName def addCustomObject(bases): from Modeling.CustomObject import CustomObject if CustomObject not in bases: bases=list(bases) bases.append(CustomObject) bases=tuple(bases) return bases def check_oldinit(classname, oldinit, entity): "Check that the already defined __init__ can be called without any arguments" import inspect args, varargs, varkw, defaults=inspect.getargspec(oldinit) if len(args)-len(defaults)>1: raise RuntimeError,'%s.__init__() cannot be called without arguments'%classname # to be continued: on veut pouvoir appeler init() avec les bons arguments, # tout en récupérant ceux qui peuvent nous servir (les attributs) # e.g. init(self, attr1='t') ou init(self, attr1='x', non_attr='xx') etc. def define_init(entity, classname, classdict): oldinit=classdict.get('__init__', None) if oldinit: classdict['__original_init__']=oldinit check_oldinit(classname, oldinit, entity) c=init_code(entity, oldinit) init=function_for_code(c, '__init__') classdict['__init__']=init def define_getter(prop, classdict): func_name, c=getter_code(prop) info(classdict, "adding getter: %s"%func_name) getter=function_for_code(c, func_name) classdict[func_name]=getter def define_getters(entity, classname, classdict): info(classdict, "setting getters") for p in entity.classProperties(): define_getter(p, classdict) def define_setter(prop, classdict): names_and_funcs=setters_code(prop) for func_name, c in names_and_funcs: info(classdict, "adding setter: %s"%func_name) setter=function_for_code(c, func_name) classdict[func_name]=setter def define_setters(entity, classname, classdict): info(classdict, "setting setters") for p in entity.classProperties(): define_setter(p, classdict) def define_properties(entity, classname, classdict): #info(classdict, "defining properties for class %s"%classname) for p in entity.classProperties(): info(classdict, "adding properties '%s' for class %s"%(p.name(),classname)) part_func_name=capitalizeFirstLetter(p.name()) prop=property(classdict['get'+part_func_name], classdict['set'+part_func_name], None) classdict[p.name()]=prop try: class A(type): pass metaclass_available=1 del A except TypeError: metaclass_available=0 class EntityNotFound(RuntimeError): pass if metaclass_available: class CustomObjectMeta(type): def __new__(meta,classname,bases,classdict): info(classdict, 'meta: %s'%meta) info(classdict, 'classname: '+classname) info(classdict, 'bases: %s'%(bases,)) info(classdict, 'classdict: %s'%classdict) entityName=checkEntityName(classname, bases, classdict) bases=addCustomObject(bases) from Modeling.ModelSet import defaultModelSet entity=defaultModelSet().entityNamed(entityName) if entity is None: raise EntityNotFound, 'Unable to initialize class %s: entity %s not found'%(classname, entityName) else: define_init(entity, classname, classdict) define_getters(entity, classname, classdict) define_setters(entity, classname, classdict) if classdict.get('mdl_define_properties', None): define_properties(entity, classname, classdict) return super(CustomObjectMeta,meta).__new__(meta,classname, bases,classdict) def build_with_metaclass(model, define_properties=0, verbose=0): module_name=model.packageName() classes={} modules={} for e in model.entities(): c=CustomObjectMeta(e.className(), (), {'mdl_verbose_metaclass': verbose, 'mdl_define_properties': define_properties}) m=new.module(e.name()) setattr(m, e.name(),c) classes[e.name()]=c modules[e.name()]=m m.__name__=model.packageName()+'.'+e.name() # pas requis? mais conforme p=new.module(module_name) #m.Book=classes['Book'] import sys for name,m in modules.items(): setattr(p,name,m) sys.modules[module_name]=p # the following is needed if we want to "from AuthorBooks.Book import Book" for name,m in modules.items(): sys.modules[module_name+'.'+name]=m else: def build_with_metaclass(model, define_properties=0, verbose=0): raise NotImplementedError, "metaclass are not available" ## ## Two examples of use follow ## if __name__ == "__main__2": from Modeling import ModelSet, Model model_name="AuthorBooks" if ModelSet.defaultModelSet().modelNamed(model_name) is None: import os mydir = '.' model=Model.searchModel(model_name, mydir, verbose=1) if not model: raise RuntimeError, "Couldn't load model '%s'"%model_name else: ModelSet.defaultModelSet().addModel(model) class Book: __metaclass__=CustomObjectMeta mdl_verbose_metaclass=1 mdl_define_properties=1 entityName='Book' #def entityName(self): # return 'Book' #def __init__(self): # print 'PPP' def willRead(self): print '[willRead]', def willChange(self): print '[willChange]', def _getTitle(self): print '[_getTitle()]', return self._title def _setTitle(self, title): print '[_setTitle()]', self._title=title #__metaclass__=CustomObjectMeta #c=type('Writer', (), {'__metaclass__': CustomObjectMeta, # 'mdl_verbose_metaclass': 1, # 'mdl_define_properties': 1}) Writer=CustomObjectMeta('Writer', (), {'mdl_verbose_metaclass': 1, 'mdl_define_properties': 0}) #Book=CustomObjectMeta('Book', (), {'mdl_verbose_metaclass': 1}) print Writer, Writer.__bases__ from Modeling.EditingContext import EditingContext ec=EditingContext() print Book.__bases__ b=Book(title='glop') ec.insert(b) print b.entityName() print b._title b.setTitle('title test') print b.getTitle() print ec.allInsertedObjects(), b print 'trying properties' print b.title print '## KVC' print 'storedValue ',b.storedValueForKey('title') print 'takestored ',b.takeStoredValueForKey('takeStoredValueForKey','title') print 'value ',b.valueForKey('title') print 'takeValue ',b.takeValueForKey('takeStoredValueForKey','title') print 'title: ', b.title sys.exit(0) if __name__ == "__main__": from Modeling import ModelSet, Model model_name="AuthorBooks" if ModelSet.defaultModelSet().modelNamed(model_name) is None: import os mydir = '.' model=Model.searchModel(model_name, mydir, verbose=1) if not model: raise RuntimeError, "Couldn't load model '%s'"%model_name else: ModelSet.defaultModelSet().addModel(model) build_with_metaclass(model, define_properties=0) from Modeling.EditingContext import EditingContext ec=EditingContext() print [b.getTitle() for b in ec.fetch('Book')] from AuthorBooks import Book from AuthorBooks.Book import Book print Book b=Book(title='mon titre') print repr(b.getTitle()), b.title sys.exit(0) Index: ClassDescription.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/ClassDescription.py,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** ClassDescription.py 14 Feb 2004 18:30:33 -0000 1.14 --- ClassDescription.py 16 Feb 2004 20:01:06 -0000 1.15 *************** *** 155,159 **** ## ClassDescription ## ! class ClassDescription: """ This class is an *abstract* class ; all methods defined in --- 155,160 ---- ## ClassDescription ## ! from Modeling.utils import base_object ! class ClassDescription(base_object): """ This class is an *abstract* class ; all methods defined in Index: CustomObject.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/CustomObject.py,v retrieving revision 1.19 retrieving revision 1.20 diff -C2 -d -r1.19 -r1.20 *** CustomObject.py 14 Feb 2004 18:27:03 -0000 1.19 --- CustomObject.py 16 Feb 2004 20:01:06 -0000 1.20 *************** *** 91,96 **** return ec.arrayFaultWithSourceGlobalID(self.sourceGlobalID, self.key, ec) ! ! class CustomObject(RelationshipManipulation, DatabaseObject): """ --- 91,97 ---- return ec.arrayFaultWithSourceGlobalID(self.sourceGlobalID, self.key, ec) ! ! from Modeling.utils import base_object ! class CustomObject(base_object, RelationshipManipulation, DatabaseObject): """ Index: Database.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/Database.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** Database.py 14 Feb 2004 18:27:03 -0000 1.9 --- Database.py 16 Feb 2004 20:01:06 -0000 1.10 *************** *** 113,117 **** unlock() ! class Database: """ Key features: --- 113,118 ---- unlock() ! from Modeling.utils import base_object ! class Database(base_object): """ Key features: Index: EditingContext.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/EditingContext.py,v retrieving revision 1.31 retrieving revision 1.32 diff -C2 -d -r1.31 -r1.32 *** EditingContext.py 14 Feb 2004 18:27:03 -0000 1.31 --- EditingContext.py 16 Feb 2004 20:01:06 -0000 1.32 *************** *** 124,128 **** ## recordObject(), deleteObject(), objectWillChange()] ! class EditingContext(ObjectStore): # ??? """ EditingContext: an in-memory world/graph of objects, with the ability --- 124,129 ---- ## recordObject(), deleteObject(), objectWillChange()] ! from Modeling.utils import base_object ! class EditingContext(base_object, ObjectStore): # ??? """ EditingContext: an in-memory world/graph of objects, with the ability *************** *** 149,153 **** # see: __init__() ######## ! class UniquingTable: """ The uniquing table - encapsulate the dictionary structure --- 150,154 ---- # see: __init__() ######## ! class UniquingTable(base_object): """ The uniquing table - encapsulate the dictionary structure Index: Entity.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/Entity.py,v retrieving revision 1.20 retrieving revision 1.21 diff -C2 -d -r1.20 -r1.21 *** Entity.py 14 Feb 2004 18:27:03 -0000 1.20 --- Entity.py 16 Feb 2004 20:01:06 -0000 1.21 *************** *** 118,122 **** from Persistent import Persistent ! class Entity(XMLCapability, Persistent, KeyValueCoding): """ Describes an entity --- 118,123 ---- from Persistent import Persistent ! from Modeling.utils import base_object ! class Entity(base_object, XMLCapability, Persistent, KeyValueCoding): """ Describes an entity Index: SQLExpression.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/SQLExpression.py,v retrieving revision 1.27 retrieving revision 1.28 diff -C2 -d -r1.27 -r1.28 *** SQLExpression.py 14 Feb 2004 18:27:04 -0000 1.27 --- SQLExpression.py 16 Feb 2004 20:01:06 -0000 1.28 *************** *** 85,89 **** pass ! class SQLExpression: """ """ --- 85,90 ---- pass ! from Modeling.utils import base_object ! class SQLExpression(base_object): """ """ Index: SnapshotsHandling.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/SnapshotsHandling.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** SnapshotsHandling.py 14 Feb 2004 18:27:04 -0000 1.6 --- SnapshotsHandling.py 16 Feb 2004 20:01:06 -0000 1.7 *************** *** 34,38 **** DistantPastTimeInterval = 0 ! class SnapshotsTable: """ __TBD --- 34,39 ---- DistantPastTimeInterval = 0 ! from Modeling.utils import base_object ! class SnapshotsTable(base_object): """ __TBD Index: utils.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/utils.py,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** utils.py 14 Feb 2004 18:27:04 -0000 1.18 --- utils.py 16 Feb 2004 20:01:06 -0000 1.19 *************** *** 39,42 **** --- 39,50 ---- from time import strftime + import types + try: + base_object = types.ObjectType + newclass = 1 + except AttributeError: + class base_object : pass + newclass = 0 + _validFirstLetter = "_"+string.letters |