[Modeling-cvs] ProjectModeling/Modeling PyModel.py,1.1,1.2 mems_lib.py,1.1,1.2 Attribute.py,1.14,1.1
Status: Abandoned
Brought to you by:
sbigaret
Update of /cvsroot/modeling/ProjectModeling/Modeling In directory sc8-pr-cvs1:/tmp/cvs-serv7471/ProjectModeling/Modeling Modified Files: Attribute.py CHANGES ClassDescription.py Entity.py Model.py ModelSet.py Relationship.py Added Files: PyModel.py mems_lib.py Log Message: Merged branch brch-0_9pre7-1-PyModel. Introducing: ability to express models in plain python rather than in xml files. See CHANGES for details. Index: Attribute.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/Attribute.py,v retrieving revision 1.14 retrieving revision 1.15 diff -C2 -d -r1.14 -r1.15 *** Attribute.py 31 May 2003 15:09:46 -0000 1.14 --- Attribute.py 7 Jul 2003 14:57:13 -0000 1.15 *************** *** 37,40 **** --- 37,41 ---- from XMLutils import * from Model import ModelError + from KeyValueCoding import KeyValueCoding import Validation from Modeling.utils import capitalizeFirstLetter *************** *** 85,89 **** from Persistent import Persistent ! class Attribute(Persistent, XMLCapability): "Describes an attribute" # + public/private _TBD --- 86,90 ---- from Persistent import Persistent ! class Attribute(Persistent, XMLCapability, KeyValueCoding): "Describes an attribute" # + public/private _TBD *************** *** 124,128 **** self._precision=0 self._scale=0 ! self._type = 'string' # see Modeling.Types for defaults self._width=0 if anEntity: --- 125,129 ---- self._precision=0 self._scale=0 ! self._type = types.StringType.__name__ self._width=0 if anEntity: *************** *** 496,502 **** --- 497,505 ---- if type(value)==types.LongType: if self.type()!=types.IntType.__name__: + #print 'int!=',self.type() _error.addErrorForKey(Validation.TYPE_MISMATCH, self.name()) elif type(value).__name__!=self.type(): _error.addErrorForKey(Validation.TYPE_MISMATCH, self.name()) + #print self.name(),': type(value).__name__: ',type(value).__name__, '!= self.type():',self.type() # String should not exceed width *************** *** 505,508 **** --- 508,512 ---- if len(value)>self.width(): _error.addErrorForKey(Validation.TYPE_MISMATCH, self.name()) + #print 'len(value): %s != self.width(): %s'%(len(value),self.width()) _error.finalize() *************** *** 677,678 **** --- 681,690 ---- raise 'Unimplemented' + ## + ## KeyValueCoding error handling + ## + def handleAssignementForUnboundKey(self, value, key): + if key=='doc': self.setComment(value) + else: + raise AttributeError, key + handleTakeStoredValueForUnboundKey=handleAssignementForUnboundKey Index: CHANGES =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/CHANGES,v retrieving revision 1.120 retrieving revision 1.121 diff -C2 -d -r1.120 -r1.121 *** CHANGES 4 Jul 2003 17:30:47 -0000 1.120 --- CHANGES 7 Jul 2003 14:57:13 -0000 1.121 *************** *** 8,11 **** --- 8,33 ---- -------------------------------------------------------- + + [Merged branch brch-0_9pre7-1-PyModel] + + * Fixed: adaptorModel() could raise instead of returning None when model's + adaptorName is not set + + * Model: added updateModelWithCFG(), loadModel(), searchModel() + ModelSet: DEPRECATED method: updateModelWithCFG() --moved in Model, will + be removed in v0.9.1 + + * Added Modeling.PyModel and Modeling.tests.test_PyModel + + * Added tests/testPackages/StoreEmployees/pymodel_StoreEmployees.py + and updated StoreEmployees/__init__.py: now loads the model from the + PyModel + + * Changed ClassDescription's delete rules: constants DELETE_CASCADE, + DELETE_DENY, DELETE_NULLIFY and DELETE_NOACTION are now strings (were: + integers) + --> Relationship.setDeleteRule() updated to accept old integer values + (backward compatibility) + 0.9-pre-9 (2003/07/04) ---------------------- *************** *** 16,20 **** KeyValueCoding.valuesForKeys(). ! Deprecated methods KeyValueCoding.setValueForKey(), setValueForKeyPath(), setStoredValueForKey() (will be removed in v0.9.1) --- 38,42 ---- KeyValueCoding.valuesForKeys(). ! DEPRECATED methods KeyValueCoding.setValueForKey(), setValueForKeyPath(), setStoredValueForKey() (will be removed in v0.9.1) Index: ClassDescription.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/ClassDescription.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** ClassDescription.py 10 Jan 2003 10:45:44 -0000 1.9 --- ClassDescription.py 7 Jul 2003 14:57:13 -0000 1.10 *************** *** 54,62 **** # Integer constants ! DELETE_NULLIFY=0 ! DELETE_DENY=1 ! DELETE_CASCADE=2 ! DELETE_NOACTION=3 # careful here... # Notification ClassDescriptionNeededForEntityNameNotification='ClassDescriptionNeededForEntityName' --- 54,68 ---- # Integer constants ! DELETE_NULLIFY='nullify' ! DELETE_DENY='deny' ! DELETE_CASCADE='cascade' ! DELETE_NOACTION='noaction' # careful here... + # For backward compatibility, used in Relationship.setDeleteRule() + old_delete_rules= { 0: DELETE_NULLIFY, + 1: DELETE_DENY, + 2: DELETE_CASCADE, + 3: DELETE_NOACTION, + } # Notification ClassDescriptionNeededForEntityNameNotification='ClassDescriptionNeededForEntityName' Index: Entity.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/Entity.py,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** Entity.py 10 Jun 2003 16:31:32 -0000 1.13 --- Entity.py 7 Jul 2003 14:57:13 -0000 1.14 *************** *** 33,36 **** --- 33,37 ---- from XMLutils import * from EntityClassDescription import EntityClassDescription + from KeyValueCoding import KeyValueCoding from Model import ModelError from Attribute import Attribute *************** *** 115,119 **** from Persistent import Persistent ! class Entity(XMLCapability, Persistent): """ Describes an entity --- 116,120 ---- from Persistent import Persistent ! class Entity(XMLCapability, Persistent, KeyValueCoding): """ Describes an entity *************** *** 1414,1419 **** ## ! ## Validation of an Entity ! ## - ## --- 1415,1429 ---- ## ! ## KeyValueCoding error handling ! ## ! def handleAssignementForUnboundKey(self, value, key): ! if key=='doc': self.setComment(value) ! else: ! raise AttributeError, key ! handleTakeStoredValueForUnboundKey=handleAssignementForUnboundKey ! ! ## ! ## TBD Validation of an Entity ! ## ## Index: Model.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/Model.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** Model.py 27 May 2003 19:37:28 -0000 1.5 --- Model.py 7 Jul 2003 14:57:13 -0000 1.6 *************** *** 40,44 **** from utils import isaValidName from XMLutils import * ! import types --- 40,44 ---- from utils import isaValidName from XMLutils import * ! from KeyValueCoding import KeyValueCoding import types *************** *** 49,53 **** from Persistent import Persistent ! class Model(Persistent, XMLCapability): "Describes a model" _is_a_model = 1 --- 49,248 ---- from Persistent import Persistent ! def updateModelWithCFG(model, cfg_path=None): ! """ ! Updates the model's connection dictionary and adaptorName with the values ! in file 'cfg_path'. If cfg_path is omitted or None, the value stored ! in the environment variable MDL_DB_CONNECTIONS_CFG is used instead. ! ! A sample configuration file is like:: ! ! [DEFAULT] ! host: localhost ! ! [ModelName_1] ! user: user_1 ! password: pwd_1 ! ! [ModelName_2] ! adaptor: MySQL ! user: user_2 ! password: pwd_2 ! ! The special field 'adaptor', if present, changes the adaptorName of the ! model. ! ! Raises IOError if file 'cfg_path' cannot be found. ! ! See also: ModelSet.addModel() ! ! Parameters: ! ! model -- the model whose conn.dict. should be updated ! ! cfg_path -- the full path to the configuration file, or if omitted or ! None, defaults to the value stored in the env. variable ! MDL_DB_CONNECTIONS_CFG ! ! """ ! import os ! if cfg_path is None: ! cfg_path=os.environ.get('MDL_DB_CONNECTIONS_CFG') ! if cfg_path is None: ! return ! ! from ConfigParser import ConfigParser ! defaults=model.connectionDictionary() ! cp=ConfigParser() ! try: ! cp.readfp(open(cfg_path)) ! except IOError: ! import traceback, cStringIO, sys ! exc_raised=sys.exc_info()[:2] ! err_msg="Unable to open file '%s' (passed in parameter 'cfg_path' or taken from env. variable MDL_DB_CONNECTIONS_CFG"%cfg_path ! exc=cStringIO.StringIO() ! traceback.print_exception(exc_raised[0], exc_raised[1], None, file=exc) ! err_msg+="\nOriginal exception was: %s"%exc.getvalue() ! raise IOError, err_msg ! ! try: options=cp.options(model.name()) ! except: return ! try: options.remove('adaptor') ! except ValueError: pass ! for key in options: ! defaults[key]=cp.get(model.name(), key) ! model.setConnectionDictionary(defaults) ! try: ! model.setAdaptorName(cp.get(model.name(), 'adaptor')) ! except: ! pass ! ! def loadModel(path): ! """ ! Load a model stored in the file 'path'. The lookup procedure is: ! ! - if path ends with '.py', we assume it is a python module. This module is ! imported and the following attributes are searched within it, in that ! order: ! ! 1. 'model' (either an attribute or a function): if found, we assume ! this is an instance of Modeling.Model.Model and we return the value ! ! 2. 'pymodel' (id.): if found, we assume this is an instance of ! Modeling.PyModel.Model and we return its 'component' attribute ! ! 3. 'model_src' (id.): if found, we assume this is a string and return ! the model build from it with ModelSet.addModelFromXML() ! ! - if path ends with '.xml', we assume this is a xml-file and we return the ! model build with ModelSet.addModelFromXML() ! ! Returns: the loaded Modeling.Model.Model instance ! ! Raises ValueError if file 'path' cannot be handled, or IOError or ! ImportError if the files does no exists, has errors, etc. ! ! Parameter: ! ! path -- the path of the file where the model is stored ! ! """ ! if path[-3:]=='.py': ! import os,imp ! dir,filename=os.path.dirname(path),os.path.basename(path) ! modulename=filename[:-3] ! file=None ! try: ! try: ! file,pathname,description=imp.find_module(modulename, [dir]) ! module=imp.load_module(modulename,file,pathname,description) ! ! if hasattr(module, 'model'): ! model=module.model ! from mems_lib import isinstance ! if callable(model) and not isinstance(model, Model): ! # Model.Model derives from ZODB.Persistent, hence it is callable ! # but it shouldn't be called! ! model=model() ! import PyModel ! if isinstance(model, PyModel.Model): ! model=model.component ! updateModelWithCFG(model) ! return model ! ! if hasattr(module, 'pymodel'): ! pymodel=module.pymodel ! if callable(pymodel): ! pymodel=pymodel() ! updateModelWithCFG(pymodel.component) ! return pymodel.component ! ! if hasattr(module, 'model_src'): ! model_src=module.model_src ! if callable(model_src): ! model_src=model_src() ! from ModelSet import ModelSet ! model=ModelSet().addModelFromXML({'string': model_src}) ! updateModelWithCFG(model) ! return model ! ! raise ValueError, "Couldn't find any of these attributes in python file '%s': model, pymodel (PyModel) or model_src (xml)"%path ! ! except ImportError: ! raise ! except: ! import cStringIO, traceback ! exc=cStringIO.StringIO() ! traceback.print_exc(file=exc) ! raise ValueError, 'Unable to handle python file %s\nReason: exception raised:\n%s'%(path,exc.getvalue()) ! ! finally: ! if file: file.close() ! elif path[-4:]=='.xml': ! from ModelSet import ModelSet ! return ModelSet().addModelFromXML({'file': path}) ! ! else: ! raise ValueError, 'Unable to handle file %s: unrecognized format (filename should end with either with .py or .xml)'%path ! ! def searchModel(modelName, path=None, verbose=0): ! """ ! Searches for the model named 'modelName' by trying loadModel() with the ! following paths: 'pymodel_<modelName>.py', 'model_<modelName>.py' and ! 'model_<modelName>.xml' in the current directory and the MDL/ directory. ! ! Returns the model, or None if it cannot be found/loaded ! ! """ ! if verbose: ! import sys ! mylog=lambda msg, stderr=sys.stderr:stderr.write('[Model.searchModel] %s\n'%msg) ! else: ! mylog=lambda msg: None ! ! searchList=('pymodel_%s.py', 'model_%s.py', 'model_%s.xml', ! 'MDL/pymodel_%s.py', 'MDL/model_%s.py', 'MDL/model_%s.xml') ! for file in searchList: ! model=None ! file=file%modelName ! if path: ! import os ! file=os.path.join(path, file) ! try: ! mylog('Trying %s'%file) ! model=loadModel(file) ! except (IOError, ValueError): ! import cStringIO, traceback ! exc=cStringIO.StringIO() ! traceback.print_exc(file=exc) ! mylog('Not found: %s\n Exception:%s'%(file,exc.getvalue())) ! del exc ! pass ! if model: ! return model ! mylog('Not found: %s'%file) ! mylog('modelName %s: All possibilities exhausted -- returning None'%modelName) ! return None ! ! class Model(Persistent, XMLCapability, KeyValueCoding): "Describes a model" _is_a_model = 1 *************** *** 329,332 **** --- 524,537 ---- } + ## + ## KeyValueCoding error handling + ## + def handleAssignementForUnboundKey(self, value, key): + if key=='connDict': self.setConnectionDictionary(value) + elif key=='doc': self.setComment(value) + else: + raise AttributeError, key + handleTakeStoredValueForUnboundKey=handleAssignementForUnboundKey + # Validation # Index: ModelSet.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/ModelSet.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** ModelSet.py 27 May 2003 19:37:28 -0000 1.8 --- ModelSet.py 7 Jul 2003 14:57:13 -0000 1.9 *************** *** 101,162 **** def updateModelWithCFG(model, cfg_path): """ ! Updates the model's connection dictionary and adaptorName with the values ! in file 'cfg_path'. ! ! A sample configuration file is like:: ! ! [DEFAULT] ! host: localhost ! ! [ModelName_1] ! user: user_1 ! password: pwd_1 ! ! [ModelName_2] ! adaptor: MySQL ! user: user_2 ! password: pwd_2 ! ! The special field 'adaptor', if present, changes the adaptorName of the ! model. ! ! Raises IOError if file 'cfg_path' cannot be found. ! ! See also: ModelSet.addModel() ! ! Parameters: ! ! model -- the model whose conn.dict. should be updated ! ! cfg_path -- the full path to the configuration file ! """ ! from ConfigParser import ConfigParser ! import os ! defaults=model.connectionDictionary() ! cp=ConfigParser() ! try: ! cp.readfp(open(cfg_path)) ! except IOError: ! import traceback, cStringIO, sys ! exc_raised=sys.exc_info()[:2] ! err_msg="Unable to open file '%s' pointed by env. variable MDL_DB_CONNECTIONS_CFG"%cfg_path ! exc=cStringIO.StringIO() ! traceback.print_exception(exc_raised[0], exc_raised[1], None, file=exc) ! err_msg+="\nOriginal exception was: %s"%exc.getvalue() ! raise IOError, err_msg - try: options=cp.options(model.name()) - except: return - try: options.remove('adaptor') - except ValueError: pass - for key in options: - defaults[key]=cp.get(model.name(), key) - model.setConnectionDictionary(defaults) - try: - model.setAdaptorName(cp.get(model.name(), 'adaptor')) - except: - pass - class ModelSet(Persistent): """Holds a set of Modeling.Models that can co-exist at runtime --- 101,113 ---- def updateModelWithCFG(model, cfg_path): """ ! Deprecated: use Model.updateModelWithCFG instead. This method will be ! removed in v0.9.1 """ ! from utils import deprecated ! deprecated('ModelSet.updateModelWithCFG','Model.updateModelWithCFG()', ! '0.9.1') ! from Modeling import Model ! return Model.updateModelWithCFG(model, cfg_path) class ModelSet(Persistent): """Holds a set of Modeling.Models that can co-exist at runtime *************** *** 185,189 **** If the environment variable 'MDL_DB_CONNECTIONS_CFG' is set, the file it points to is used to update aModel's connection dictionary (and ! possibly its adaptorName as well). See updateModelWithCFG() for details. """ #assert --- 136,141 ---- If the environment variable 'MDL_DB_CONNECTIONS_CFG' is set, the file it points to is used to update aModel's connection dictionary (and ! possibly its adaptorName as well). See Model.updateModelWithCFG() for ! details. """ #assert *************** *** 205,210 **** cfg_path=os.environ.get('MDL_DB_CONNECTIONS_CFG') if cfg_path: updateModelWithCFG(aModel, cfg_path) ! # XML Import/Export facilities def addModelFromXML(self, xmlSource): --- 157,163 ---- cfg_path=os.environ.get('MDL_DB_CONNECTIONS_CFG') if cfg_path: + from Model import updateModelWithCFG updateModelWithCFG(aModel, cfg_path) ! # XML Import/Export facilities def addModelFromXML(self, xmlSource): Index: Relationship.py =================================================================== RCS file: /cvsroot/modeling/ProjectModeling/Modeling/Relationship.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** Relationship.py 27 May 2003 19:37:28 -0000 1.9 --- Relationship.py 7 Jul 2003 14:57:13 -0000 1.10 *************** *** 32,35 **** --- 32,36 ---- from Join import Join from utils import isaValidName, toBoolean + from KeyValueCoding import KeyValueCoding from XMLutils import * import Validation *************** *** 49,53 **** # Relationships props ! from EntityClassDescription import DELETE_NULLIFY, DELETE_DENY, DELETE_CASCADE from utils import isListOrTuple --- 50,54 ---- # Relationships props ! from ClassDescription import DELETE_NULLIFY, DELETE_DENY, DELETE_CASCADE, DELETE_NOACTION, old_delete_rules from utils import isListOrTuple *************** *** 64,70 **** ! class Relationship(Persistent, XMLCapability): "See interfaces.Relationship for detail" - # _isClassProperty=1 --- 65,70 ---- ! class Relationship(Persistent, XMLCapability, KeyValueCoding): "See interfaces.Relationship for detail" # _isClassProperty=1 *************** *** 161,170 **** DELETE_NULLIFY, DELETE_CASCADE and DELETE_DENY """ if rule not in (DELETE_NULLIFY, DELETE_CASCADE, DELETE_DENY): raise ValueError, \ ! ("Parameter 'rule' should be one of DELETE_NULLIFY (%i), "+\ ! "DELETE_CASCADE (%i) or DELETE_DENY (%i)") \ ! % (DELETE_NULLIFY, DELETE_CASCADE, DELETE_DENY) ! rule=int(rule) self._deleteRule=rule --- 161,173 ---- DELETE_NULLIFY, DELETE_CASCADE and DELETE_DENY """ + #backward compatibility + if type(rule) in (type(0), type(0L), type(0.0)) or\ + rule in ('0', '1', '2', '3'): + rule=old_delete_rules.get(int(rule), rule) if rule not in (DELETE_NULLIFY, DELETE_CASCADE, DELETE_DENY): raise ValueError, \ ! ("Parameter 'rule' (%s) should be one of DELETE_NULLIFY (%s), "+\ ! "DELETE_CASCADE (%s) or DELETE_DENY (%s)") \ ! % (rule, DELETE_NULLIFY, DELETE_CASCADE, DELETE_DENY) self._deleteRule=rule *************** *** 205,213 **** upperBound -- must be a strictly positive integer, or -1 for a non ! constrained to-many relationship. Special value '*' is ! equivalent to -1. """ ! if upperBound=='*': upperBound=-1 assert(int(upperBound)>0 or int(upperBound)==-1) self._multUpper=int(upperBound) --- 208,216 ---- upperBound -- must be a strictly positive integer, or -1 for a non ! constrained to-many relationship. Special values '*' ! and None are equivalent to -1. """ ! if upperBound in ('*', None): upperBound=-1 assert(int(upperBound)>0 or int(upperBound)==-1) self._multUpper=int(upperBound) *************** *** 295,299 **** lambda self=None,p=None: None, self.name), ! 'deleteRule' : ('number', self.setDeleteRule, self.deleteRule), --- 298,302 ---- lambda self=None,p=None: None, self.name), ! 'deleteRule' : ('string', self.setDeleteRule, self.deleteRule), *************** *** 801,804 **** --- 804,818 ---- return d + ## + ## KeyValueCoding error handling + ## + def handleAssignementForUnboundKey(self, value, key): + if key=='doc': self.setComment(value) + elif key=='delete': + self.setDeleteRule(value) + else: + raise AttributeError, key + handleTakeStoredValueForUnboundKey=handleAssignementForUnboundKey + class FlattenedRelationship(Relationship): *************** *** 1161,1165 **** return d - # Validation # --- 1175,1178 ---- |