Thread: [Modeling-cvs] SF.net SVN: modeling: [972] trunk/ProjectModeling
Status: Abandoned
Brought to you by:
sbigaret
From: <sbi...@us...> - 2006-02-26 01:27:21
|
Revision: 972 Author: sbigaret Date: 2006-02-25 17:27:05 -0800 (Sat, 25 Feb 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=972&view=rev Log Message: ----------- Fixed bug #918115: tests were failing under py2.1 w/ ZODB was installed, plus: relationships equality was not behaving as expected under py2.1 and 2.2, because these versions of python use __cmp__ rather than __eq__ Modified Paths: -------------- trunk/ProjectModeling/CHANGES trunk/ProjectModeling/Modeling/ChangeLog trunk/ProjectModeling/Modeling/Relationship.py trunk/ProjectModeling/Modeling/tests/test_Relationship.py Modified: trunk/ProjectModeling/CHANGES =================================================================== --- trunk/ProjectModeling/CHANGES 2006-02-25 23:49:51 UTC (rev 971) +++ trunk/ProjectModeling/CHANGES 2006-02-26 01:27:05 UTC (rev 972) @@ -9,6 +9,10 @@ * Now distributed under a 3-clause BSD-style license, see LICENSE for details + * Fixed bug #918115: tests were failing under py2.1 w/ ZODB was installed, + plus: relationships equality was not behaving as expected under py2.1 and + 2.2, because these versions of python use __cmp__ rather than __eq__ + * Fixed: Attribute.convertStringToAttributeType() failed when python db-adapters, such as mysqldb, already return values under the a date type Modified: trunk/ProjectModeling/Modeling/ChangeLog =================================================================== --- trunk/ProjectModeling/Modeling/ChangeLog 2006-02-25 23:49:51 UTC (rev 971) +++ trunk/ProjectModeling/Modeling/ChangeLog 2006-02-26 01:27:05 UTC (rev 972) @@ -1,3 +1,10 @@ +2006-02-26 Sebastien Bigaret <Seb...@en...> + + * Relationship.py (Relationship.__cmp__): added for py2.1 and 2.2, + or equality is not correcty handled (bug #918115) + * utils.py (cache_simple_methods): disabled under py2.1 when ZODB + is installed (bug #918115) + 2006-02-25 Sebastien Bigaret <Seb...@en...> * Attribute.py (date_types): added python date and datetime types Modified: trunk/ProjectModeling/Modeling/Relationship.py =================================================================== --- trunk/ProjectModeling/Modeling/Relationship.py 2006-02-25 23:49:51 UTC (rev 971) +++ trunk/ProjectModeling/Modeling/Relationship.py 2006-02-26 01:27:05 UTC (rev 972) @@ -227,6 +227,12 @@ def __ne__(self, aRelationship): # See test_Relationship.test_00_equality_n_inequality() for details return not self.__eq__(aRelationship) + + import sys + if sys.version_info < (2,3): + def __cmp__(self, r): + return not self.__eq__(r) + # XMLCapabilityInterface def initWithXMLDOMNode(self, aNode, encoding='iso-8859-1'): Modified: trunk/ProjectModeling/Modeling/tests/test_Relationship.py =================================================================== --- trunk/ProjectModeling/Modeling/tests/test_Relationship.py 2006-02-25 23:49:51 UTC (rev 971) +++ trunk/ProjectModeling/Modeling/tests/test_Relationship.py 2006-02-26 01:27:05 UTC (rev 972) @@ -16,13 +16,13 @@ from __future__ import nested_scopes -import unittest +import unittest, sys if __name__ == "__main__": - import utils, sys + import utils utils.disable_model_cache() utils.fixpath() -from Modeling import ModelSet +from Modeling import ModelSet, Relationship import StoreEmployees # load the model @@ -46,11 +46,22 @@ # v2.2 both of which were defaulting to identity comparison for '!=' # when __ne__ was undefined (despite the fact that __eq__ was defined). # python2.3 operator '!=' takes '__eq__' into account and that revealed - # both the bug and the fact that py2.1 and 2.2 + # both the bug and the fact that py2.1 and 2.2 rely on __cmp__ instead of + # __eq__ rel_ab=model.entityNamed('A').relationshipNamed('toB') rel_ac=model.entityNamed('A').relationshipNamed('toCs') + import copy - rel_abb=copy.copy(rel_ab) # same, different id() + if sys.version_info < (2,3): + # simulates copy, because it fails if ZODB is installed (because of + # extension class) + rel_abb=Relationship.SimpleRelationship('toB') + for k in rel_ab.__dict__.keys(): + setattr(rel_abb, k, getattr(rel_ab, k)) + else: + rel_abb = copy.copy(rel_ab) + + self.assertNotEqual(id(rel_ab), id(rel_abb)) self.failUnless(rel_ab==rel_ab, "rel==rel fails") self.failUnless(rel_ab==rel_abb, "rel==copy(rel) fails") self.failUnless(not rel_ab!=rel_ab, "rel!=rel fails") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sbi...@us...> - 2006-02-26 17:45:11
|
Revision: 976 Author: sbigaret Date: 2006-02-26 09:44:38 -0800 (Sun, 26 Feb 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=976&view=rev Log Message: ----------- Updated license Modified Paths: -------------- trunk/ProjectModeling/LICENSE trunk/ProjectModeling/Modeling/DatabaseAdaptors/LICENSE trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/LICENSE trunk/ProjectModeling/Modeling/DatabaseAdaptors/OracleAdaptorLayer/LICENSE trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/LICENSE trunk/ProjectModeling/Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/LICENSE trunk/ProjectModeling/Modeling/LICENSE trunk/ProjectModeling/Modeling/doc/HomePage/licence.tex trunk/ProjectModeling/Modeling/tests/LICENSE Modified: trunk/ProjectModeling/LICENSE =================================================================== --- trunk/ProjectModeling/LICENSE 2006-02-26 14:39:05 UTC (rev 975) +++ trunk/ProjectModeling/LICENSE 2006-02-26 17:44:38 UTC (rev 976) @@ -1,6 +1,6 @@ Modeling Framework: an Object-Relational Bridge for python -Copyright (c) 2001 - 2004 Sstien Bigaret <sbi...@us...> +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> All rights reserved. Redistribution and use in source and binary forms, with or without Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/LICENSE =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/LICENSE 2006-02-26 14:39:05 UTC (rev 975) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/LICENSE 2006-02-26 17:44:38 UTC (rev 976) @@ -1,6 +1,6 @@ Modeling Framework: an Object-Relational Bridge for python -Copyright (c) 2001 - 2004 Sstien Bigaret <sbi...@us...> +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> All rights reserved. Redistribution and use in source and binary forms, with or without Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/LICENSE =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/LICENSE 2006-02-26 14:39:05 UTC (rev 975) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/LICENSE 2006-02-26 17:44:38 UTC (rev 976) @@ -1,6 +1,6 @@ Modeling Framework: an Object-Relational Bridge for python -Copyright (c) 2001 - 2004 Sstien Bigaret <sbi...@us...> +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> All rights reserved. Redistribution and use in source and binary forms, with or without Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/OracleAdaptorLayer/LICENSE =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/OracleAdaptorLayer/LICENSE 2006-02-26 14:39:05 UTC (rev 975) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/OracleAdaptorLayer/LICENSE 2006-02-26 17:44:38 UTC (rev 976) @@ -1,6 +1,6 @@ Modeling Framework: an Object-Relational Bridge for python -Copyright (c) 2001 - 2004 Sstien Bigaret <sbi...@us...> +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> All rights reserved. Redistribution and use in source and binary forms, with or without Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/LICENSE =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/LICENSE 2006-02-26 14:39:05 UTC (rev 975) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/LICENSE 2006-02-26 17:44:38 UTC (rev 976) @@ -1,6 +1,6 @@ Modeling Framework: an Object-Relational Bridge for python -Copyright (c) 2001 - 2004 Sstien Bigaret <sbi...@us...> +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> All rights reserved. Redistribution and use in source and binary forms, with or without Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/LICENSE =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/LICENSE 2006-02-26 14:39:05 UTC (rev 975) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/LICENSE 2006-02-26 17:44:38 UTC (rev 976) @@ -1,6 +1,6 @@ Modeling Framework: an Object-Relational Bridge for python -Copyright (c) 2001 - 2004 Sstien Bigaret <sbi...@us...> +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> All rights reserved. Redistribution and use in source and binary forms, with or without Modified: trunk/ProjectModeling/Modeling/LICENSE =================================================================== --- trunk/ProjectModeling/Modeling/LICENSE 2006-02-26 14:39:05 UTC (rev 975) +++ trunk/ProjectModeling/Modeling/LICENSE 2006-02-26 17:44:38 UTC (rev 976) @@ -1,6 +1,6 @@ Modeling Framework: an Object-Relational Bridge for python -Copyright (c) 2001 - 2004 Sstien Bigaret <sbi...@us...> +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> All rights reserved. Redistribution and use in source and binary forms, with or without Modified: trunk/ProjectModeling/Modeling/doc/HomePage/licence.tex =================================================================== --- trunk/ProjectModeling/Modeling/doc/HomePage/licence.tex 2006-02-26 14:39:05 UTC (rev 975) +++ trunk/ProjectModeling/Modeling/doc/HomePage/licence.tex 2006-02-26 17:44:38 UTC (rev 976) @@ -11,16 +11,17 @@ \begin{rawhtml}<hr noshade>\end{rawhtml} {\sc \bf Important~:} License has changed. All versions released prior to 0.7a5-1 (including 0.7a5-1) were under a BSD-like licence. From 0.8 -(inclusive), the Modeling Framework is released under the GNU General -Public License. +(inclusive) to 0.9-pre-17, the Modeling Framework was released under the GNU +General Public License. From version 0.9, it is distributed under the 3-clause +BSD licence. \begin{rawhtml}<hr noshade>\end{rawhtml} -\section{Versions 0.9pre18 and higher} +\section{Versions 0.9 and higher} \begin{centering} \begin{verbatim} Modeling Framework: an Object-Relational Bridge for python -Copyright (c) 2001 - 2004 Sstien Bigaret <sbi...@us...> +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> All rights reserved. Redistribution and use in source and binary forms, with or without Modified: trunk/ProjectModeling/Modeling/tests/LICENSE =================================================================== --- trunk/ProjectModeling/Modeling/tests/LICENSE 2006-02-26 14:39:05 UTC (rev 975) +++ trunk/ProjectModeling/Modeling/tests/LICENSE 2006-02-26 17:44:38 UTC (rev 976) @@ -1,6 +1,6 @@ Modeling Framework: an Object-Relational Bridge for python -Copyright (c) 2001 - 2004 Sstien Bigaret <sbi...@us...> +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> All rights reserved. Redistribution and use in source and binary forms, with or without This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sbi...@us...> - 2006-02-26 18:13:15
|
Revision: 981 Author: sbigaret Date: 2006-02-26 10:12:56 -0800 (Sun, 26 Feb 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=981&view=rev Log Message: ----------- Preparation for v0.9 Modified Paths: -------------- trunk/ProjectModeling/CHANGES trunk/ProjectModeling/Modeling/__init__.py trunk/ProjectModeling/Modeling/doc/HomePage/downloads.tex trunk/ProjectModeling/Modeling/doc/HomePage/main.tex trunk/ProjectModeling/Modeling/doc/Tutorial.tex trunk/ProjectModeling/Modeling/doc/UserGuide.tex trunk/ProjectModeling/setup.py trunk/ProjectModeling/vertoo.data Modified: trunk/ProjectModeling/CHANGES =================================================================== --- trunk/ProjectModeling/CHANGES 2006-02-26 18:04:47 UTC (rev 980) +++ trunk/ProjectModeling/CHANGES 2006-02-26 18:12:56 UTC (rev 981) @@ -2,7 +2,7 @@ Module Modeling --------------- -Current release is: 0.9-pre-17.1 / See also: TODO, INSTALL and doc/ +Current release is: 0.9 / See also: TODO, INSTALL and doc/ ** Distributed under a 3-clause BSD-style license, see LICENSE for details ** ----------------------------------------------------------------------------- Modified: trunk/ProjectModeling/Modeling/__init__.py =================================================================== --- trunk/ProjectModeling/Modeling/__init__.py 2006-02-26 18:04:47 UTC (rev 980) +++ trunk/ProjectModeling/Modeling/__init__.py 2006-02-26 18:12:56 UTC (rev 981) @@ -25,7 +25,7 @@ SQLite. """ -__version__="0.9-pre-17.1" +__version__="0.9" import DatabaseContext # make it register itself for notifications from utils import migration_warnings Modified: trunk/ProjectModeling/Modeling/doc/HomePage/downloads.tex =================================================================== --- trunk/ProjectModeling/Modeling/doc/HomePage/downloads.tex 2006-02-26 18:04:47 UTC (rev 980) +++ trunk/ProjectModeling/Modeling/doc/HomePage/downloads.tex 2006-02-26 18:12:56 UTC (rev 981) @@ -9,7 +9,7 @@ \maketitle \begin{enumerate} -\item[\bf Current version: 0.9-pre-17.1] +\item[\bf Current version: 0.9] Download it here:\begin{rawhtml}<a href="https://sourceforge.net/projects/modeling/">Sourceforge's project home Modified: trunk/ProjectModeling/Modeling/doc/HomePage/main.tex =================================================================== --- trunk/ProjectModeling/Modeling/doc/HomePage/main.tex 2006-02-26 18:04:47 UTC (rev 980) +++ trunk/ProjectModeling/Modeling/doc/HomePage/main.tex 2006-02-26 18:12:56 UTC (rev 981) @@ -6,7 +6,7 @@ % Increment the release number whenever significant changes are made. % The author and/or editor can define 'significant' however they like. -%\release{0.9-pre-17.1} +%\release{0.9} % At minimum, give your name and an email address. You can include a % snail-mail address if you like. Modified: trunk/ProjectModeling/Modeling/doc/Tutorial.tex =================================================================== --- trunk/ProjectModeling/Modeling/doc/Tutorial.tex 2006-02-26 18:04:47 UTC (rev 980) +++ trunk/ProjectModeling/Modeling/doc/Tutorial.tex 2006-02-26 18:12:56 UTC (rev 981) @@ -13,7 +13,7 @@ \authoraddress{Email: \email{sbi...@us...}} \date{February 10, 2003} %\date{\today} -\release{0.9-pre-17.1} +\release{0.9} %\setreleaseinfo{5} \setshortversion{0.9} Modified: trunk/ProjectModeling/Modeling/doc/UserGuide.tex =================================================================== --- trunk/ProjectModeling/Modeling/doc/UserGuide.tex 2006-02-26 18:04:47 UTC (rev 980) +++ trunk/ProjectModeling/Modeling/doc/UserGuide.tex 2006-02-26 18:12:56 UTC (rev 981) @@ -21,9 +21,9 @@ % Please at least include a long-lived email address; % the rest is at your discretion. \authoraddress{Email: \email{sbi...@us...}} -%\date{Feb 22, 2004} +%\date{Feb 26, 2006} \date{\today} -\release{0.9-pre-17.1} +\release{0.9} %\setreleaseinfo{pre-8} \setshortversion{0.9} Modified: trunk/ProjectModeling/setup.py =================================================================== --- trunk/ProjectModeling/setup.py 2006-02-26 18:04:47 UTC (rev 980) +++ trunk/ProjectModeling/setup.py 2006-02-26 18:12:56 UTC (rev 981) @@ -70,7 +70,7 @@ compile_cheetah_template(cheetah_compile_cmd) setup(name="ModelingCore", - version="0.9-pre-17.1", + version="0.9", license ="BSD License", description=short_description, author="Sstien Bigaret", Modified: trunk/ProjectModeling/vertoo.data =================================================================== --- trunk/ProjectModeling/vertoo.data 2006-02-26 18:04:47 UTC (rev 980) +++ trunk/ProjectModeling/vertoo.data 2006-02-26 18:12:56 UTC (rev 981) @@ -1,2 +1,2 @@ -mdl-code = major:0; minor:9; pre:17.1; release:x; date:Feb 22, 2004; -mdl_doc = major:0; minor:9; pre:17.1; release:x; date:Feb 22, 2004; \ No newline at end of file +mdl-code = major:0; minor:9; pre:x; release:x; date:Feb 26, 2006; +mdl_doc = major:0; minor:9; pre:x; release:x; date:Feb 26, 2006; \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sbi...@us...> - 2006-02-26 18:28:56
|
Revision: 983 Author: sbigaret Date: 2006-02-26 10:28:43 -0800 (Sun, 26 Feb 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=983&view=rev Log Message: ----------- Fixed MANIFEST Modified Paths: -------------- trunk/ProjectModeling/MANIFEST.in Added Paths: ----------- trunk/ProjectModeling/Modeling/DatabaseAdaptors/AbstractDBAPI2AdaptorLayer/LICENSE Modified: trunk/ProjectModeling/MANIFEST.in =================================================================== --- trunk/ProjectModeling/MANIFEST.in 2006-02-26 18:15:28 UTC (rev 982) +++ trunk/ProjectModeling/MANIFEST.in 2006-02-26 18:28:43 UTC (rev 983) @@ -1,8 +1,8 @@ -include COPYING +include LICENSE include INSTALL include MIGRATION include TODO -include Modeling/COPYING +include Modeling/LICENSE include Modeling/TODO include Modeling/scripts/mdl_generate_DB_schema.py @@ -19,32 +19,32 @@ recursive-include Modeling/tests/xmlmodels *.txt *.xml *.py -include Modeling/DatabaseAdaptors/COPYING +include Modeling/DatabaseAdaptors/LICENSE include Modeling/DatabaseAdaptors/CHANGES include Modeling/DatabaseAdaptors/README include Modeling/DatabaseAdaptors/AbstractDBAPI2AdaptorLayer/CHANGES -include Modeling/DatabaseAdaptors/AbstractDBAPI2AdaptorLayer/COPYING +include Modeling/DatabaseAdaptors/AbstractDBAPI2AdaptorLayer/LICENSE include Modeling/DatabaseAdaptors/AbstractDBAPI2AdaptorLayer/README include Modeling/DatabaseAdaptors/AbstractDBAPI2AdaptorLayer/TODO -include Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/COPYING +include Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/LICENSE include Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/CHANGES include Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/DEPENDENCIES include Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/INSTALL include Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/TODO -include Modeling/DatabaseAdaptors/MySQLAdaptorLayer/COPYING +include Modeling/DatabaseAdaptors/MySQLAdaptorLayer/LICENSE include Modeling/DatabaseAdaptors/MySQLAdaptorLayer/CHANGES include Modeling/DatabaseAdaptors/MySQLAdaptorLayer/DEPENDENCIES include Modeling/DatabaseAdaptors/MySQLAdaptorLayer/README include Modeling/DatabaseAdaptors/MySQLAdaptorLayer/TODO -include Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/COPYING +include Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/LICENSE include Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/README.txt include Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/TODO -include Modeling/DatabaseAdaptors/OracleAdaptorLayer/COPYING +include Modeling/DatabaseAdaptors/OracleAdaptorLayer/LICENSE recursive-include Modeling/ModelMasons *.tmpl *.gif Added: trunk/ProjectModeling/Modeling/DatabaseAdaptors/AbstractDBAPI2AdaptorLayer/LICENSE =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/AbstractDBAPI2AdaptorLayer/LICENSE (rev 0) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/AbstractDBAPI2AdaptorLayer/LICENSE 2006-02-26 18:28:43 UTC (rev 983) @@ -0,0 +1,31 @@ +Modeling Framework: an Object-Relational Bridge for python + +Copyright (c) 2001 - 2006 Sstien Bigaret <sbi...@us...> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of its copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sbi...@us...> - 2006-04-09 13:53:33
|
Revision: 988 Author: sbigaret Date: 2006-04-09 06:53:19 -0700 (Sun, 09 Apr 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=988&view=rev Log Message: ----------- Fixed bug #621210: defining __cmp__ leads to infinite loop Modified Paths: -------------- trunk/ProjectModeling/CHANGES trunk/ProjectModeling/Modeling/DatabaseContext.py trunk/ProjectModeling/Modeling/RelationshipManipulation.py trunk/ProjectModeling/Modeling/tests/testPackages/AuthorBooks/Book.py trunk/ProjectModeling/Modeling/tests/testPackages/AuthorBooks/Writer.py trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py Modified: trunk/ProjectModeling/CHANGES =================================================================== --- trunk/ProjectModeling/CHANGES 2006-02-26 19:37:08 UTC (rev 987) +++ trunk/ProjectModeling/CHANGES 2006-04-09 13:53:19 UTC (rev 988) @@ -7,6 +7,12 @@ ** Distributed under a 3-clause BSD-style license, see LICENSE for details ** ----------------------------------------------------------------------------- + * Fixed bug #621210: when __cmp__ (and/or, possibly, other special methods + such as __eq__ or __ne__) was defined in a CustomObject, it was possible + to enter a infinite loop. The fix consisted in making sure that the + framework does not trigger those special methods, since in all cases what + we really want is comparing class instances by object identity. + 0.9 (2006/02/26) ---------------- Modified: trunk/ProjectModeling/Modeling/DatabaseContext.py =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseContext.py 2006-02-26 19:37:08 UTC (rev 987) +++ trunk/ProjectModeling/Modeling/DatabaseContext.py 2006-04-09 13:53:19 UTC (rev 988) @@ -1588,7 +1588,7 @@ aGlobalID -- KeyGlobalID (non temporary) """ - if anEditingContext.objectForGlobalID(aGlobalID)!=aDatabaseObject: + if id(anEditingContext.objectForGlobalID(aGlobalID))!=id(aDatabaseObject): raise ValueError, 'aDatabaseObject %s is not registered within the '\ 'EditingContext %s for globalID: %s'%(repr(aDatabaseObject), repr(anEditingContext), Modified: trunk/ProjectModeling/Modeling/RelationshipManipulation.py =================================================================== --- trunk/ProjectModeling/Modeling/RelationshipManipulation.py 2006-02-26 19:37:08 UTC (rev 987) +++ trunk/ProjectModeling/Modeling/RelationshipManipulation.py 2006-04-09 13:53:19 UTC (rev 988) @@ -77,7 +77,7 @@ # toOne relationship: is it already set? _backRelObj=anObject.valueForKey(_backRelKey) #if _backRelObj and _backRelObj.persistentID()!=self.persistentID(): - if _backRelObj and _backRelObj!=self: + if _backRelObj and id(_backRelObj)!=id(self): # Yes: now remove it _removeObjectFromBothSidesOfRelationshipWithKey(anObject, _backRelObj, _backRelKey, otoOnes, otoManys) _addObjectToPropertyWithKey(anObject, self, _backRelKey, otoOnes, otoManys) @@ -164,7 +164,7 @@ _removeObjectFromPropertyWithKey(self,anObject, aKey, toOnes, toManys) else: # toOne: check this is the one! - if self.valueForKey(aKey) != anObject: + if id(self.valueForKey(aKey)) != id(anObject): raise ValueError, 'anObject %s is not set for key %s'%(repr(anObject), aKey) _addObjectToPropertyWithKey(self,None, aKey, toOnes,toManys) @@ -205,7 +205,7 @@ if aKey in toOnes: # toOne: Simply uses KVC - if self.valueForKey(aKey)!=anObject: + if id(self.valueForKey(aKey)) != id(anObject): raise ValueError, 'anObject %s is not set for key %s'%(repr(anObject), aKey) self.takeValueForKey(None, aKey) Modified: trunk/ProjectModeling/Modeling/tests/testPackages/AuthorBooks/Book.py =================================================================== --- trunk/ProjectModeling/Modeling/tests/testPackages/AuthorBooks/Book.py 2006-02-26 19:37:08 UTC (rev 987) +++ trunk/ProjectModeling/Modeling/tests/testPackages/AuthorBooks/Book.py 2006-04-09 13:53:19 UTC (rev 988) @@ -94,4 +94,26 @@ self.willChange() self._author=object + + def check_cmp_allowed(self): + # see comments in class Writer, same method + import AuthorBooks + from inspect import stack + if not AuthorBooks.allow_cmp and stack()[3][0].f_code.co_name not in ('__observersForObject', '__setObjectObservers', 'notifyObserversObjectWillChange','removeObjectFromAlreadyNotifiedObjects'): + raise 'Invalid call of %s in %s'%(stack()[1][0].f_code.co_name, + repr(self)) + + def __cmp__(self, o): + self.check_cmp_allowed() + return cmp( id(self), id(o) ) + + def __eq__(self, o): + self.check_cmp_allowed() + return id(self) == id(o) + def __ne__(self, o): + self.check_cmp_allowed() + return id(self) != id(o) + + def __hash__(self): + return hash(id(self)) Modified: trunk/ProjectModeling/Modeling/tests/testPackages/AuthorBooks/Writer.py =================================================================== --- trunk/ProjectModeling/Modeling/tests/testPackages/AuthorBooks/Writer.py 2006-02-26 19:37:08 UTC (rev 987) +++ trunk/ProjectModeling/Modeling/tests/testPackages/AuthorBooks/Writer.py 2006-04-09 13:53:19 UTC (rev 988) @@ -13,6 +13,7 @@ """ Writers are objects ... """ + allow_cmp=1 __implements__ = CustomObject.__implements__ @@ -137,18 +138,26 @@ def addToBooks(self,object): "Add the books relationship to many" + import AuthorBooks + _saved_value = AuthorBooks.allow_cmp + AuthorBooks.allow_cmp = 1 if object not in self._books: self.willChange() _books=list(self._books) _books.append(object) self._books=tuple(_books) + AuthorBooks.allow_cmp = _saved_value def removeFromBooks(self,object): "Remove the books relationship to many" self.willChange() _books=list(self._books) + import AuthorBooks + _saved_value = AuthorBooks.allow_cmp + AuthorBooks.allow_cmp = 1 _books.remove(object) self._books=tuple(_books) + AuthorBooks.allow_cmp = _saved_value @@ -164,3 +173,32 @@ def __str__(self): return '('+repr(self)+')'+' '+str(self._firstName)+' '+str(self._lastName) + + def check_cmp_allowed(self): + # part of the tests for bug #621210 + import AuthorBooks + from inspect import stack + + # excluded funcs are part of the Notification framework. It uses + # WeakDict. whose method get calls __cmp__ + # technically, these means that at some points, the framework does + # actually call __cmp__. for the moment we leave it as-is, since it + # is not triggering the infinite loop bug. + if not AuthorBooks.allow_cmp and stack()[3][0].f_code.co_name not in ('__observersForObject', '__setObjectObservers', 'notifyObserversObjectWillChange','removeObjectFromAlreadyNotifiedObjects'): + raise 'Invalid call of %s in %s'%(stack()[1][0].f_code.co_name, + repr(self)) + + def __cmp__(self, o): + self.check_cmp_allowed() + return cmp( id(self), id(o) ) + + def __eq__(self, o): + self.check_cmp_allowed() + return id(self) == id(o) + + def __ne__(self, o): + self.check_cmp_allowed() + return id(self) != id(o) + + def __hash__(self): + return hash(id(self)) Modified: trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py =================================================================== --- trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py 2006-02-26 19:37:08 UTC (rev 987) +++ trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py 2006-04-09 13:53:19 UTC (rev 988) @@ -41,7 +41,6 @@ from AuthorBooks.Writer import Writer from AuthorBooks.Book import Book - from Modeling.EditingContext import EditingContext from Modeling.FetchSpecification import FetchSpecification from Modeling.Qualifier import qualifierWithQualifierFormat @@ -50,6 +49,18 @@ from Modeling import Adaptor from Modeling import Database +# The following is part of the global test for bug #621210 +# Note that the tests only works when using the testPackages/AuthorBooks +# modules, not the ones that are generated on the fly +# (see ref. to utils.dynamically_build_test_packages, above) +# The principle of the test is simple: the framework should not call any +# of the special funcs __cmp__ , __eq__, __ne__, etc. +import AuthorBooks +AuthorBooks.allow_cmp = 0 +def allow_cmp(): + AuthorBooks.allow_cmp = 1 +def forbid_cmp(): + AuthorBooks.allow_cmp = 0 class Writer_test07(Writer): refusesValidateForDelete=0 @@ -76,7 +87,6 @@ class TestEditingContext_Global(unittest.TestCase): "Global tests for EditingContext" - def test_00_insertObject_loads_databaseContexts(self): "[EditingContext] ..." # drop any existing default ObjectStoreCoordinator @@ -148,7 +158,9 @@ fetchSpec=FetchSpecification(entityName='Writer') objects=ec.objectsWithFetchSpecification(fetchSpec) + allow_cmp() self.failUnless(w in objects) + allow_cmp() def test_01c_objectsWithFetchSpecification_closes_adaptorChannel(self): "[EditingContext] objectsWithFetchSpecification closes adaptorChannel" @@ -170,10 +182,15 @@ objects_1=ec.objectsWithFetchSpecification(fetchSpec) objects_2=ec.fetch('Writer', 'lastName like "?a*"') self.failIf(len(objects_1)!=len(objects_2)) + allow_cmp() self.failIf([o for o in objects_1 if o not in objects_2]) + forbid_cmp() + objects_3=ec.fetch('Writer', qualifier) self.failIf(len(objects_1)!=len(objects_3)) + allow_cmp() self.failIf([o for o in objects_1 if o not in objects_3]) + forbid_cmp() def test_02_toOneFaultTrigger(self): "[EditingContext] toOneFaultTrigger" @@ -191,11 +208,12 @@ self.failUnless(dard_pygmalion.isFault()) dard_pygmalion.getLastName() #trigger self.failIf(dard_pygmalion.isFault()) + allow_cmp() self.failUnless(dard._pygmalion==dard_pygmalion) - # Last, check that the original object containing the toMany fault was not # marked as changed self.failIf(dard in ec.updatedObjects()) + forbid_cmp() self.failIf(ec.hasChanges()) def test_02b_toOneFaultOrNone(self): @@ -249,8 +267,10 @@ ec.processRecentChanges() self.failIf(ec.hasUnprocessedChanges(), 'no unprocessed changes anymore') self.failUnless(ec.hasChanges(), 'has changes') + allow_cmp() self.assertEqual(ec.insertedObjects(), [w]) - + forbid_cmp() + # new EC ec=EditingContext() fetchSpec=FetchSpecification(entityName='Writer') @@ -263,7 +283,9 @@ ec.processRecentChanges() self.failIf(ec.hasUnprocessedChanges(), 'no unprocessed changes anymore') self.failUnless(ec.hasChanges(), 'has changes') + allow_cmp() self.assertEqual(ec.updatedObjects(), [ws[0]]) + forbid_cmp() # new EC ec=EditingContext() @@ -299,11 +321,14 @@ dard_books=dard.getBooks() ldb=len(dard_books) # trigger dard_books=dard.getBooks() + allow_cmp() self.failIf(dard_books[0] in ec.deletedObjects()) + forbid_cmp() ec.processRecentChanges() self.failUnless(len(ec.deletedObjects())==ldb+1) # Check that the author was also deleted [cascade] + allow_cmp() self.failUnless(dard in ec.deletedObjects()) # AND that neither the author nor the book are marked as updated # [Bug #599602] @@ -312,6 +337,7 @@ for book in dard_books: self.failUnless(book in ec.deletedObjects()) + forbid_cmp() def test_06_deleteRule_nullify(self): "[EditingContext] processRecentChanges: deleteRule: NULLIFY" @@ -354,7 +380,9 @@ # Now the dard.getBooks() should have been refreshed and the book # that was deleted should be removed from dard's books. self.failIf(len(dard.getBooks())!=2) + allow_cmp() self.failIf(dard_book1 in dard.getBooks()) + forbid_cmp() def test_07_savechanges_01(self): @@ -447,8 +475,9 @@ ## return objects marked for deletion fetchSpec=FetchSpecification(entityName='Writer') writers=ec.objectsWithFetchSpecification(fetchSpec) + allow_cmp() self.failIf(hugo in writers) - + forbid_cmp() ## 4rd test: now deleting it for real should be OK hugo.refusesValidateForDelete=0 try: @@ -457,7 +486,9 @@ self.fail("Error: deletion failed") ## 5th test: check that the object has been removed from the uniquing table + allow_cmp() self.failIf(hugo in ec.registeredObjects()) + forbid_cmp() def test_09_savechanges_03(self): "[EditingContext] saveChanges part 03: change + validation" @@ -815,8 +846,10 @@ cleese.willChange() ec.setPropagatesInsertionForRelatedObjects(1) ec.processRecentChanges() + allow_cmp() self.failUnless(book_cleese in ec.insertedObjects()) self.failUnless(pygmalion_cleese in ec.insertedObjects()) + forbid_cmp() # Last: check that subsequent changes are notified after # ec.processRecentChanges() @@ -833,8 +866,10 @@ cleese.setPygmalion(pygmalion_cleese) cleese.addToBooks(book_cleese) ec.processRecentChanges() + allow_cmp() self.failUnless(book_cleese in ec.insertedObjects()) self.failUnless(pygmalion_cleese in ec.insertedObjects()) + forbid_cmp() def test_15_propagatesInsertionForRelatedObjects_02(self): "[EditingContext] propagatesInsertionForRelatedObjects (inserted objects)" @@ -849,13 +884,17 @@ hugo.addObjectToBothSidesOfRelationshipWithKey(b1, 'books') ec.processRecentChanges() + allow_cmp() self.failUnless(b1 in ec.insertedObjects()) + forbid_cmp() #Check that subsequent changes are notified after ec.processRecentChanges() b2=Book() ; b2.setTitle("Les travailleurs de la mer") hugo.addObjectToBothSidesOfRelationshipWithKey(b2, 'books') ec.processRecentChanges() + allow_cmp() self.failUnless(b2 in ec.insertedObjects()) + forbid_cmp() def test_16_toManySnapshotsUpdated(self): "[EditingContext] checks that toManySnapshots are correctly updated" @@ -1072,7 +1111,9 @@ self.assertEqual(adaptorChannel._count_for_execute, fetchCount+1) # fault was cleared for book in w.getBooks(): + allow_cmp() self.failIf(book not in tomany_fault) + forbid_cmp() def test_21_snapshot_raw(self): "[EditingContext] CustomObject.snapshot_raw()" @@ -1139,23 +1180,36 @@ ec=EditingContext() rabelais=ec.fetch('Writer', 'lastName == "Rabelais"')[0] ec.deleteObject(rabelais) + allow_cmp() self.failUnless(rabelais in ec.allDeletedObjects()) self.failIf(rabelais in ec.deletedObjects()) # unprocessed + forbid_cmp() ec.insertObject(rabelais) # cancel the deletion self.failIf(len(ec.fetch('Writer', 'lastName == "Rabelais"'))!=1) + allow_cmp() self.failIf(rabelais in ec.allDeletedObjects()) self.failIf(rabelais in ec.allInsertedObjects()) - + forbid_cmp() + ## check: delete / processRecentChanges / insert ec=EditingContext() rabelais=ec.fetch('Writer', 'lastName == "Rabelais"')[0] ec.deleteObject(rabelais) + allow_cmp() self.failUnless(rabelais in ec.allDeletedObjects()) + forbid_cmp() + ec.processRecentChanges() + + allow_cmp() self.failUnless(rabelais in ec.deletedObjects()) + forbid_cmp() + ec.insertObject(rabelais) # cancel the deletion + allow_cmp() self.failIf(rabelais in ec.allDeletedObjects()) self.failIf(rabelais in ec.allInsertedObjects()) + forbid_cmp() ## check: delete / saveChanges / insert ec=EditingContext() @@ -1167,12 +1221,16 @@ new=ec.fetch('Writer', 'lastName == "test_22"')[0] new_gid=new.globalID() ec.deleteObject(new) + allow_cmp() self.failUnless(new in ec.allDeletedObjects()) self.failIf(new in ec.deletedObjects()) + forbid_cmp() ec.saveChanges() ec.insertObject(new) # cancel the deletion? No, insertion of a new object + allow_cmp() self.failIf(new in ec.allDeletedObjects()) self.failUnless(new in ec.allInsertedObjects()) + forbid_cmp() self.failIf(new.globalID()==new_gid) self.failIf(not new.globalID().isTemporary()) @@ -1186,18 +1244,32 @@ new=ec.fetch('Writer', 'lastName == "test_22"')[0] new_gid=new.globalID() new.setLastName('test_22 alternate value') + allow_cmp() self.failUnless(new in ec.allUpdatedObjects()) + forbid_cmp() + ec.deleteObject(new) + + allow_cmp() self.failUnless(new in ec.allDeletedObjects()) self.failIf(new in ec.deletedObjects()) self.failIf(new in ec.allUpdatedObjects()) + forbid_cmp() + ec.processRecentChanges() + + allow_cmp() self.failUnless(new in ec.deletedObjects()) self.failIf(new in ec.allUpdatedObjects()) + forbid_cmp() + ec.insertObject(new) # cancel the deletion + + allow_cmp() self.failIf(new in ec.allDeletedObjects()) self.failUnless(new in ec.allUpdatedObjects()) self.failUnless(new.globalID()==new_gid) + forbid_cmp() ## check: modify / delete / saveChanges / insert @@ -1262,8 +1334,10 @@ # explicitely look for duplicates for w in ws: _ws=list(ws) #[:-1]) + allow_cmp() _ws.remove(w) self.failIf(w in _ws, 'Duplicate found: %s'%w) + forbid_cmp() def test_25_fetchCount_is_not_affected_by_duplicates(self): "[EditingContext] fetchCount is not affected by duplicates" @@ -1320,6 +1394,47 @@ self.failUnless(len(objects)==1) self.failUnless('Dard' in objects_names) + def test_29_bug621210(self): + "[EditingContext] Infinite loop when defining __cmp__" + # Note: bug #621210 is in fact tested not only w/ this test, but also + # globally. See notes at the beginning of this file, and changes + # introduced in revision 988. + ec=EditingContext() + from new import instancemethod + def invalid_call_fct(msg): + def invalid_call(self, o, msg): + raise 'Invalid call of %s in %s'%(msg,self) + return lambda s,o,fct=invalid_call,msg=msg: fct(s,o,msg) + Writer.__cmp__ = instancemethod(invalid_call_fct('__cmp__'), None, Writer) + Writer.__eq__ = instancemethod(invalid_call_fct('__eq__'), None, Writer) + Writer.__ne__ = instancemethod(invalid_call_fct('__ne__'), None, Writer) + + gargantua=ec.fetch('Book', 'title == "Gargantua"')[0] + rabelais = gargantua.getAuthor() + self.failUnless(rabelais.isFault()) + rabelais.getLastName() + + def _test_29_fetch_backslash(self): + "[EditingContext] fetch real backslash" + # bug # + ec=EditingContext() + b1=Book(); b1.setTitle(r'abc\n') + b2=Book(); b2.setTitle('abc\\\\') + b3=Book(); b3.setTitle('\\') + ec.insert(b1); ec.insert(b2); ec.insert(b3) + ec.saveChanges() + + res=ec.fetch('Book', 'title == "abc\\n"') + self.assertEqual(len(res), 1) + self.assertEqual(res[0].getTitle(), r"abc\n") + res=ec.fetch('Book', 'title == "\\"') + self.assertEqual(len(res), 1) + self.assertEqual(res[0].getTitle(), "\\") + #res=ec.fetch('Book', 'title like "*abc%d*"') + #self.assertEqual(len(res), 1) + #self.assertEqual(res[0].getTitle(), "abc%d") + # TBD: with LIKE and ILIKE + def test_999_customSQLQuery(self): "[EditingContext] custom SQL Query" fs=FetchSpecification(entityName='Writer') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sbi...@us...> - 2006-04-19 19:39:32
|
Revision: 994 Author: sbigaret Date: 2006-04-19 12:39:18 -0700 (Wed, 19 Apr 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=994&view=rev Log Message: ----------- Fix for bug #1471992: objects w/ values containing a single backslash are not properly handled by the MySQL and Postgresql adaptor layers Modified Paths: -------------- trunk/ProjectModeling/CHANGES trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLSQLExpression.py trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/PostgresqlSQLExpression.py trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py Modified: trunk/ProjectModeling/CHANGES =================================================================== --- trunk/ProjectModeling/CHANGES 2006-04-15 09:48:43 UTC (rev 993) +++ trunk/ProjectModeling/CHANGES 2006-04-19 19:39:18 UTC (rev 994) @@ -7,6 +7,11 @@ ** Distributed under a 3-clause BSD-style license, see LICENSE for details ** ----------------------------------------------------------------------------- + * Fixed bug #1471992: objects w/ values containing a single backslash are + not properly handled by the MySQL and Postgresql adaptor layer (the + generated SQLExpression are incorrect; for example, insertions of such + objects failed) + * Fixed bug #621210: when __cmp__ (and/or, possibly, other special methods such as __eq__ or __ne__) was defined in a CustomObject, it was possible to enter a infinite loop. The fix consisted in making sure that the Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLSQLExpression.py =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLSQLExpression.py 2006-04-15 09:48:43 UTC (rev 993) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLSQLExpression.py 2006-04-19 19:39:18 UTC (rev 994) @@ -235,7 +235,24 @@ else: return SQLExpression.sqlStringForSelector(self, selector, value) + def sqlStringForString(self, aString): + """ + Formats 'aString' and returns the string suitable for inclusion in a SQL + statement. SQLExpression's implementation surrounds the string with + simple quotes, and back-quotes any simple quotes 'aString' may have. + It returns 'NULL' if 'aString' is None. + See also: formatValueForAttribute() + """ + if aString is not None: + # quote the string: interprets the strings + aString = repr(aString)[1:-1] + from Modeling.SQLExpression import escapeQuote + str=escapeQuote.sub("\\'", aString) + return "'"+str+"'" + else: + return 'NULL' + if mysql_server_version()[:2]>=(4,0): MySQLSQLExpression.SQL92_join=1 else: Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/PostgresqlSQLExpression.py =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/PostgresqlSQLExpression.py 2006-04-15 09:48:43 UTC (rev 993) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/PostgresqlSQLExpression.py 2006-04-19 19:39:18 UTC (rev 994) @@ -25,20 +25,7 @@ from Modeling.SQLExpression import SQLExpression, DateType, CharacterType import string -import re -esc_question_tmp_replct='MDL_ESCAPED_QUESTION_MARK_MDL' -esc_star_tmp_replct='MDL_ESCAPED_STAR_MDL' - -star=re.compile('\*') -escaped_star=re.compile(r'\\\*') -question_mark=re.compile('\?') -escaped_question_mark=re.compile(r'\\\?') -percent=re.compile('%') -underscore=re.compile('_') -anti_escaped_star=re.compile(esc_star_tmp_replct) -anti_esc_question_mark=re.compile(esc_question_tmp_replct) - class PostgresqlSQLExpression(SQLExpression): """ @@ -46,6 +33,25 @@ valueTypeForExternalTypeMapping() to add some new """ + def ____addInsertListAttribute(self, attribute, value): + """ + + Parameters: + + attribute -- an Attribute object + + value -- the value to store + + """ + sqlAttr=self.sqlStringForAttributeNamed(attribute.name()) + sqlValue=self.sqlStringForValue(value, attribute.name()) + #print '### sqlAttr: %s / sqlValue: %s'%(sqlAttr, sqlValue) + self.appendItemToListString(sqlAttr, self._listString) + import pdb ; pdb.set_trace() + if type(sqlValue) is type(''): + sqlValue = repr(sqlValue) + self.appendItemToListString(sqlValue, self._valueList) + def columnTypeStringForAttribute(self, attribute): """ Overrides default implementation to handle TEXT field properly. @@ -107,21 +113,24 @@ """ return '\\\\' - def sqlPatternFromShellPatternWithEscapeCharacter(self, pattern, escapeChar): + def sqlStringForString(self, aString): """ - Overrides default behaviour so that '%' is changed to '\\%' instead of - '\%': postgresql interprets backslashes in strings + Formats 'aString' and returns the string suitable for inclusion in a SQL + statement. SQLExpression's implementation surrounds the string with + simple quotes, and back-quotes any simple quotes 'aString' may have. + It returns 'NULL' if 'aString' is None. + + See also: formatValueForAttribute() """ - pattern=percent.sub(r'\\\\%', pattern) - pattern=underscore.sub(r'\\\\_', pattern) - pattern=escaped_question_mark.sub(esc_question_tmp_replct, pattern) - pattern=question_mark.sub('_', pattern) - pattern=escaped_star.sub(esc_star_tmp_replct, pattern) - pattern=star.sub('%', pattern) - pattern=anti_escaped_star.sub('*', pattern) - pattern=anti_esc_question_mark.sub('?', pattern) - return pattern - + if aString is not None: + # quote the string: postgresql interprets the strings + aString = repr(aString)[1:-1] + from Modeling.SQLExpression import escapeQuote + str=escapeQuote.sub("\\'", aString) + return "'"+str+"'" + else: + return 'NULL' + def valueTypeForExternalTypeMapping(self): """ Modified: trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py =================================================================== --- trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py 2006-04-15 09:48:43 UTC (rev 993) +++ trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py 2006-04-19 19:39:18 UTC (rev 994) @@ -1414,22 +1414,31 @@ self.failUnless(rabelais.isFault()) rabelais.getLastName() - def _test_29_fetch_backslash(self): + def test_30_fetch_backslash(self): "[EditingContext] fetch real backslash" # bug # ec=EditingContext() - b1=Book(); b1.setTitle(r'abc\n') - b2=Book(); b2.setTitle('abc\\\\') - b3=Book(); b3.setTitle('\\') - ec.insert(b1); ec.insert(b2); ec.insert(b3) + b1=Book(); b1.setPrice(1.0); b1.setTitle(r'abc\n') + b2=Book(); b2.setPrice(2.0); b2.setTitle('abc\n') + b3=Book(); b3.setPrice(3.0); b3.setTitle('\\') + b4=Book(); b4.setPrice(4.0); b4.setTitle(r'\\') + ec.insert(b1); ec.insert(b2); ec.insert(b3); ec.insert(b4) ec.saveChanges() res=ec.fetch('Book', 'title == "abc\\n"') self.assertEqual(len(res), 1) self.assertEqual(res[0].getTitle(), r"abc\n") + self.assertEqual(res[0].getPrice(), 1) + + res=ec.fetch('Book', 'title == "abc\n"') + self.assertEqual(len(res), 1) + self.assertEqual(res[0].getTitle(), "abc\n") + self.assertEqual(res[0].getPrice(), 2) + res=ec.fetch('Book', 'title == "\\"') self.assertEqual(len(res), 1) self.assertEqual(res[0].getTitle(), "\\") + self.assertEqual(res[0].getPrice(), 3) #res=ec.fetch('Book', 'title like "*abc%d*"') #self.assertEqual(len(res), 1) #self.assertEqual(res[0].getTitle(), "abc%d") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sbi...@us...> - 2006-04-19 20:31:10
|
Revision: 995 Author: sbigaret Date: 2006-04-19 13:30:59 -0700 (Wed, 19 Apr 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=995&view=rev Log Message: ----------- Fixed bug #855257 and #918092: objects w/ string values containing simple quotes, and fetch requests containing simple quotes, were not properly handled by the SQLite and Oracle adaptor layers Modified Paths: -------------- trunk/ProjectModeling/CHANGES trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLSQLExpression.py trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/PostgresqlSQLExpression.py trunk/ProjectModeling/Modeling/SQLExpression.py trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py Modified: trunk/ProjectModeling/CHANGES =================================================================== --- trunk/ProjectModeling/CHANGES 2006-04-19 19:39:18 UTC (rev 994) +++ trunk/ProjectModeling/CHANGES 2006-04-19 20:30:59 UTC (rev 995) @@ -7,8 +7,14 @@ ** Distributed under a 3-clause BSD-style license, see LICENSE for details ** ----------------------------------------------------------------------------- + * Fixed bug #855257 and #918092: objects w/ string values containing simple + quotes, and fetch requests containing simple quotes, were not properly + handled by the SQLite and Oracle adaptor layers (they were escaped with + backslashes, they are now replaced by two consecutive single quotes, + following the SQL standard) + * Fixed bug #1471992: objects w/ values containing a single backslash are - not properly handled by the MySQL and Postgresql adaptor layer (the + not properly handled by the MySQL and Postgresql adaptor layers (the generated SQLExpression are incorrect; for example, insertions of such objects failed) Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLSQLExpression.py =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLSQLExpression.py 2006-04-19 19:39:18 UTC (rev 994) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLSQLExpression.py 2006-04-19 20:30:59 UTC (rev 995) @@ -238,8 +238,9 @@ def sqlStringForString(self, aString): """ Formats 'aString' and returns the string suitable for inclusion in a SQL - statement. SQLExpression's implementation surrounds the string with - simple quotes, and back-quotes any simple quotes 'aString' may have. + statement. This method surrounds the string with simple quotes, so, every + simple quote in 'aString' is transformed into a sequence a two simple + quotes. Single backslashes are escaped as well. It returns 'NULL' if 'aString' is None. See also: formatValueForAttribute() @@ -248,7 +249,7 @@ # quote the string: interprets the strings aString = repr(aString)[1:-1] from Modeling.SQLExpression import escapeQuote - str=escapeQuote.sub("\\'", aString) + str=escapeQuote.sub("''", aString) return "'"+str+"'" else: return 'NULL' Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/PostgresqlSQLExpression.py =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/PostgresqlSQLExpression.py 2006-04-19 19:39:18 UTC (rev 994) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/PostgresqlAdaptorLayer/PostgresqlSQLExpression.py 2006-04-19 20:30:59 UTC (rev 995) @@ -116,8 +116,9 @@ def sqlStringForString(self, aString): """ Formats 'aString' and returns the string suitable for inclusion in a SQL - statement. SQLExpression's implementation surrounds the string with - simple quotes, and back-quotes any simple quotes 'aString' may have. + statement. This method surrounds the string with simple quotes, so, every + simple quote in 'aString' is transformed into a sequence a two simple + quotes. Single backslashes are escaped as well. It returns 'NULL' if 'aString' is None. See also: formatValueForAttribute() @@ -126,7 +127,7 @@ # quote the string: postgresql interprets the strings aString = repr(aString)[1:-1] from Modeling.SQLExpression import escapeQuote - str=escapeQuote.sub("\\'", aString) + str=escapeQuote.sub("''", aString) return "'"+str+"'" else: return 'NULL' Modified: trunk/ProjectModeling/Modeling/SQLExpression.py =================================================================== --- trunk/ProjectModeling/Modeling/SQLExpression.py 2006-04-19 19:39:18 UTC (rev 994) +++ trunk/ProjectModeling/Modeling/SQLExpression.py 2006-04-19 20:30:59 UTC (rev 995) @@ -1387,14 +1387,15 @@ def sqlStringForString(self, aString): """ Formats 'aString' and returns the string suitable for inclusion in a SQL - statement. SQLExpression's implementation surrounds the string with - simple quotes, and back-quotes any simple quotes 'aString' may have. + statement. This method surrounds the string with simple quotes, so, every + simple quote in 'aString' is transformed into a sequence a two simple + quotes. It returns 'NULL' if 'aString' is None. See also: formatValueForAttribute() """ if aString is not None: - str=escapeQuote.sub("\\'", aString) + str=escapeQuote.sub("''", aString) return "'"+str+"'" else: return 'NULL' Modified: trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py =================================================================== --- trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py 2006-04-19 19:39:18 UTC (rev 994) +++ trunk/ProjectModeling/Modeling/tests/test_EditingContext_Global.py 2006-04-19 20:30:59 UTC (rev 995) @@ -1425,16 +1425,19 @@ ec.insert(b1); ec.insert(b2); ec.insert(b3); ec.insert(b4) ec.saveChanges() + ec=EditingContext() res=ec.fetch('Book', 'title == "abc\\n"') self.assertEqual(len(res), 1) self.assertEqual(res[0].getTitle(), r"abc\n") self.assertEqual(res[0].getPrice(), 1) + ec=EditingContext() res=ec.fetch('Book', 'title == "abc\n"') self.assertEqual(len(res), 1) self.assertEqual(res[0].getTitle(), "abc\n") self.assertEqual(res[0].getPrice(), 2) + ec=EditingContext() res=ec.fetch('Book', 'title == "\\"') self.assertEqual(len(res), 1) self.assertEqual(res[0].getTitle(), "\\") @@ -1444,6 +1447,37 @@ #self.assertEqual(res[0].getTitle(), "abc%d") # TBD: with LIKE and ILIKE + def test_31_insert_and_fetch_single_quotes(self): + "[EditingContext] insert and fetch single quotes" + # bug #855257 and #918092 + ec=EditingContext() + b1=Book(); b1.setPrice(1.0); b1.setTitle("ab'c") + b2=Book(); b2.setPrice(2.0); b2.setTitle("'") + b3=Book(); b3.setPrice(3.0); b3.setTitle("ab''c") + ec.insert(b1); ec.insert(b2); ec.insert(b3) + ec.saveChanges() # should not fail + + ec=EditingContext() + res=ec.fetch('Book', 'title == "ab\'\'c"') + self.assertEqual(len(res), 1) + self.assertEqual(res[0].getTitle(), "ab''c") + self.assertEqual(res[0].getPrice(), 3) + + ec=EditingContext() + res=ec.fetch('Book', 'title == "ab\'c"') + self.assertEqual(len(res), 1) + self.assertEqual(res[0].getTitle(), "ab'c") + self.assertEqual(res[0].getPrice(), 1) + + res=ec.fetch('Book', 'title == "\'"') + self.assertEqual(len(res), 1) + self.assertEqual(res[0].getTitle(), "'") + self.assertEqual(res[0].getPrice(), 2) + + ec=EditingContext() + res=ec.fetch('Book', '''title == "ab''''c"''') + self.assertEqual(len(res), 0) + def test_999_customSQLQuery(self): "[EditingContext] custom SQL Query" fs=FetchSpecification(entityName='Writer') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sbi...@us...> - 2006-04-22 18:47:15
|
Revision: 999 Author: sbigaret Date: 2006-04-22 11:47:08 -0700 (Sat, 22 Apr 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=999&view=rev Log Message: ----------- Fixed bug #1474720: when saving changes, the PKs needed for the inserted objects were retrieved one after the other, opening and closing a transaction for every PK Modified Paths: -------------- trunk/ProjectModeling/CHANGES trunk/ProjectModeling/Modeling/DatabaseContext.py Modified: trunk/ProjectModeling/CHANGES =================================================================== --- trunk/ProjectModeling/CHANGES 2006-04-22 18:36:10 UTC (rev 998) +++ trunk/ProjectModeling/CHANGES 2006-04-22 18:47:08 UTC (rev 999) @@ -7,6 +7,12 @@ ** Distributed under a 3-clause BSD-style license, see LICENSE for details ** ----------------------------------------------------------------------------- + * Fixed bug #1474720: when saving changes, the PKs needed for the inserted + objects are retrieved one after the other, opening and closing a + transaction for every PK. PKs are now fetched by batch, in a single + transaction for all objects having the same entity. + This should make inserting a lot of objects really faster. + * Feature request #1011515: Configurability of ABORT/COMMIT on read-only transactions (for postgresql). Modified: trunk/ProjectModeling/Modeling/DatabaseContext.py =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseContext.py 2006-04-22 18:36:10 UTC (rev 998) +++ trunk/ProjectModeling/Modeling/DatabaseContext.py 2006-04-22 18:47:08 UTC (rev 999) @@ -1066,18 +1066,23 @@ # get the primary keys for inserted objects - # this could be made more efficient if PKs were asked within a single - # round-trip to the DB + # 1st: sort the inserted objects by entity + # 2nd: fetch the primary keys, one entity after the other + # The purpose is to make one and only one round-trip to the db + # (==one transaction) per entity self.lock() try: channel=self.availableChannel().adaptorChannel() + entity_to_gids={} for gID in self._inserted_gIDs: - entity=ec.objectForGlobalID(gID).classDescription().entity() - pk=channel.primaryKeysForNewRowsWithEntity(1, entity) - self._pks_for_inserted_gIDs[gID]=pk[0] - - newGid=KeyGlobalID(entity.name(), self._pks_for_inserted_gIDs[gID]) - self.__temporaryGID_to_KeyGlobalID[gID]=newGid + entity_to_gids.setdefault(ec.objectForGlobalID(gID).classDescription().entity(), []).append(gID) + + for entity, gIDs in entity_to_gids.items(): + pks=channel.primaryKeysForNewRowsWithEntity(len(gIDs), entity) + for gID, pk in map(None, gIDs, pks): + self._pks_for_inserted_gIDs[gID]=pk + newGid=KeyGlobalID(entity.name(), self._pks_for_inserted_gIDs[gID]) + self.__temporaryGID_to_KeyGlobalID[gID]=newGid finally: self.unlock() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sbi...@us...> - 2006-04-22 19:07:23
|
Revision: 1000 Author: sbigaret Date: 2006-04-22 12:07:12 -0700 (Sat, 22 Apr 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=1000&view=rev Log Message: ----------- Feature Request #978800: "SQLite adaptor: get X primary keys at once". PKs are now retrieved in a single request Modified Paths: -------------- trunk/ProjectModeling/CHANGES trunk/ProjectModeling/Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/SQLiteAdaptorChannel.py Modified: trunk/ProjectModeling/CHANGES =================================================================== --- trunk/ProjectModeling/CHANGES 2006-04-22 18:47:08 UTC (rev 999) +++ trunk/ProjectModeling/CHANGES 2006-04-22 19:07:12 UTC (rev 1000) @@ -7,6 +7,9 @@ ** Distributed under a 3-clause BSD-style license, see LICENSE for details ** ----------------------------------------------------------------------------- + * Feature Request #978800: "SQLite adaptor: get X primary keys at once" + PKs are now retrieved in a single request. + * Fixed bug #1474720: when saving changes, the PKs needed for the inserted objects are retrieved one after the other, opening and closing a transaction for every PK. PKs are now fetched by batch, in a single Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/SQLiteAdaptorChannel.py =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/SQLiteAdaptorChannel.py 2006-04-22 18:47:08 UTC (rev 999) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/SQLiteAdaptorLayer/SQLiteAdaptorChannel.py 2006-04-22 19:07:12 UTC (rev 1000) @@ -69,23 +69,22 @@ try: pkName=anEntity.primaryKeyAttributeNames()[0] pkRootName=anEntity.primaryKeyRootName() - statements=["UPDATE PK_SEQ_%s SET id=((select max(id) from PK_SEQ_%s)+1)"%(pkRootName,pkRootName), + statements=["UPDATE PK_SEQ_%s SET id=((select max(id) from PK_SEQ_%s)+%i)"%(pkRootName,pkRootName,count), "select id FROM PK_SEQ_%s"%pkRootName] - result=[] - for idx in range(count): - for statement in statements: - db_info('Evaluating: %s'%statement) - try: - self.dbAPI_cursor().execute(statement) - except: - exctype, value = sys.exc_info()[:2] - msg="Couldn't evaluate expression %s. Reason: %s:%s"%(statement, exctype, value) - db_error(msg) - raise GeneralAdaptorException, msg - - SQLiteAdaptorChannel._count_for_execute+=1 + for statement in statements: + db_info('Evaluating: %s'%statement) + try: + self.dbAPI_cursor().execute(statement) + except: + exctype, value = sys.exc_info()[:2] + msg="Couldn't evaluate expression %s. Reason: %s:%s"%(statement, exctype, value) + db_error(msg) + raise GeneralAdaptorException, msg + + SQLiteAdaptorChannel._count_for_execute+=1 - result.append({pkName :self.dbAPI_cursor().fetchone()[0]}) + result = self.dbAPI_cursor().fetchone()[0] + result = [{pkName : v+1} for v in range(result-count,result)] return tuple(result) finally: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sbi...@us...> - 2006-04-22 22:22:51
|
Revision: 1001 Author: sbigaret Date: 2006-04-22 15:22:45 -0700 (Sat, 22 Apr 2006) ViewCVS: http://svn.sourceforge.net/modeling/?rev=1001&view=rev Log Message: ----------- Feature Request #978800 extended for MySQL: PKs are also fetched in a single request (instead of n requests in one transaction) Modified Paths: -------------- trunk/ProjectModeling/CHANGES trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLAdaptorChannel.py Modified: trunk/ProjectModeling/CHANGES =================================================================== --- trunk/ProjectModeling/CHANGES 2006-04-22 19:07:12 UTC (rev 1000) +++ trunk/ProjectModeling/CHANGES 2006-04-22 22:22:45 UTC (rev 1001) @@ -7,8 +7,12 @@ ** Distributed under a 3-clause BSD-style license, see LICENSE for details ** ----------------------------------------------------------------------------- + * Feature Request #978800 extended for MySQL: PKs are also fetched in a + single request (instead of n requests in one transaction) + * Feature Request #978800: "SQLite adaptor: get X primary keys at once" - PKs are now retrieved in a single request. + PKs are now retrieved in a single request (instead of n requests in one + transaction) * Fixed bug #1474720: when saving changes, the PKs needed for the inserted objects are retrieved one after the other, opening and closing a Modified: trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLAdaptorChannel.py =================================================================== --- trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLAdaptorChannel.py 2006-04-22 19:07:12 UTC (rev 1000) +++ trunk/ProjectModeling/Modeling/DatabaseAdaptors/MySQLAdaptorLayer/MySQLAdaptorChannel.py 2006-04-22 22:22:45 UTC (rev 1001) @@ -68,23 +68,23 @@ try: pkName=anEntity.primaryKeyAttributeNames()[0] pkRootName=anEntity.primaryKeyRootName() - statements=["UPDATE PK_SEQ_%s SET id=LAST_INSERT_ID(id+1)"%pkRootName, + statements=["UPDATE PK_SEQ_%s SET id=LAST_INSERT_ID(id+%i)"%(pkRootName,count), "select LAST_INSERT_ID()"] result=[] - for idx in range(count): - for statement in statements: - db_info('Evaluating: %s'%statement) - try: - self.dbAPI_cursor().execute(statement) - except: - exctype, value = sys.exc_info()[:2] - msg="Couldn't evaluate expression %s. Reason: %s:%s"%(statement, exctype, value) - db_error(msg) - raise GeneralAdaptorException, msg - - MySQLAdaptorChannel._count_for_execute+=1 + for statement in statements: + db_info('Evaluating: %s'%statement) + try: + self.dbAPI_cursor().execute(statement) + except: + exctype, value = sys.exc_info()[:2] + msg="Couldn't evaluate expression %s. Reason: %s:%s"%(statement, exctype, value) + db_error(msg) + raise GeneralAdaptorException, msg + + MySQLAdaptorChannel._count_for_execute+=1 - result.append({pkName :self.dbAPI_cursor().fetchone()[0]}) + result = self.dbAPI_cursor().fetchone()[0] + result = [{pkName : v+1} for v in range(result-count,result)] return tuple(result) finally: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |