modeling-users Mailing List for Object-Relational Bridge for python (Page 18)
Status: Abandoned
Brought to you by:
sbigaret
You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(2) |
Sep
(3) |
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(19) |
Feb
(55) |
Mar
(54) |
Apr
(48) |
May
(41) |
Jun
(40) |
Jul
(156) |
Aug
(56) |
Sep
(90) |
Oct
(14) |
Nov
(41) |
Dec
(32) |
2004 |
Jan
(6) |
Feb
(57) |
Mar
(38) |
Apr
(23) |
May
(3) |
Jun
(40) |
Jul
(39) |
Aug
(82) |
Sep
(31) |
Oct
(14) |
Nov
|
Dec
(9) |
2005 |
Jan
|
Feb
(4) |
Mar
(13) |
Apr
|
May
(5) |
Jun
(2) |
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
(1) |
2006 |
Jan
(1) |
Feb
(1) |
Mar
(9) |
Apr
(1) |
May
|
Jun
(1) |
Jul
(5) |
Aug
|
Sep
(5) |
Oct
(1) |
Nov
|
Dec
|
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(2) |
Nov
(1) |
Dec
|
2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(4) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Mario R. <ma...@ru...> - 2003-12-04 09:43:31
|
Hi, two small questions that I do not remember/find the answer for... Can anyone remind me: - how to best incorporate a constraint that a (non-primary, string) attribute value should be unique ? - how to best handle enumeration attributes ? - how to best handle the single quote character when writing out string values ? (unescaped gives error for sqlite) Cheers, mario |
From: Mario R. <ma...@ru...> - 2003-12-04 05:59:33
|
> Mario Ruggier <ma...@ru...> wrote: >> [...] >> This reminds me of a problem that I meant to report though: >> - I create an object with a date attribute (value for attribute set >> with >> mx.DateTime.now()), but without doing ec.saveChanges() >> - then if I fetch the object with >> ec.fetch('MyClass', >> qualifier = 'createdate=="%s"' %(myObject.getDateattr()) ) >> the fetch does not return the newly created object. >> This may be a bug, but I can confirm after playing with it further. > > This would help if you had a working test case, yes ;) Fair enough ;) I have made a simple object with just a DateTime attribute, so in the pymodel it looks like : Entity('MyObj', properties=[ ADateTime('createdate',displayLabel='Date',isRequired=1), ] ) Then I made the following test that uses it: def test_0_FetchUnSavedDateTime(self): ec = EditingContext() o = MyObj() test_datetime = mx.DateTime.now() q = 'createdate=="%s"' %(test_datetime) o.setCreatedate(test_datetime) ec.insert(o) ec.saveChanges() print test_datetime, print ec.fetch('MyObj',qualifier=q)[0] o2 = MyObj() test_datetime2 = mx.DateTime.now() q2 = 'createdate=="%s"' %(test_datetime2) o2.setCreatedate(test_datetime2) ec.insert(o2) #ec.saveChanges() print test_datetime2, print ec.fetch('MyObj',qualifier=q2)[0] The first fetch is OK, the second is not. This is with SQLite and Modleing CVS. Cheers, mario |
From: Sebastien B. <sbi...@us...> - 2003-12-02 17:16:14
|
Mario Ruggier <ma...@ru...> wrote: > [...] > This reminds me of a problem that I meant to report though: > - I create an object with a date attribute (value for attribute set with > mx.DateTime.now()), but without doing ec.saveChanges() > - then if I fetch the object with > ec.fetch('MyClass', > qualifier =3D 'createdate=3D=3D"%s"' %(myObject.getDateattr()= ) ) > the fetch does not return the newly created object. > This may be a bug, but I can confirm after playing with it further. This would help if you had a working test case, yes ;)=20 -- S=E9bastien. |
From: Sebastien B. <sbi...@us...> - 2003-12-02 17:13:10
|
Hi, It was not clear to me why this was not working for you until I realized that the following statement: >>> ec.fetch('Writer', "birthday>1970-01-01 00:00:00.00") leads exactly to what you describe (libpq.OperationalError:ERROR: bad timestamp external representation '1970'). You've found a bug here, the QualifierPaser has not detected that the qualifier string you passed to it has a syntax error. Those two are correct, however, and should work as you expect: ec.fetch('Writer', 'birthday>"1970-01-01 00:00:00.00"') ec.fetch('Writer', 'birthday>"%s"' % str(DateTime(1970,01,01))) --and yes, this is a limitation of the parser, it only accepts double quo= tes around strings in qualifiers. Hopefully this solves the problem. If you still have difficulties, please tell. And thanks for reporting, I'll try to correct the bug in the parser f= or the next release. -- S=E9bastien. |
From: Mario R. <ma...@ru...> - 2003-12-01 17:16:32
|
Hi Lukasz, not clear to me why you are concatenating the qualifer string the way you are. Using mx.DateTime for date fields, I can then do this in my qualifier to include a condition on the date value of the table column "createdate" for the fetch: q_part_whatever =3D ' ... ' q_date =3D 'createdate<"%s"' %(customObject.getCreatedate()) qualifier =3D ' AND '.join([ q_part_whatever, q_date]) This works. Not sure if there is a nicer way to do it though. This reminds me of a problem that I meant to report though: - I create an object with a date attribute (value for attribute set with mx.DateTime.now()), but without doing ec.saveChanges() - then if I fetch the object with ec.fetch('MyClass', qualifier =3D 'createdate=3D=3D"%s"' = %(myObject.getDateattr()) ) the fetch does not return the newly created object. This may be a bug, but I can confirm after playing with it further. Cheers, mario > Hi > > I've got some problem with conditions that using dates. The following > examlple shows this. > > ERD: > MaWychowawce > Klasa|<<--------------->|Nauczyciel > -----| |------------ > |attr: DataUrodzenia > > code: > --------------------------------------------------------------------- > warunek=3D'MaWychowawce.DataUrodzenia > '+str(DateTime(1970,1,1)) > print warunek > klasy=3DEC.fetch('Klasa',qualifier=3Dwarunek) > --------------------------------------------------------------------- > > Printed qualifier look like this: MaWychowawce.DataUrodzenia > =20 > 1970-01-01 > 00:00:00.00 > I've tried with: MaWychowawce.DataUrodzenia > '1970-01-01 00:00:00.00' = =20 > but > it also didn't work > Conditions on another attributes in 'Nauczyciel' works perfectly. > > error > --------------------------------------- > Couldn't evaluate expression SELECT DISTINCT t0.KLASA_ID, t0.NAZWA, > t0.PROFIL, t0.WYCHOWAWCA_ID FROM KLASA t0 INNER JOIN NAUCZYCIEL t1 ON > t0.WYCHOWAWCA_ID=3Dt1.NAUCZYCIEL_ID WHERE t1.DATA_URODZENIA > '1970'. =20= > Reason: > libpq.OperationalError:ERROR: bad timestamp external representation =20= > '1970' > > Traceback (most recent call last): > File "<stdin>", line 1, in ? > File "Baza.py", line 45, in PobierzDane > klasy=3DEC.fetch('Klasa',qualifier=3Dwarunek) > File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\EditingContext.py", line =20= > 1419, in > fetch > return self.objectsWithFetchSpecification(fs) > File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\EditingContext.py", line =20= > 1302, in > objectsWithFetchSpecification > objects=3Dself.parentObjectStore().objectsWithFetchSpecification(fs,= =20 > ec) > File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\ObjectStoreCoordinator.py", = =20 > line > 434, in objectsWithFetchSpecification > return store.objectsWithFetchSpecification(aFetchSpecification, > anEditingContext) > File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\DatabaseContext.py", line =20= > 1817, > in objectsWithFetchSpecification > anEditingContext) > File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\DatabaseChannel.py", line =20= > 394, in > selectObjectsWithFetchSpecification > entity) > File > = "C:\PROGRA~1\Zope2.6.2\bin\Modeling\DatabaseAdaptors\AbstractDBAPI2Adap=20= > torLa > yer\AbstractDBAPI2AdaptorChannel.py", line 297, in selectAttributes > raise GeneralAdaptorException, msg > Modeling.Adaptor.GeneralAdaptorException: Couldn't evaluate expression > SELECT DISTINCT t0.KLASA_ID, t0.NAZWA, t0.PROFIL, t0.WYCHOWAWCA_ID = FROM > KLASA t0 INNER JO > IN NAUCZYCIEL t1 ON t0.WYCHOWAWCA_ID=3Dt1.NAUCZYCIEL_ID WHERE > t1.DATA_URODZENIA > '1970'. Reason: libpq.OperationalError:ERROR: Bad > timestamp external representation '1970' > ------------------------------------ > > Is there any explanation? > > > **************************** > * =A3ukasz =A3akomy > * luk...@po... > **************************** > > > > > ------------------------------------------------------- > This SF.net email is sponsored by: SF.net Giveback Program. > Does SourceForge.net help you be more productive? Does it > help you create better code? SHARE THE LOVE, and help us help > YOU! Click Here: http://sourceforge.net/donate/ > _______________________________________________ > Modeling-users mailing list > Mod...@li... > https://lists.sourceforge.net/lists/listinfo/modeling-users |
From: Sebastien B. <sbi...@us...> - 2003-12-01 17:10:41
|
Hi all, Let me expose a bug in the framework that can cause data loss when used w/ postgresql and psycopg (and maybe other adaptors as well, I cannot be categorical). There is a bug in the SQL generated for the database schema, involving relationships to entities having subclasses: say you have classes A, B and C, with A being the parent of B and B the parent of C. Now if you design a relationship from A to B and you try to save two objects 'a' and 'c' in relation, oracle and postgresql will fail because the following constraint generated by mdl_generate_DB_schema.py is wrong: ALTER TABLE A ADD CONSTRAINT b FOREIGN KEY (FK_B) REFERENCES B(ID); [in this case A.FK_B can reference either B(ID) or C(ID)] Now the problem is that psycopg DISCARDS the error and does not raise anything (in this case, an IntegrityError) --> nothing is actually written in the database, but ec.saveChanges() returns successfully. This problems happens w/ psycopg only, as far as I know. Other adaptors will either fail (DCOracle2, pgdb, pypresql) with an integrity error, or simply succeed because the underlying db does not enforce the referential constraint (mysql, sqlite). Immediate workaround: in your database schema, drop the constraints coming from to-one relationships pointing to entities having subclasses. Postgresql and Oracle: ALTER TABLE A drop CONSTRAINT <constraint_name>; This will ensure that your data are correctly saved w/ no "false" integrity error, and additionally it will prevent data loss if you're using postgresql and psycopg. (You do not need this if you use sqlite or mysql, as far as I know) -- S=E9bastien. PS: the bug has been reported to the psycopg ml, you can find more details here: http://lists.initd.org/pipermail/psycopg/2003-December/002432.html |
From: <luk...@po...> - 2003-12-01 08:42:33
|
Hi I've got some problem with conditions that using dates. The following examlple shows this. ERD: MaWychowawce Klasa|<<--------------->|Nauczyciel -----| |------------ |attr: DataUrodzenia code: --------------------------------------------------------------------- warunek=3D'MaWychowawce.DataUrodzenia > '+str(DateTime(1970,1,1)) print warunek klasy=3DEC.fetch('Klasa',qualifier=3Dwarunek) --------------------------------------------------------------------- Printed qualifier look like this: MaWychowawce.DataUrodzenia > 1970-01-01 00:00:00.00 I've tried with: MaWychowawce.DataUrodzenia > '1970-01-01 00:00:00.00' bu= t it also didn't work Conditions on another attributes in 'Nauczyciel' works perfectly. error --------------------------------------- Couldn't evaluate expression SELECT DISTINCT t0.KLASA_ID, t0.NAZWA, t0.PROFIL, t0.WYCHOWAWCA_ID FROM KLASA t0 INNER JOIN NAUCZYCIEL t1 ON t0.WYCHOWAWCA_ID=3Dt1.NAUCZYCIEL_ID WHERE t1.DATA_URODZENIA > '1970'. Rea= son: libpq.OperationalError:ERROR: bad timestamp external representation '1970= ' Traceback (most recent call last): File "<stdin>", line 1, in ? File "Baza.py", line 45, in PobierzDane klasy=3DEC.fetch('Klasa',qualifier=3Dwarunek) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\EditingContext.py", line 1419,= in fetch return self.objectsWithFetchSpecification(fs) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\EditingContext.py", line 1302,= in objectsWithFetchSpecification objects=3Dself.parentObjectStore().objectsWithFetchSpecification(fs, = ec) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\ObjectStoreCoordinator.py", li= ne 434, in objectsWithFetchSpecification return store.objectsWithFetchSpecification(aFetchSpecification, anEditingContext) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\DatabaseContext.py", line 1817= , in objectsWithFetchSpecification anEditingContext) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\DatabaseChannel.py", line 394,= in selectObjectsWithFetchSpecification entity) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\DatabaseAdaptors\AbstractDBAPI2Adapto= rLa yer\AbstractDBAPI2AdaptorChannel.py", line 297, in selectAttributes raise GeneralAdaptorException, msg Modeling.Adaptor.GeneralAdaptorException: Couldn't evaluate expression SELECT DISTINCT t0.KLASA_ID, t0.NAZWA, t0.PROFIL, t0.WYCHOWAWCA_ID FROM KLASA t0 INNER JO IN NAUCZYCIEL t1 ON t0.WYCHOWAWCA_ID=3Dt1.NAUCZYCIEL_ID WHERE t1.DATA_URODZENIA > '1970'. Reason: libpq.OperationalError:ERROR: Bad timestamp external representation '1970' ------------------------------------ Is there any explanation? **************************** * =A3ukasz =A3akomy * luk...@po... **************************** |
From: <luk...@po...> - 2003-11-29 15:17:39
|
Hi Thanks Sebastien for all advices. I use both optimization methods and there are my results. They may be interesting. Given time is an average of 10 measurments Fetching one table 'Mothers' with 100 records and three tables related with it: 0. Fetching table in "pure" PostgreSQL by psql: 0.025 seconds With Modeling: 1. Without any optimization: 14.20 seconds 2. Setting permanent DB connection: 1.31 seconds 3. Setting permanent DB connection and batchFetch 1.14 seconds Now, its almost perfect Code after optimization: --------------------- # first optimization import os os.environ['MDL_PERMANENT_DB_CONNECTION']='1' # second optimization def databaseContext(entityName, ec): from Modeling.FetchSpecification import FetchSpecification fs=FetchSpecification(entityName) return ec.rootObjectStore().objectStoreForFetchSpecification(fs) EC=EditingContext() mothers=EC.fetch('Mothers') from Modeling.ModelSet import defaultModelSet dbContext=databaseContext('Mothers', EC) rel=defaultModelSet().entityNamed('Mothers').relationshipNamed('toProvince') # Now fetch all provinces of mothers in a single fetch dbContext.batchFetchRelationship(rel, mothers, EC) for mother in mothers: id=mother.getMothersId() date=mother.getBirthDate() province=mother.gettoProvince().getName() --------------------- (It's Sebastien's code but he make some little mistakes.) > I should probably add this feature to the framework, it's been > regularly asked. Do we want this in the next release? > [...] > PS: as I said it previously when I sent the first version of the patch, > this is not the definitive user-friendly interface ;) There will > probably be a more convenient method at the EditingContext level, > something like ec.batchFetch(mothers, 'toProvince') e.g. It's a VERY good idea. And a question about patches. How to include patch to the file. Now I just copy the code from .patch file to .py file. It is propably some way to do it automaticaly with WinCVS, but I dont know how. **************************** * Lukasz Lakomy * luk...@po... **************************** |
From: John G. <ig...@do...> - 2003-11-28 10:44:03
|
Hi, This is a patch to handle the differences between python 2.2 & 2.3 regarding converting boolean values. It uses the bool() built-in, so I think it won't work for versions of python < 2.2.1 Boolean values such as isClassProperty & isAbstract are written as 0/1 in 2.2 and True/False in 2.3. The model loads fine with either 2.2/2.3 regardless of the version of python it was generated from. I'm not familiar with the code base, so let me know if this breaks something else. cheers john diff -urN Modeling.orig/Attribute.py Modeling/Attribute.py --- Modeling.orig/Attribute.py 2003-09-14 11:35:07.000000000 +0300 +++ Modeling/Attribute.py 2003-11-28 12:18:52.000000000 +0200 @@ -572,6 +572,13 @@ attrType=self.xmlAttributeType(attributeName) set=self.xmlSetAttribute(attributeName) if attrType=='string': value=unicodeToStr(value, encoding) + elif attrType=='number': value=int(value) + elif attrType=='bool': + if value=='False': value=False + else: + try: value=bool(int(value)) + except ValueError: value=bool(value) + set(value) def getXMLDOM(self, doc=None, parentNode=None, encoding='iso-8859-1'): @@ -634,10 +641,10 @@ 'externalType' : ('string', self.setExternalType, self.externalType), - 'isClassProperty' : ('string', + 'isClassProperty' : ('bool', self.setIsClassProperty, self.isClassProperty), - 'isRequired' : ('string', + 'isRequired' : ('bool', self.setIsRequired, self.isRequired), # defaultValue must be loaded AFTER type is set, or we will get the diff -urN Modeling.orig/Entity.py Modeling/Entity.py --- Modeling.orig/Entity.py 2003-11-24 14:12:32.000000000 +0200 +++ Modeling/Entity.py 2003-11-28 12:15:11.000000000 +0200 @@ -1278,6 +1278,12 @@ attrType=self.xmlAttributeType(attributeName) set=self.xmlSetAttribute(attributeName) if attrType=='string': value=unicodeToStr(value, encoding) + elif attrType=='number': value=int(value) + elif attrType=='bool': + if value=='False': value=False + else: + try: value=bool(int(value)) + except ValueError: value=bool(value) set(value) if phase==1: @@ -1405,10 +1411,10 @@ 'externalName': ( 'string', self.setExternalName, self.externalName ), - 'isReadOnly': ( 'string', + 'isReadOnly': ( 'bool', self.setReadOnly, self.isReadOnly ), - 'isAbstract': ( 'string', + 'isAbstract': ( 'bool', self.setIsAbstract, self.isAbstract ), 'moduleName': ( 'string', diff -urN Modeling.orig/Relationship.py Modeling/Relationship.py --- Modeling.orig/Relationship.py 2003-07-28 10:18:59.000000000 +0300 +++ Modeling/Relationship.py 2003-11-28 12:15:37.000000000 +0200 @@ -251,7 +251,12 @@ attrType=self.xmlAttributeType(attributeName) set=self.xmlSetAttribute(attributeName) if attrType=='string': value=unicodeToStr(value, encoding) - if attrType=='number': value=int(value) + elif attrType=='number': value=int(value) + elif attrType=='bool': + if value=='False': value=False + else: + try: value=bool(int(value)) + except ValueError: value=bool(value) set(value) return @@ -303,7 +308,7 @@ 'displayLabel' : ('string', self.setDisplayLabel, self.displayLabel), - 'isClassProperty' : ('number', + 'isClassProperty' : ('bool', self.setIsClassProperty, self.isClassProperty), 'multiplicityLowerBound': ('number', diff -urN Modeling.orig/utils.py Modeling/utils.py --- Modeling.orig/utils.py 2003-11-24 14:12:38.000000000 +0200 +++ Modeling/utils.py 2003-11-27 21:36:56.000000000 +0200 @@ -81,11 +81,11 @@ def toBoolean(param): """ - If param is a string (or unicode) and equals to 0, returns 0 ; otherwise + If param is a string (or unicode) and equals to 0, returns False ; otherwise returns 'not not param'. """ if type(param) in (types.StringType, types.UnicodeType): - if param=='0': return 0 + if param=='0': return False return not not param if sys.version_info < (2, 2): |
From: Sebastien B. <sbi...@us...> - 2003-11-27 10:43:32
|
Hi, <luk...@po...> wrote: > I have some questions about modeling efficency. Lets consider the followi= ng > example: >=20 > Model: > (mother lives in one province, in one province lives many mothers) > [ snipped model: Mother <<------> Province ] > > and python code (my orginal code translated from Polish to English:-): >=20 > EC=3DEditingContext() > mothers=3DEC.fetch('Mothers') > for mother in mothers: > id=3Dmother.getMothersId() > date=3Dmother.getBirthDate() >=20 > # efficency problematic code > province=3Dmother.gettoProvince().getName() >=20 > According to the manual everything is all right, and so it works. But... = in > database there is over 100 records. When I'm fetching the hole databse and > get only Id and BirthDate it takes 0.0 seconds - good. But when I try to = get > the name of the province by toProvince realtion it takes about 0,5 sec for > each row! So presenting this small database takes about minute. >=20 > 1. Am I doing something wrong or this slow working is the feature of > Modeling Framework? You're not doing anything wrong. What happens here is that the province is lazily fetched when needed, meaning that each iteration triggers a fetch when the line=20 > province=3Dmother.gettoProvince().getName() is hit. You can verify this by activating the mdl db-log (env. variable MDL_ENABLE_DATABASE_LOGGING). > 2. Is there any explanation for this or another way to get this data but > much faster? There are two ways of making this faster: 1. by default the framework opens a connection to the db, fetches, then closes the connection; if you do not want that, set the env. variable=20 MDL_PERMANENT_DB_CONNECTION to "1" (see details at http://modeling.sf.net/UserGuide/env-vars-core.html). NB: the reason for this default behaviour originally was that there were problems with psycopg in a MT environment and that seemed to solve this --but the problem is now solved and there is no reason for this to remain the default, we should probably change that. 2. Doing this, the fetch will probably be significantly faster, however you still get one fetch per ietration, which is not that efficient since you know that you'll need all of them anyway, so you probably want to fetch them all. We've discussed this some time ago with Yannick (see https://sf.net/mailarchive/forum.php?thread_id=3D2766300&forum_id=3D10674) and at that time I made a patch for DBContext working w/ to-many relationships only. Since in your case you deal w/ to-one relationships I've updated the patch: https://sf.net/tracker/index.php?func=3Ddetail&aid=3D771009&group_id=3D5893= 5&atid=3D489337 so you can use it w/ to-one relationship as well. Then you can try it like that: ------------------------------------------------------------------------ def databaseContext(entityName, ec): from Modeling.FetchSpecification import FetchSpecification fs=3DFetchSpecification(entityName) return ec.rootObjectStore().objectStoreForFetchSpecification(fs) =20=20 from Modeling.ModelSet import defaultModelSet dbContext=3DdatabaseContext('Company', ec) rel=3DdefaultModelSet().entityNamed('Mothers').relationshipNamed('toProvi= nce') EC=3DEditingContext() mothers=3DEC.fetch('Mothers') =20=20 # Now fetch all provinces of mothers in a single fetch dbContext.batchFetchRelationship(rel, mothers, ec) =20=20 for mother in mothers: id=3Dmother.getMothersId() date=3Dmother.getBirthDate() =20=20 province=3Dmother.gettoProvince().getName() ------------------------------------------------------------------------ This makes the whole fetch even faster (because all the fetching is done in a single roundtrip to the db). BTW is there anyone here still using the original patch for toMany relationships? (Yannick?) I should probably add this feature to the framework, it's been regularly asked. Do we want this in the next release? -- S=E9bastien. PS: as I said it previously when I sent the first version of the patch, this is not the definitive user-friendly interface ;) There will probably be a more convenient method at the EditingContext level, something like ec.batchFetch(mothers, 'toProvince') e.g. |
From: <luk...@po...> - 2003-11-25 12:06:30
|
Hi I have some questions about modeling efficency. Lets consider the followi= ng example: Model: (mother lives in one province, in one province lives many mothers) |------------| |--------------| | Mothers | | Province | |------------|* 1|--------------| | MothersId |-----------| ProvinceId | | BirthDate | | Name | | ProvinceId | | | |------------| |--------------| and python code (my orginal code translated from Polish to English:-): EC=3DEditingContext() mothers=3DEC.fetch('Mothers') for mother in mothers: id=3Dmother.getMothersId() date=3Dmother.getBirthDate() # efficency problematic code province=3Dmother.gettoProvince().getName() According to the manual everything is all right, and so it works. But... = in database there is over 100 records. When I'm fetching the hole databse an= d get only Id and BirthDate it takes 0.0 seconds - good. But when I try to = get the name of the province by toProvince realtion it takes about 0,5 sec fo= r each row! So presenting this small database takes about minute. 1. Am I doing something wrong or this slow working is the feature of Modeling Framework? 2. Is there any explanation for this or another way to get this data but much faster? **************************** * =A3ukasz =A3akomy * luk...@po... **************************** |
From: Mario R. <ma...@ru...> - 2003-11-23 08:22:47
|
Thanks S=E9bastien, that fixes the problem. Running the tests after applying the patch I get the little error below. Not sure if this is coming form this patch or not, but must be a small typo introduced recently. Cheers, mario % python run.py Traceback (most recent call last): File "run.py", line 42, in ? import test_PyModel File "./test_PyModel.py", line 34, in ? from Modeling.PyModel import * File "<string>", line 528 <<<<<<< PyModel.py ^ IndentationError: expected an indented block > Okay, please see ticket #847212 and the patch provided there: > https://sourceforge.net/tracker/=20 > index.php?func=3Ddetail&aid=3D847212&group_id=3D58935&atid=3D489335 > > Thanks for reporting, hopefully this should fix the problem (and =20 > fixes > the very same problem for date, BTW). > > -- S=E9bastien. > > Mario Ruggier <ma...@ru...> wrote: >> Hello! >> >> I am attempting to use the tempting IN operator, however, it doesn't =20= >> like me >> doing that ;) >> The field I am using it on is a nothing-special string attribute: >> >> GeneralAdaptorException: Couldn't evaluate expression SELECT =20 >> COUNT(*) FROM >> SomeTable t0 WHERE ((t0.CREATEDATE > '2003-11-22 09:29:15.65' AND =20 >> t0.ACTION IN >> (one, two, three, four)) AND t0.USERNAME =3D 'john'). Reason: >> _sqlite.DatabaseError:right-hand side of IN operator must be constant >> >> The qualifier that I pass to fetchCount() is: >> >> createdate>"2003-11-22 10:44:53.25" AND action IN =20 >> ["one","two","three","four"] >> AND username=3D=3D"john" >> >> Am I misusing this, or is this a problem with the IN operator? >> >> Cheers, mario > |
From: Sebastien B. <sbi...@us...> - 2003-11-22 19:57:52
|
Hi, <luk...@po...> wrote: > Hi >=20 > I notice a strange behavior. When I import this script showed below all is > ok, Python finds the module "Matki" (sorry for strange names - ther are in > Polish :-). But when I call function "PokazMatki()" I got this error. > Interesting thing is that when I replace > matki=3DEC.fetch('Matki') > with > matki=3DEC.fetch('Matki', rawRows=3D1) > all is ok again. The package "BazaAdresowa" isn't in directory where is t= his > script. The package is in Python directory in subdirectory "GifExtensions= ". > When I copy the package "BazaAdresowa" to the directory where the script = is > everything works fine again. Strange isn't it? Could you give me some > explanation? >=20 > #------ > from mx.DateTime import * > from Modeling.EditingContext import EditingContext > from GifExtensions.BazaAdresowa.Matki import Matki >=20 > def PokazMatki(): > EC=3DEditingContext() > matki=3DEC.fetch('Matki') > #------ This happens because the framework is not able to find the class: I'm quite sure that your model have packageName=3D"BazaAdresowa", with entity's moduleName=3DMatki and className=3DMatki (whatever that means ;) When you fetch, the framework tries to do the equivalent of: "from <packageName>.<moduleName> import <className>",=20 in your case: "from BazaAdresowa.Matki import Matki". But this does not work, because as your script shows it, package BazaAdresowa is in GifExtensions, not in the python path. So the solution is: either add BazaAdresowa in your python path, or change the model so that its package name is "GifExtensions.BazaAdresowa". In any case and as a general rule, wherever in the python code the statement "from <packageName>.<moduleName> import <className>" fails, the framework will equally fails. This is something that should probably be put somewhere, I'll try not to forget and add that to the faq. That's why the framework says: > ImportError: Unable to locate class BazaAdresowa.Matki.Matki corresponding > to entity 'Matki'. > It is possible that the model's packageName, or the entity's moduleName or > className do not correspond to where the module is installed --for exampl= e, > you might have moved it to a sub-package. You can solve this easily by > updating your model so that 'packageName.moduleName.className' points to > the exact location where the class is installed >=20 > Original exception was: ImportError: No module named BazaAdresowa Back on your other question: > Interesting thing is that when I replace > matki=3DEC.fetch('Matki') > with > matki=3DEC.fetch('Matki', rawRows=3D1) > all is ok again. fetch w/ rawRows does not try to instanciate any objects, it just returns a dictionary from the db -> it does not try to import any class in the process, and that's why it does not fail. I hope I succedeed to make it clear, if not, you can keep picking on me ;) -- S=E9bastien. |
From: <luk...@po...> - 2003-11-22 18:44:36
|
Hi I notice a strange behavior. When I import this script showed below all i= s ok, Python finds the module "Matki" (sorry for strange names - ther are i= n Polish :-). But when I call function "PokazMatki()" I got this error. Interesting thing is that when I replace matki=3DEC.fetch('Matki') with matki=3DEC.fetch('Matki', rawRows=3D1) all is ok again. The package "BazaAdresowa" isn't in directory where is t= his script. The package is in Python directory in subdirectory "GifExtensions= ". When I copy the package "BazaAdresowa" to the directory where the script = is everything works fine again. Strange isn't it? Could you give me some explanation? #------ from mx.DateTime import * from Modeling.EditingContext import EditingContext from GifExtensions.BazaAdresowa.Matki import Matki def PokazMatki(): EC=3DEditingContext() matki=3DEC.fetch('Matki') #------ Traceback (most recent call last): File "<stdin>", line 1, in ? File "PS_Baza.py", line 55, in PobierzMatki matki=3DEC.fetch('Matki') File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\EditingContext.py", line 1419,= in fetch return self.objectsWithFetchSpecification(fs) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\EditingContext.py", line 1302,= in objectsWithFetchSpecification objects=3Dself.parentObjectStore().objectsWithFetchSpecification(fs, = ec) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\ObjectStoreCoordinator.py", li= ne 434, in objectsWithFetchSpecification return store.objectsWithFetchSpecification(aFetchSpecification, anEditingContext) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\DatabaseContext.py", line 1765= , in objectsWithFetchSpecification object=3Dchannel.fetchObject() File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\DatabaseChannel.py", line 269,= in fetchObject object=3Dcd.createInstanceWithEditingContext(ec) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\EntityClassDescription.py", li= ne 177, in createInstanceWithEditingContext theClass=3Dself.classForInstances() File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\EntityClassDescription.py", li= ne 161, in classForInstances theClass=3DclassForEntity(self._entity) File "C:\PROGRA~1\Zope2.6.2\bin\Modeling\EntityClassDescription.py", li= ne 521, in classForEntity raise ImportError, err_msg ImportError: Unable to locate class BazaAdresowa.Matki.Matki correspondin= g to entity 'Matki'. It is possible that the model's packageName, or the entity's moduleName o= r className do not correspond to where the module is installed --for exampl= e, you might have moved it to a sub-package. You can solve this easily by updating your model so that 'packageName.moduleName.className' points to the exact location where the class is installed Original exception was: ImportError: No module named BazaAdresowa **************************** * =A3ukasz =A3akomy * luk...@po... **************************** |
From: Sebastien B. <sbi...@us...> - 2003-11-22 13:30:28
|
Okay, please see ticket #847212 and the patch provided there: https://sourceforge.net/tracker/index.php?func=3Ddetail&aid=3D847212&group_= id=3D58935&atid=3D489335 Thanks for reporting, hopefully this should fix the problem (and fixes the very same problem for date, BTW). -- S=E9bastien. Mario Ruggier <ma...@ru...> wrote: > Hello! >=20 > I am attempting to use the tempting IN operator, however, it doesn't like= me > doing that ;) > The field I am using it on is a nothing-special string attribute: >=20 > GeneralAdaptorException: Couldn't evaluate expression SELECT COUNT(*) F= ROM > SomeTable t0 WHERE ((t0.CREATEDATE > '2003-11-22 09:29:15.65' AND t0.ACTI= ON IN > (one, two, three, four)) AND t0.USERNAME =3D 'john'). Reason: > _sqlite.DatabaseError:right-hand side of IN operator must be constant >=20 > The qualifier that I pass to fetchCount() is: >=20 > createdate>"2003-11-22 10:44:53.25" AND action IN ["one","two","three","f= our"] > AND username=3D=3D"john" >=20 > Am I misusing this, or is this a problem with the IN operator? >=20 > Cheers, mario |
From: Sebastien B. <sbi...@us...> - 2003-11-22 12:28:47
|
Hi, This is indeed a bug in the generation of the SQL statement --and a quick check confirms that this affects every adaptors, not only SQLite. I'm gonna look at that. -- S=E9bastien. Mario Ruggier <ma...@ru...> wrote: > Hello! >=20 > I am attempting to use the tempting IN operator, however, it doesn't like= me > doing that ;) > The field I am using it on is a nothing-special string attribute: >=20 > GeneralAdaptorException: Couldn't evaluate expression SELECT COUNT(*) F= ROM > SomeTable t0 WHERE ((t0.CREATEDATE > '2003-11-22 09:29:15.65' AND t0.ACTI= ON IN > (one, two, three, four)) AND t0.USERNAME =3D 'john'). Reason: > _sqlite.DatabaseError:right-hand side of IN operator must be constant >=20 > The qualifier that I pass to fetchCount() is: >=20 > createdate>"2003-11-22 10:44:53.25" AND action IN ["one","two","three","f= our"] > AND username=3D=3D"john" >=20 > Am I misusing this, or is this a problem with the IN operator? >=20 > Cheers, mario |
From: Mario R. <ma...@ru...> - 2003-11-22 10:04:52
|
Hello! I am attempting to use the tempting IN operator, however, it doesn't like me doing that ;) The field I am using it on is a nothing-special string attribute: GeneralAdaptorException: Couldn't evaluate expression SELECT COUNT(*) FROM SomeTable t0 WHERE ((t0.CREATEDATE > '2003-11-22 09:29:15.65' AND t0.ACTION IN (one, two, three, four)) AND t0.USERNAME = 'john'). Reason: _sqlite.DatabaseError:right-hand side of IN operator must be constant The qualifier that I pass to fetchCount() is: createdate>"2003-11-22 10:44:53.25" AND action IN ["one","two","three","four"] AND username=="john" Am I misusing this, or is this a problem with the IN operator? Cheers, mario |
From: Mario R. <ma...@ru...> - 2003-11-19 21:27:01
|
Hello! thanks for the reply! Oh, btw, the little reorganization changes you made on the public web site are a good improvement in my opinion... >> thanks for taking the time to clarify this issue... given that it >> seems that >> others are not often surprised by this, and that making this automatic >> will result in unnecessary overhead, I would be in favour of just >> clarifying >> when this may happen, and how to deal with it (also in the form of a >> nice faq...) > > Seems reasonable, esp. in the light of what follows... > >> Having said this, I still do not fully buy the performance overhead >> argument. See comments below... > [snipped] >> In this particular model, [containing just A and B] >> it is categoric that an A is related to a B (or, >> I guess, a sub-class of B, but not a super-class of B!). >> So, I still do not see why an A is returned, as this does not >> conform to the model -- thus I see this as incorrect behaviour. > > Okay... In fact, I realize that I did not explain the right thing > --what > I explained is more a reason on why the GlobalID for a fault is related > to the root entity, than a reason why the fault itself is an instance > of > the root class. Ah, OK. > I understand your point and agree that this can be seen as an > incorrect behaviour. I need to investigate on that, to see if fixing > this could be a problem in any way (incl. time overhead) --I dunno > for > now. Look forward to what you find out and the estimation for changing this. >>> Now if you clear the fault (b.willRead()), then b.getAs() works as >>> expected. >> >> Fine. At the moment, the (default) code that gets executed when >> a.getB() is called is something like: >> >> def getB(self): >> "Return the b relationship (toOne)" >> self.willRead() >> return self._b >> >> But, what's wrong with doing something like (only when an entity >> participates in an inheritance hierarchy) ? >> >> def getB(self): >> "Return the b relationship (toOne)" >> self.willRead() >> b = self._b >> b.willRead() >> return b >> >> This method is not called all the time b needs to be accessed (as in >> the examples you cite below, right?), so the performance hit >> (associated >> with the _getattr_ suggestion) is minimal. Or am I being too naive >> here? > > You're not ;) But why do you insist that we make it simple when we can > make it complex ?)) Because I'm just a simple guy... ( ... I live from day to day, A ray of sunshine melts my frown, and blows my blues away... ;) > [...] >> Other than the a.getB() explicit calls in client code, when is this >> method called within the framework? > > --> In fact you're absolutely right, and the framework will not call > this on its own: remember that the mdl. uses KeyValueCoding to > access properties, and only private methods (storedValueForKey), > so when obj._prop and obj.getProp() are defined, it always > accesses obj._prop and never calls obj.getProp(). > > Plus, your method is crystal-clear, and does not require any complex > inspection of subclasses or whatsoever... > > Sorry for having obfuscated rather than clarifying the > subject... Luckyly you were attentive on this one. Great. Nice to know that sometimes my gut feeling that things need not be complicated turns out to be correct ;) Unfortunately this is not always the case ;( Cheers, mario |
From: Sebastien B. <sbi...@us...> - 2003-11-17 13:45:21
|
Hi, > thanks for taking the time to clarify this issue... given that it seems t= hat > others are not often surprised by this, and that making this automatic > will result in unnecessary overhead, I would be in favour of just clarify= ing > when this may happen, and how to deal with it (also in the form of a > nice faq...) Seems reasonable, esp. in the light of what follows... > Having said this, I still do not fully buy the performance overhead > argument. See comments below... [snipped] > In this particular model, [containing just A and B] > it is categoric that an A is related to a B (or, > I guess, a sub-class of B, but not a super-class of B!). > So, I still do not see why an A is returned, as this does not > conform to the model -- thus I see this as incorrect behaviour. Okay... In fact, I realize that I did not explain the right thing --what I explained is more a reason on why the GlobalID for a fault is related to the root entity, than a reason why the fault itself is an instance of the root class. I understand your point and agree that this can be seen as an incorrect behaviour. I need to investigate on that, to see if fixing this could be a problem in any way (incl. time overhead) --I dunno for now. > > Now if you clear the fault (b.willRead()), then b.getAs() works as > > expected. >=20 > Fine. At the moment, the (default) code that gets executed when > a.getB() is called is something like: >=20 > def getB(self): > "Return the b relationship (toOne)" > self.willRead() > return self._b >=20 > But, what's wrong with doing something like (only when an entity > participates in an inheritance hierarchy) ? >=20 > def getB(self): > "Return the b relationship (toOne)" > self.willRead() > b =3D self._b > b.willRead() > return b >=20 > This method is not called all the time b needs to be accessed (as in > the examples you cite below, right?), so the performance hit (associated > with the _getattr_ suggestion) is minimal. Or am I being too naive here? You're not ;) But why do you insist that we make it simple when we can make it complex ?)) [...] > Other than the a.getB() explicit calls in client code, when is this > method called within the framework? --> In fact you're absolutely right, and the framework will not call this on its own: remember that the mdl. uses KeyValueCoding to access properties, and only private methods (storedValueForKey), so when obj._prop and obj.getProp() are defined, it always accesses obj._prop and never calls obj.getProp(). Plus, your method is crystal-clear, and does not require any complex inspection of subclasses or whatsoever... =20 Sorry for having obfuscated rather than clarifying the subject... Luckyly you were attentive on this one. -- S=E9bastien. |
From: Mario R. <ma...@ru...> - 2003-11-16 23:15:28
|
Hi, thanks for taking the time to clarify this issue... given that it seems=20= that others are not often surprised by this, and that making this automatic will result in unnecessary overhead, I would be in favour of just=20 clarifying when this may happen, and how to deal with it (also in the form of a nice faq...) Having said this, I still do not fully buy the performance overhead argument. See comments below... > Hi all, > > Back on the subject, now that the problem is identified. I think = this > can be interesting to anyone willing to understand faults and the way > they are handled by the framework, so I'll try there to be as explicit > as possible. This message concludes with... a question on how this=20 > could > possibly be handled by the framework in the future, your opinion is > appreciated. > > Remember we have a model: A <<----> B, with B inheriting from A, and = we > have an two instances 'a' and 'b' in relation to each other: a <<---->=20= > b > > you fetch object 'a': > >>>> a=3Dec.fetch(..., isDeep=3D1)[0] >>>> b=3Da.getB() > > Now, if we suppose that the fetch only fetched 'a' and *not* 'b' as=20 > well > (which is possible since the fetch has isDeep=3D1), assuming = furthermore > that b has not been fetched before within 'ec', we have: > >>>> b.isFault() > 1 >>>> b, b.__class__ > (<A.A instance at 0x820b24c>, <class A.A at 0x81d7f6c>) >>>> b.getAs > [...] > AttributeError: A instance has no attribute 'getAs' > > --> b is a faulted object, and indeed, its class is A; like any fault, > its class is the root entity's class. That is basically why you = get > an AttributeError when trying to send to this object a 'getAs()' > message, to which only class B's instances can answer. In this particular model, it is categoric that an A is related to a B=20 (or, I guess, a sub-class of B, but not a super-class of B!). So, I still do not see why an A is returned, as this does not conform to the model -- thus I see this as incorrect behaviour. > Now if you clear the fault (b.willRead()), then b.getAs() works as > expected. Fine. At the moment, the (default) code that gets executed when a.getB() is called is something like: def getB(self): "Return the b relationship (toOne)" self.willRead() return self._b But, what's wrong with doing something like (only when an entity participates in an inheritance hierarchy) ? def getB(self): "Return the b relationship (toOne)" self.willRead() b =3D self._b b.willRead() return b This method is not called all the time b needs to be accessed (as in the examples you cite below, right?), so the performance hit (associated with the _getattr_ suggestion) is minimal. Or am I being too naive here? > I understand this can be surprising. The fact is that the model here > is very simple, and that you expect to get a B instance, not an A. = To > understand why a fault is *always* an instance of the root entity=20 > when > created, just imagine there is a third entity in the model such as: > > C <<-----> A <<----> B > > and an object 'c' such as: c <---> b <----> a > > If you fetch c first, then getA() returns 'b', a fault for an 'A', > then you fetch 'a', and you expect to get the _same_ object 'b' when > you ask for a.getB() --this is uniquing: the same row can only be > represented by one, and only one, object in the editing context. > As you can see here, even by examining the model there is no way to > deduce from it that 'b' will be a 'B' when we ask for c.getA() --and > I'm sure we do not want the fault's class to be checked and=20 > eventually > changed when a is asked for getB(), or we'll experiment a real slow > down in the process of uniquing & fetching objects. Other than the a.getB() explicit calls in client code, when is this method called within the framework? > I hope I succeeded in making it clear /why/ faults are created w/ the > rott entity's class. Now it can be also surprising that the fault is=20= > not > automatically cleared when it gets the 'getAs()' message. In fact, = this > is not a bug in itself, the fault is just not programmed to act like > this. > > There would be a way to do this: define __getattr__() so that it=20 > calls > willRead() on the object when it gets called. But this is not > something I want to add to the default behaviour, I do not think = this > is a good thing to do, just because __getattr__ gets called in a lot > of situations where you do want a fault to be actually triggered. = For > example, asking 'dir(b)' makes __getattr__ be asked for = '__members__' > and '__methods__', printing 'b' (in log e.g, or wherever) makes > __getattr__ be asked for '__str__', then for '__repr__' (when none = of > them exists and before falling back to the default --clasic-style > classes only), etc. > > --> I'm pretty sure that, if this is made the default, almost everyone > will complain sooner or later about faults being triggered for > choose-any-reason-here... > > That's the reason why this is not the default, and why the choice=20= > is > left to each developer there. > > Now, of course, __getattr__ could be designed so that it only calls > willRead() if any of the class' subclasses methods are searched... > Should we go that way? Or does anyone see an other possible = approach? > Or maybe is it enough to explicitely add this to the documentation? Again, it seems that few fall into this surprise, so attempting a=20 possibly bug-prone complex solution may not be worth the effort. I would be happy just to be aware of what is happening, so I know how to deal with the situation. If there is a simple way to unfault objects when needed, then so much the better. Cheers, mario > -- S=E9bastien. |
From: Sebastien B. <sbi...@us...> - 2003-11-16 18:28:47
|
Hi, I'd like to offer various useful dist. packages for the framework; that's why I've added the win32.exe installer. Now, studying new possibilities: 1. I've put the result of py-distutils 'bdist_rpm' at: http://modeling.sf.net/download/ModelingCore-0.9pre16-1.noarch.rpm http://modeling.sf.net/download/ModelingCore-0.9pre16-1.src.rpm=20=20=20= =20=20=20 If someone can confirm that one of these two or both are useful and working, I'll add them to the files distributed when a release is made. 2. I tried to use the debian/ directory that Guenther Starnberger offered at the beginning of september, but w/ no success. If someone has experiences on building .deb before I check the documentation for=20 'debian common build system' that would help a lot. As far as .deb and .rpm package are concerned, I'll probably not spend a lot of time on them unless this appears to be useful and I get feedback; I'm also looking for someone to maintain them and their configuration files, so if you feel like it, drop me a mail! -- S=E9bastien. |
From: Sebastien B. <sbi...@us...> - 2003-11-16 17:54:53
|
Hi all, I'm pleased to announce that release 0.9pre16 is finally out. It only contains fixes for bugs that have been detected on 0.9pre15 --as usual, you'll find the complete changelog below. The ZModeling is also repackaged but w/ no change of the shipped Zope products, it's just that I removed from the tarball the products that are out of sync and that are for debugging purposes only. Hence there is no need to re-download it if you already installed 0.9pre15 ZModelizationTool & ZEditingContextSessioning products. For the 1st time, I also included for the core a win32.exe installer, since I got positive feedbacks from Vladimir Drobnjak (thank you!) for 0.9pre15 that the executable created by python-distutils is fully functional (an installer.exe has also been added for the NotificationFramework v0.6). -- S=E9bastien. ------------------------------------------------------------------------ 0.9-pre-16 (2003/11/16) ----------------------- * Fixed bug #839231: python code generated in -B/--base mode made it impossible to import a class having sub-classes at first (it was raising because of circular imports). * Fixed bug #842698: when a PyModel.Attribute property is set after instanciation, its value was never propagated to the final Attribute at build() time. * Fixed bug #841315: PyModel associations do not set the multiplicity bou= nds e.g. a toOne relationship was always [0,1] regardless of what the definition of the Association. * RFE #812708: mdl_generate_db_schema.py now automatically adds a semi-co= lon (';') when option '-c' is enabled. A new option (-e/--end-with) is added to control this behaviour. In particular, the old behaviour (no semi-co= lon at end of statements) can be still obtained by supplying an empty string to option -e/--end-with (-e "" or --end-with ""). * Fixed bug #812671: utils.finalize_docstrings() disabled * Fixed bug #814007: KeyValueCoding.storedValueForKey() unexpectedly returned obj.key instead of obj._key when both exist. * Fixed bug #785434: When mdl_generate_db_schema is run with an option wh= ich doesn't require the admin-dsn to be set, the script fails with a KeyErr= or. ------------------------------------------------------------------------ |
From: Sebastien B. <sbi...@us...> - 2003-11-15 19:40:01
|
Hi all, Back on the subject, now that the problem is identified. I think this can be interesting to anyone willing to understand faults and the way they are handled by the framework, so I'll try there to be as explicit as possible. This message concludes with... a question on how this could possibly be handled by the framework in the future, your opinion is appreciated. Remember we have a model: A <<----> B, with B inheriting from A, and we have an two instances 'a' and 'b' in relation to each other: a <<----> b you fetch object 'a': >>> a=3Dec.fetch(..., isDeep=3D1)[0] >>> b=3Da.getB() Now, if we suppose that the fetch only fetched 'a' and *not* 'b' as well (which is possible since the fetch has isDeep=3D1), assuming furthermore that b has not been fetched before within 'ec', we have: >>> b.isFault() 1 >>> b, b.__class__ (<A.A instance at 0x820b24c>, <class A.A at 0x81d7f6c>) >>> b.getAs [...] AttributeError: A instance has no attribute 'getAs' --> b is a faulted object, and indeed, its class is A; like any fault, its class is the root entity's class. That is basically why you get an AttributeError when trying to send to this object a 'getAs()' message, to which only class B's instances can answer. Now if you clear the fault (b.willRead()), then b.getAs() works as expected. I understand this can be surprising. The fact is that the model here is very simple, and that you expect to get a B instance, not an A. To understand why a fault is *always* an instance of the root entity when created, just imagine there is a third entity in the model such as: C <<-----> A <<----> B=20 and an object 'c' such as: c <---> b <----> a If you fetch c first, then getA() returns 'b', a fault for an 'A', then you fetch 'a', and you expect to get the _same_ object 'b' when you ask for a.getB() --this is uniquing: the same row can only be represented by one, and only one, object in the editing context. As you can see here, even by examining the model there is no way to deduce from it that 'b' will be a 'B' when we ask for c.getA() --and I'm sure we do not want the fault's class to be checked and eventually changed when a is asked for getB(), or we'll experiment a real slow down in the process of uniquing & fetching objects. I hope I succeeded in making it clear /why/ faults are created w/ the rott entity's class. Now it can be also surprising that the fault is not automatically cleared when it gets the 'getAs()' message. In fact, this is not a bug in itself, the fault is just not programmed to act like this. There would be a way to do this: define __getattr__() so that it calls willRead() on the object when it gets called. But this is not something I want to add to the default behaviour, I do not think this is a good thing to do, just because __getattr__ gets called in a lot of situations where you do want a fault to be actually triggered. For example, asking 'dir(b)' makes __getattr__ be asked for '__members__' and '__methods__', printing 'b' (in log e.g, or wherever) makes __getattr__ be asked for '__str__', then for '__repr__' (when none of them exists and before falling back to the default --clasic-style classes only), etc. --> I'm pretty sure that, if this is made the default, almost everyone will complain sooner or later about faults being triggered for choose-any-reason-here... That's the reason why this is not the default, and why the choice is left to each developer there. Now, of course, __getattr__ could be designed so that it only calls willRead() if any of the class' subclasses methods are searched... Should we go that way? Or does anyone see an other possible approach? Or maybe is it enough to explicitely add this to the documentation? -- S=E9bastien. |
From: Sebastien B. <sbi...@us...> - 2003-11-15 13:17:21
|
Mario Ruggier <ma...@ru...> wrote: > I have installed this 2-in-1 patch, and confirm that the first > test (% python ./run.py) succeeds, and that the warnings > are not generated when I regenerate all from my model. Fine, thanks for reporting, it's now integrated into CVS, and will be in the next release. Please note that the fix that has been checked-in in slightly different with the previously posted one, you'll find it at https://sourceforge.net/tracker/index.php?func=3Ddetail&aid=3D841315&grou= p_id=3D58935&atid=3D489335 It fixes both bugs #841315 and #842698. -- S=E9bastien. |
From: Mario R. <ma...@ru...> - 2003-11-14 08:24:43
|
Hi, I have installed this 2-in-1 patch, and confirm that the first test (% python ./run.py) succeeds, and that the warnings are not generated when I regenerate all from my model. Thanks! mario >> thanks... Created bug 841315 for this: >> "Model associations do not set the multiplicity bounds" >> >> I have installed the patch, but there are some problems. >> >> First, the first installation test fails: >> % python ./run.py >> = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> FAIL: [PyModel] unqualified_relationships_with_inverse >> = ---------------------------------------------------------------------- >> Traceback (most recent call last): >> File "test_PyModel.py", line 393, in >> test_08_qualified_relationships_with_inverse >> self.check_model(model) >> File "test_PyModel.py", line 92, in check_model >> =20 >> self.failIf(fkStore.isRequired()!=3DtoStore.multiplicityLowerBound()) >> File >> "/BinaryCache/python/python-3.root~193/usr/lib/python2.2/=20 >> unittest.py", line >> 258, in failIf >> if expr: raise self.failureException, msg >> AssertionError > [...] > > Okay, thanks for reporting. In fact the test is right --it checks that > the PyModel does what is expected, i.e. that the FK, when = automatically > created, is mandatory/required when the multiplicity's lower bound is > 1. Since this correlation was not coded but the multiplicity is now > correctly forwarded, the test now fails ;) I've attached to bug ticket > #841315 the corresponding patch (it is an extension of the one I = posted > earlier today). That's a 2-in-1 bugfix, cool. > >> Then, for my model, on validation I get a warning for each >> such relationship, e.g: >> >> Object: Relationship A.b >> ------------------------------- >> * Warning(s): >> - relationship is mandatory but source attribute A.fkBId is not = =20 >> required > > Yes, this warning is "normal" in the bug context, it is due to the = fact > that the FK is not marked as mandatory as it should (in particular, =20= > this > makes mdl_generate_DB_schema.py mark the FK as a NOT NULL column). It > will disappear w/ the new patch applied. > > Please note: this is not integrated into cvs yet, I still need to = add > test for the other discovered bug --but this will be in the next > release for sure. > > Thanks for the report, > > -- S=E9bastien. |