[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 ----
|