Thread: [Pyobjc-dev] Possible bug in PyObjC bridge (SyncService)
Brought to you by:
ronaldoussoren
From: Mani G. <ma...@tu...> - 2010-04-29 15:21:53
|
Hello, Users of my app have been complaining of the following error: ValueError: NSInvalidArgumentException - *** -encodeInt:forKey: only defined for abstract class. Define -[NSArchiver encodeInt:forKey:]! It occurs in the following line of code: session.prepareToPullChangesForEntityNames_beforeDate_(entityNames, NSDate.distantFuture()) Where "session" is an ISyncSession object (http://developer.apple.com/mac/library/documentation/cocoa/Reference/SyncServicesFramework/Classes/ISyncSession_Class/Reference/Reference.html#//apple_ref/occ/cl/ISyncSession), and "entityNames" is a Python list of strings. Most of the time, for most users, this problem does not happen. But it seems like, for some people a different code path is being executed under the hood of SyncServices and this is happening. Not much to start with, but I am here to provide any more information as needed. This is a very serious issue for our user base and hopefully someone will be able to shed light on the issue, if it is indeed a PyObjC bridge matter. Thanks very much! Mani |
From: Aahz <aa...@py...> - 2010-04-29 15:46:04
|
On Thu, Apr 29, 2010, Mani Ghasemlou wrote: > > Users of my app have been complaining of the following error: > > ValueError: NSInvalidArgumentException - *** -encodeInt:forKey: only > defined for abstract class. Define -[NSArchiver encodeInt:forKey:]! > > It occurs in the following line of code: > > session.prepareToPullChangesForEntityNames_beforeDate_(entityNames, > NSDate.distantFuture()) > > Where "session" is an ISyncSession object > (http://developer.apple.com/mac/library/documentation/cocoa/Reference/SyncServicesFramework/Classes/ISyncSession_Class/Reference/Reference.html#//apple_ref/occ/cl/ISyncSession), > and "entityNames" is a Python list of strings. What versions of Python, PyObjC, and OSX are you using? What's the full traceback? What is the value of entityNames? How do you create session? -- Aahz (aa...@py...) <*> http://www.pythoncraft.com/ "It is easier to optimize correct code than to correct optimized code." --Bill Harlan |
From: Mani G. <ma...@tu...> - 2010-04-29 15:58:00
|
On Thu, Apr 29, 2010 at 11:45 AM, Aahz <aa...@py...> wrote: > On Thu, Apr 29, 2010, Mani Ghasemlou wrote: >> >> Users of my app have been complaining of the following error: >> >> ValueError: NSInvalidArgumentException - *** -encodeInt:forKey: only >> defined for abstract class. Define -[NSArchiver encodeInt:forKey:]! >> >> It occurs in the following line of code: >> >> session.prepareToPullChangesForEntityNames_beforeDate_(entityNames, >> NSDate.distantFuture()) >> >> Where "session" is an ISyncSession object >> (http://developer.apple.com/mac/library/documentation/cocoa/Reference/SyncServicesFramework/Classes/ISyncSession_Class/Reference/Reference.html#//apple_ref/occ/cl/ISyncSession), >> and "entityNames" is a Python list of strings. > > What versions of Python, PyObjC, and OSX are you using? What's the full > traceback? What is the value of entityNames? How do you create session? Hi Aahz! I'm building my app on a 10.5.8 system, with standard versions of Python and PyObjC (2.5, and 2.0 respectively). I have not determined if the errors occur on specific versions of OSX, but we QA the application on both Leopard and Snow Leopard and internally we cannot reproduce the problem (yet). The error posted is the full traceback. There is nothing else. The value of entityNames is *always* the following: entityNames = ['com.apple.contacts.Contact', 'com.apple.contacts.Email Address', 'com.apple.calendars.Calendar', 'com.apple.calendars.Event', 'com.apple.calendars.Recurrence', 'com.apple.calendars.Attendee'] The session is created using "ISyncSession.beginSessionWithClient_entityNames_beforeDate_". The prepareToPullChanges... code would not be invoked if creating the session returns a nil/None session object, or if it raises any exception. Thanks! Mani |
From: Ronald O. <ron...@ma...> - 2010-04-30 05:40:31
Attachments:
smime.p7s
|
On 29 Apr, 2010, at 17:57, Mani Ghasemlou wrote: > On Thu, Apr 29, 2010 at 11:45 AM, Aahz <aa...@py...> wrote: >> On Thu, Apr 29, 2010, Mani Ghasemlou wrote: >>> >>> Users of my app have been complaining of the following error: >>> >>> ValueError: NSInvalidArgumentException - *** -encodeInt:forKey: only >>> defined for abstract class. Define -[NSArchiver encodeInt:forKey:]! >>> >>> It occurs in the following line of code: >>> >>> session.prepareToPullChangesForEntityNames_beforeDate_(entityNames, >>> NSDate.distantFuture()) >>> >>> Where "session" is an ISyncSession object >>> (http://developer.apple.com/mac/library/documentation/cocoa/Reference/SyncServicesFramework/Classes/ISyncSession_Class/Reference/Reference.html#//apple_ref/occ/cl/ISyncSession), >>> and "entityNames" is a Python list of strings. >> >> What versions of Python, PyObjC, and OSX are you using? What's the full >> traceback? What is the value of entityNames? How do you create session? > > Hi Aahz! > > I'm building my app on a 10.5.8 system, with standard versions of > Python and PyObjC (2.5, and 2.0 respectively). I have not determined > if the errors occur on specific versions of OSX, but we QA the > application on both Leopard and Snow Leopard and internally we cannot > reproduce the problem (yet). > > The error posted is the full traceback. There is nothing else. > > The value of entityNames is *always* the following: > > entityNames = ['com.apple.contacts.Contact', > 'com.apple.contacts.Email Address', > 'com.apple.calendars.Calendar', > 'com.apple.calendars.Event', > 'com.apple.calendars.Recurrence', > 'com.apple.calendars.Attendee'] > > The session is created using > "ISyncSession.beginSessionWithClient_entityNames_beforeDate_". The > prepareToPullChanges... code would not be invoked if creating the > session returns a nil/None session object, or if it raises any > exception. I haven't used SyncServices for anything serious yet, which means I could be completely wrong with my assumptions. IIUC prepareToPullChanges... ends the phase where you push updates to SyncServices and starts the phase where SyncServices pushes changes to you. What kind of objects do you push to SyncServices? Are those pure Objective-C, instances of PyObjC subclasses or pure Python? The exception could occur when you push Python objects to SyncServices and SyncServices tries to serialize them using NSArchiver that doesn't support keyed coding, the code in Lib/objc/_pycoder.py assumes all archivers support keyed coding. Ronald |
From: Mani G. <ma...@tu...> - 2010-05-04 15:44:10
|
On Fri, Apr 30, 2010 at 1:40 AM, Ronald Oussoren <ron...@ma...> wrote: > > On 29 Apr, 2010, at 17:57, Mani Ghasemlou wrote: > >> On Thu, Apr 29, 2010 at 11:45 AM, Aahz <aa...@py...> wrote: >>> On Thu, Apr 29, 2010, Mani Ghasemlou wrote: >>>> >>>> Users of my app have been complaining of the following error: >>>> >>>> ValueError: NSInvalidArgumentException - *** -encodeInt:forKey: only >>>> defined for abstract class. Define -[NSArchiver encodeInt:forKey:]! >>>> >>>> It occurs in the following line of code: >>>> >>>> session.prepareToPullChangesForEntityNames_beforeDate_(entityNames, >>>> NSDate.distantFuture()) >>>> >>>> Where "session" is an ISyncSession object >>>> (http://developer.apple.com/mac/library/documentation/cocoa/Reference/SyncServicesFramework/Classes/ISyncSession_Class/Reference/Reference.html#//apple_ref/occ/cl/ISyncSession), >>>> and "entityNames" is a Python list of strings. >>> >>> What versions of Python, PyObjC, and OSX are you using? What's the full >>> traceback? What is the value of entityNames? How do you create session? >> >> Hi Aahz! >> >> I'm building my app on a 10.5.8 system, with standard versions of >> Python and PyObjC (2.5, and 2.0 respectively). I have not determined >> if the errors occur on specific versions of OSX, but we QA the >> application on both Leopard and Snow Leopard and internally we cannot >> reproduce the problem (yet). >> >> The error posted is the full traceback. There is nothing else. >> >> The value of entityNames is *always* the following: >> >> entityNames = ['com.apple.contacts.Contact', >> 'com.apple.contacts.Email Address', >> 'com.apple.calendars.Calendar', >> 'com.apple.calendars.Event', >> 'com.apple.calendars.Recurrence', >> 'com.apple.calendars.Attendee'] >> >> The session is created using >> "ISyncSession.beginSessionWithClient_entityNames_beforeDate_". The >> prepareToPullChanges... code would not be invoked if creating the >> session returns a nil/None session object, or if it raises any >> exception. > > I haven't used SyncServices for anything serious yet, which means I could be completely wrong with my assumptions. > > IIUC prepareToPullChanges... ends the phase where you push updates to SyncServices and starts the phase where SyncServices pushes changes to you. What kind of objects do you push to SyncServices? Are those pure Objective-C, instances of PyObjC subclasses or pure Python? > > The exception could occur when you push Python objects to SyncServices and SyncServices tries to serialize them using NSArchiver that doesn't support keyed coding, the code in Lib/objc/_pycoder.py assumes all archivers support keyed coding. > > Ronald Hello Ronald, The data pushed is a Python list of Python dicts. The dicts' keys are always strings, and the values are a mix of: - Python strings - Python ints - Python lists of Python strings & lists of Python ints - None objects - NSDatetime objects, created using NSCalendarDate.dateWithTimeIntervalSince1970_(python_int) - Python lists of NSDatetime objects (created same way as above) Your suggestion that the error could be caused by one or more of the records I am pushing helps me. I will try running tests with Calendar events (the main type of data I am syncing) that make use of all the above types and see if any of them trigger the error. I will be posting again with my findings sometime this week, but please let me know if there is something specific from the above that I should test for. Thanks! Mani |
From: Ronald O. <ron...@ma...> - 2010-05-04 16:05:20
Attachments:
smime.p7s
|
On 4 May, 2010, at 17:44, Mani Ghasemlou wrote: > On Fri, Apr 30, 2010 at 1:40 AM, Ronald Oussoren <ron...@ma...> wrote: >> >> On 29 Apr, 2010, at 17:57, Mani Ghasemlou wrote: >> >>> On Thu, Apr 29, 2010 at 11:45 AM, Aahz <aa...@py...> wrote: >>>> On Thu, Apr 29, 2010, Mani Ghasemlou wrote: >>>>> >>>>> Users of my app have been complaining of the following error: >>>>> >>>>> ValueError: NSInvalidArgumentException - *** -encodeInt:forKey: only >>>>> defined for abstract class. Define -[NSArchiver encodeInt:forKey:]! >>>>> >>>>> It occurs in the following line of code: >>>>> >>>>> session.prepareToPullChangesForEntityNames_beforeDate_(entityNames, >>>>> NSDate.distantFuture()) >>>>> >>>>> Where "session" is an ISyncSession object >>>>> (http://developer.apple.com/mac/library/documentation/cocoa/Reference/SyncServicesFramework/Classes/ISyncSession_Class/Reference/Reference.html#//apple_ref/occ/cl/ISyncSession), >>>>> and "entityNames" is a Python list of strings. >>>> >>>> What versions of Python, PyObjC, and OSX are you using? What's the full >>>> traceback? What is the value of entityNames? How do you create session? >>> >>> Hi Aahz! >>> >>> I'm building my app on a 10.5.8 system, with standard versions of >>> Python and PyObjC (2.5, and 2.0 respectively). I have not determined >>> if the errors occur on specific versions of OSX, but we QA the >>> application on both Leopard and Snow Leopard and internally we cannot >>> reproduce the problem (yet). >>> >>> The error posted is the full traceback. There is nothing else. >>> >>> The value of entityNames is *always* the following: >>> >>> entityNames = ['com.apple.contacts.Contact', >>> 'com.apple.contacts.Email Address', >>> 'com.apple.calendars.Calendar', >>> 'com.apple.calendars.Event', >>> 'com.apple.calendars.Recurrence', >>> 'com.apple.calendars.Attendee'] >>> >>> The session is created using >>> "ISyncSession.beginSessionWithClient_entityNames_beforeDate_". The >>> prepareToPullChanges... code would not be invoked if creating the >>> session returns a nil/None session object, or if it raises any >>> exception. >> >> I haven't used SyncServices for anything serious yet, which means I could be completely wrong with my assumptions. >> >> IIUC prepareToPullChanges... ends the phase where you push updates to SyncServices and starts the phase where SyncServices pushes changes to you. What kind of objects do you push to SyncServices? Are those pure Objective-C, instances of PyObjC subclasses or pure Python? >> >> The exception could occur when you push Python objects to SyncServices and SyncServices tries to serialize them using NSArchiver that doesn't support keyed coding, the code in Lib/objc/_pycoder.py assumes all archivers support keyed coding. >> >> Ronald > > Hello Ronald, > > The data pushed is a Python list of Python dicts. The dicts' keys are > always strings, and the values are a mix of: > > - Python strings > - Python ints > - Python lists of Python strings & lists of Python ints > - None objects > - NSDatetime objects, created using > NSCalendarDate.dateWithTimeIntervalSince1970_(python_int) > - Python lists of NSDatetime objects (created same way as above) > > Your suggestion that the error could be caused by one or more of the > records I am pushing helps me. I will try running tests with Calendar > events (the main type of data I am syncing) that make use of all the > above types and see if any of them trigger the error. > > I will be posting again with my findings sometime this week, but > please let me know if there is something specific from the above that > I should test for. You could try a sync action with 'objc.setVerbose(1)', that will print exception traces when translating exceptions to ObjC and tends to be helpful when an exception is raised in Python code and then transitions through an ObjC layer. If this traceback contains references to objc._pycoder my hypothesis is correct, and that means that that module should be enhanced to support both keyed coding and classic non-keyed coding. BTW. All values you mention except 'None' should encode just fine using a "classic" coder, replacing 'None' by NSNull.null() before encoding might be the quickest solution to your problem. It looks like this is relatively easy to enhance the unittests of _pycoder to test with classic coders, my first result is a collection of failed tests: ====================================================================== ERROR: test_structseq (__main__.TestArchivePlainPython) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/test/pickletester.py", line 583, in test_structseq s = self.dumps(t, proto) File "test_archive_python.py", line 436, in dumps return NSArchiver.archivedDataWithRootObject_(arg) ValueError: NSInvalidArgumentException - *** -encodeInt:forKey: only defined for abstract class. Define -[NSArchiver encodeInt:forKey:]! Fixing the tests is more work, but should be relatively straightforward. Ronald > > Thanks! > Mani |
From: Ronald O. <ron...@ma...> - 2010-05-04 19:14:33
Attachments:
smime.p7s
|
> > > It looks like this is relatively easy to enhance the unittests of _pycoder to test with classic coders, my first result is a collection of failed tests: > > ====================================================================== > ERROR: test_structseq (__main__.TestArchivePlainPython) > ---------------------------------------------------------------------- > Traceback (most recent call last): > File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/test/pickletester.py", line 583, in test_structseq > s = self.dumps(t, proto) > File "test_archive_python.py", line 436, in dumps > return NSArchiver.archivedDataWithRootObject_(arg) > ValueError: NSInvalidArgumentException - *** -encodeInt:forKey: only defined for abstract class. Define -[NSArchiver encodeInt:forKey:]! > > Fixing the tests is more work, but should be relatively straightforward. > > Ronald Sadly enough it wasn't possible to implement this without changes to C code. I've committed an initial patch for this in r2465, but that's a partial commit from my workspace and I'm not 100% sure that I added everything to the commit. Anyway, the trunk is not compatible enough with 2.2 to just rebuild pyobjc-core, you'd have to rebuild all of PyObjC and I'm not quite ready to do a release. Ronald |
From: Mani G. <ma...@tu...> - 2010-05-05 15:25:38
|
On Tue, May 4, 2010 at 3:14 PM, Ronald Oussoren <ron...@ma...> wrote: >> >> >> It looks like this is relatively easy to enhance the unittests of _pycoder to test with classic coders, my first result is a collection of failed tests: >> >> ====================================================================== >> ERROR: test_structseq (__main__.TestArchivePlainPython) >> ---------------------------------------------------------------------- >> Traceback (most recent call last): >> File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/test/pickletester.py", line 583, in test_structseq >> s = self.dumps(t, proto) >> File "test_archive_python.py", line 436, in dumps >> return NSArchiver.archivedDataWithRootObject_(arg) >> ValueError: NSInvalidArgumentException - *** -encodeInt:forKey: only defined for abstract class. Define -[NSArchiver encodeInt:forKey:]! >> >> Fixing the tests is more work, but should be relatively straightforward. >> >> Ronald > > Sadly enough it wasn't possible to implement this without changes to C code. I've committed an initial patch for this in r2465, but that's a partial commit from my workspace and I'm not 100% sure that I added everything to the commit. > > Anyway, the trunk is not compatible enough with 2.2 to just rebuild pyobjc-core, you'd have to rebuild all of PyObjC and I'm not quite ready to do a release. > > Ronald > > Hello Ronald, I will go ahead with your suggested workaround to use NSNull.null() instead of None, and will let you know if it solves the bug for our users. Thanks very much for your hard work! PyObjC is a great project and we really appreciate your supporting it. Regards, Mani |
From: Scott H. <sco...@gm...> - 2010-05-13 19:35:53
|
I'm running on 10.6.2 with no other Python than the Apple supplied version. After looking a the docs and mailing list I'm still a bit confused. If I do this: "easy_install pyobjc==2.2" I'll end up installing 2.2 over the 2.2b3 that comes with my system and that's bad, right? So should I install another version of Python and make sure that that python is in front of the system Python in my path so that I install PyObjC against that? Can I just stick with the supplied version of PyObjC and python? What's the downside there? What's the recommended setup for PyObjC development? Thanks, -Scott |
From: James R E. <Jam...@lr...> - 2010-05-14 08:36:05
|
Hi Scott, You should be able to stick with the system-supplied PyObjC for most cases. There have been some bugs fixed since that version, but for the most part, they are minor (although the definition of "minor" will depend on which libraries you need to use). For what it's worth, I'm still using a (mostly) stock 10.6.3 Python/PyObjC setup for all of my development. The only changes I've made are to fix a couple of bugs in py2app relating to 1) alias builds and 2) plugin builds (see below). (I believe that Ronald has already incorporated these fixes in SVN.) Cheers! James [1]: Jagaroth:/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/pyt hon/py2app $ diff -u build_app.py.orig build_app.py --- build_app.py.orig 2009-07-01 08:26:30.000000000 +0200 +++ build_app.py 2009-11-02 11:49:57.000000000 +0100 @@ -1090,7 +1090,12 @@ # symlink python executable execdst = os.path.join(appdir, 'Contents', 'MacOS', 'python') - self.symlink(sys.executable, execdst) + prefixPathExecutable = os.path.join(sys.prefix, 'bin', 'python') + if os.path.exists(prefixPathExecutable): + pyExecutable = prefixPathExecutable + else: + pyExecutable = sys.executable + self.symlink(pyExecutable, execdst) # make PYTHONHOME pyhome = os.path.join(resdir, 'lib', 'python' + sys.version[:3]) [2]: Jagaroth:/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/pyt hon/py2app/bootstrap $ diff -u boot_plugin.py.orig boot_plugin.py --- boot_plugin.py.orig 2006-07-11 22:31:34.000000000 +0200 +++ boot_plugin.py 2009-11-16 13:35:27.000000000 +0100 @@ -5,6 +5,7 @@ base = os.environ['RESOURCEPATH'] site.addsitedir(base) site.addsitedir(os.path.join(base, 'Python', 'site-packages')) + site.addsitedir(os.path.join(sys.prefix, 'Extras', 'lib', 'python')) for script in scripts: path = os.path.join(base, script) __file__ = path Le 13 mai 2010 à 21:35, Scott Harris a écrit : > I'm running on 10.6.2 with no other Python than the Apple supplied version. > > After looking a the docs and mailing list I'm still a bit confused. > > If I do this: "easy_install pyobjc==2.2" > I'll end up installing 2.2 over the 2.2b3 that comes with my system and that's bad, right? > > So should I install another version of Python and make sure that that python is in front of the system Python in my path so that I install PyObjC against that? > > Can I just stick with the supplied version of PyObjC and python? What's the downside there? > > What's the recommended setup for PyObjC development? > > Thanks, > -Scott > > > ------------------------------------------------------------------------------ > > _______________________________________________ > Pyobjc-dev mailing list > Pyo...@li... > https://lists.sourceforge.net/lists/listinfo/pyobjc-dev -- James R. Eagan LRI — Bâtiment 490 Université de Paris-Sud XI email: Jam...@lr... 91405 Orsay Cedex — France web: http://www.lri.fr/~eaganj |
From: Scott H. <sco...@gm...> - 2010-05-14 16:11:37
|
Thanks for the info. I installed the XCode templates and got a demo program up and running last night using the stock PyObjC. Trying out mixing ObjC and Python and calling each language from the other. It's falling into place. -Scott On May 14, 2010, at 2:35 AM, James R Eagan wrote: > Hi Scott, > > You should be able to stick with the system-supplied PyObjC for most cases. There have been some bugs fixed since that version, but for the most part, they are minor (although the definition of "minor" will depend on which libraries you need to use). > > For what it's worth, I'm still using a (mostly) stock 10.6.3 Python/PyObjC setup for all of my development. The only changes I've made are to fix a couple of bugs in py2app relating to 1) alias builds and 2) plugin builds (see below). (I believe that Ronald has already incorporated these fixes in SVN.) > > Cheers! > James > > > [1]: > Jagaroth:/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/pyt > hon/py2app $ diff -u build_app.py.orig build_app.py > --- build_app.py.orig 2009-07-01 08:26:30.000000000 +0200 > +++ build_app.py 2009-11-02 11:49:57.000000000 +0100 > @@ -1090,7 +1090,12 @@ > > # symlink python executable > execdst = os.path.join(appdir, 'Contents', 'MacOS', 'python') > - self.symlink(sys.executable, execdst) > + prefixPathExecutable = os.path.join(sys.prefix, 'bin', 'python') > + if os.path.exists(prefixPathExecutable): > + pyExecutable = prefixPathExecutable > + else: > + pyExecutable = sys.executable > + self.symlink(pyExecutable, execdst) > > # make PYTHONHOME > pyhome = os.path.join(resdir, 'lib', 'python' + sys.version[:3]) > > > [2]: > Jagaroth:/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/pyt > hon/py2app/bootstrap $ diff -u boot_plugin.py.orig boot_plugin.py > --- boot_plugin.py.orig 2006-07-11 22:31:34.000000000 +0200 > +++ boot_plugin.py 2009-11-16 13:35:27.000000000 +0100 > @@ -5,6 +5,7 @@ > base = os.environ['RESOURCEPATH'] > site.addsitedir(base) > site.addsitedir(os.path.join(base, 'Python', 'site-packages')) > + site.addsitedir(os.path.join(sys.prefix, 'Extras', 'lib', 'python')) > for script in scripts: > path = os.path.join(base, script) > __file__ = path > > > > > Le 13 mai 2010 à 21:35, Scott Harris a écrit : > >> I'm running on 10.6.2 with no other Python than the Apple supplied version. >> >> After looking a the docs and mailing list I'm still a bit confused. >> >> If I do this: "easy_install pyobjc==2.2" >> I'll end up installing 2.2 over the 2.2b3 that comes with my system and that's bad, right? >> >> So should I install another version of Python and make sure that that python is in front of the system Python in my path so that I install PyObjC against that? >> >> Can I just stick with the supplied version of PyObjC and python? What's the downside there? >> >> What's the recommended setup for PyObjC development? >> >> Thanks, >> -Scott >> >> >> ------------------------------------------------------------------------------ >> >> _______________________________________________ >> Pyobjc-dev mailing list >> Pyo...@li... >> https://lists.sourceforge.net/lists/listinfo/pyobjc-dev > > -- > James R. Eagan > LRI — Bâtiment 490 > Université de Paris-Sud XI email: Jam...@lr... > 91405 Orsay Cedex — France web: http://www.lri.fr/~eaganj > |