Main

November 15, 2008

touchengine -- iPhone Google App Engine communication

My friend Noah Gift, an awesome python programmer who wrote the very popular book Python for Unix and Linux System Administration and I are working on a new open source framework that aims to facilitate communication between the iPhone SDK and Google App engine. In the spirit of the open source mantra, "release early, release often," we've made it available here on Google Code and is MIT licensed. We're also working on a couple of apps that use the framework; we plan to eat our own dogfood so-to-speak.

Current features

  • Includes a slightly modified version of the python plist library to allow syndication of data from Google App Engine to the iPhone via xml plists.
  • Includes a generically useful caching plist downloader library for the iPhone SDK that keeps the user in sync with Google App Engine data and allows offline access to that data.

Example Code

  • isonnet, a Google App Engine application that syndicates Shakespeare's Sonnets in plist form for consumption by the iPhone app.
  • Sonnet, a viewer application for the iPhone, which we're going to release soon for free on the app store, that connects to our Google App Engine site to download, cache, and display Shakespeare's Sonnets.

Future Features / Informal Roadmap

  • Authentication with Google App Engine with the user's Google ID
  • Two-way communication and data sync between app engine and the iPhone SDK
  • Integration and automatic plist syndication of underlying Google App Engine Data Storage and objects
  • Support for Application skinning through plist syndication
  • Support for storage of the iPhone user's application preferences on Google App Engine.
Look for our article on IBM DeveloperWorks coming soon.

If you have any questions or comments for us, please feel free to contact me at jonathan ((at)) thisdomainyou'reonrightnow ((dot com)).

December 03, 2007

Poking around in others' software is sometimes useful (and thanks to Zorn)

I need an NSNumberFormatter subclass for a PyObjC project I'm working on that reformats an NSNumber to hours:minutes:seconds. Thinking I've seen this before (and kind of hoping that there was some voodoo I was missing somewhere to make this simple), I decided to poke around in applications that deal with time. After a little head-scratching, I was reminded of that most useful time-tracking and invoicing application I've grown to love called Billable (Zorn!). On this screenshot (from the Clickable Bliss site) we see a field labeled "Time Spent:" with a "Start" button next to it. Thinking to myself, "I want that formatter!" I fired up F-Script Anywhere, injected it into Billable and dug down until I was the class name for the formatter. CBTimeLengthFormatter.jpg Time to pray to google. Ah! Zorn! You beautiful helpful coding-type person. You've pasted it for us. Thank you! Now all that is left is to pythonify it. (I made a few modifications to the behavior, but it's the same general idea)
#
#  CBTimeLengthFormatter.py
#  PuppyTracker
#
#  Created by Jonathan Saggau on 12/3/07.
#  Copyright (c) 2007 __MyCompanyName__. All rights reserved.


from Foundation import *
from math import floor

#modified from http://paste.lisp.org/display/21854
class CBTimeLengthFormatter(NSNumberFormatter):

    def stringForObjectValue_(self, anObject):
        if (not (anObject.isKindOfClass_(NSNumber))):
            return(None)
            
        if (anObject.intValue() <= 0):
            return("00:00:00")
        intval = int(floor(anObject))
        
        hours = intval / (60*60)
        minutes = (intval - (hours * 60 * 60)) / 60
        seconds = intval - (minutes * 60) - (hours * 60 * 60)
        string = "%02i:%02i:%02i" %((hours), (minutes), (seconds))
        return(string)
    
    def getObjectValue_forString_errorDescription_(self, objVal, inString, err):
        """Take a string like "00:00:00" and turns it into a NSNumber and returns YES
           Also able to handle 10:10 (as 10 minutes, 10 seconds) and 10 (as 10 seconds)"""
        
        string = NSString.stringWithString_(inString)
        
        #catch for nil or empty string
        if (string == None or string.isEqualToString_("")):
            return True, 0, None
        
        stringList = string.split(":")
        #make seconds first, instead of hours
        stringList.reverse()
        
        #turn each into an integer, filtering out empty strings
        try:
            stringList = [int(each) for each in stringList if each is not u'']
            
        #if we can't make any part of this into an int, bail
        except ValueError, e:
            return False, 0, None
        
        #make sure we have Seconds, Hours, Minutes by padding the list with zeros
        #in case we have (say) Seconds, Hours only
        while ( len(stringList) < 3):
            stringList.append(0)
        
                        #sec            #min               #hour
        timeInSeconds = stringList[0] + stringList[1]*60 + stringList[2]*60*60
        return True, timeInSeconds, None

July 10, 2006

Python from objective-C

I've been working on getting python objects to instantiate in objective-C and have put together a little demo app as a learning tool for myself. It may not be the best way to python from objc, but it works. I hope it's helpful.

http://www.jonathansaggau.com/cocoa-dev/test.tgz

XCode should build the bundle for you when you hit Build and Go. You'll see a bunch of stuff in the log window that shows you that the python object is firing on all cylinders and that calling the super class that's written in objc works as expected, etc. You'll want to look in the NIB file to see how it's all connected.

How it works:
I subclassed an objc object (JSAbstractTest) in python (Test.py), using of the NIB file to indicate the class hierarchy. You don't necessarily *have* to subclass in this way, you could use a protocol like Bob suggests on the pythonmac-SIG. The protocol method is cleaner, for instance, when you don't really want to implement any of the functionality of the class in objc. This will allow you to do things you might want to do in the compiled language while offloading some functionality to our friendly "batteries included" python. (This is such fun).

Also useful (http://pyobjc.sourceforge.net/doc/intro.php) so we know what the bridge is expecting:

* Python numbers (int, float, long ) are translated into NSNumber instances. Their identity is not preserved across the bridge.
* Python str is proxied using OC_PythonString, a subclass of NSString. A Python str may be used anywhere a NSString is expected, but unicode should be used whenever possible. OC_PythonString will use the default encoding of NSString, which is normally MacRoman but could be something else.
* Python unicode is proxied using OC_PythonUnicode , a subclass of NSString. A Python unicode may be used anywhere a NSString is expected.
* Python dict is proxied using OC_PythonDictionary, a subclass of NSMutableDictionary. A Python dict may be used anywhere an NSDictionary is expected.
* Python list and tuple are proxied using OC_PythonArray, a subclass of NSMutableArray. Python list or tuple objects may be used anywhere an NSArray is expected.
* Python objects that implement the Python buffer API, except for str and unicode, are proxied using OC_PythonData, a NSData subclass. Objects that implement the Python buffer API such as buffer, array.array, mmap.mmap, etc. may be used anywhere a NSData is expected.

Armed with the above information, I coaxed a UDP networking toy written in python to send messages to SuperCollider based on the activity of an image stream coming from my iSight through a quartz composer project. WOO HOO!)

(I've also posted this to pythonmac-SIG, where I'm sure to get comments to refine this post. In the meantime, take this with a grain of salt.)

June 07, 2006

Bob

I don't know how he finds the time, but the python / mac community owes Bob several rounds of applause. Let me be the first to stand (soon as I get this here foot outta mah mouth). I'm also wowed at how he managed to find my blog and comment before I got round to sending a question to the mailing lists. And ... well you know... he kicked my butt and I deserved it.

June 06, 2006

PyObjC proxy fun

PyObjC is cool. Really. No Kidding. What I'm about to say, though, is making me think that my friend Patrick www.patrickkidd.com has a better idea in using pyQT for gui work...

When I'm using an external library, say perhaps one that sends information over a network, I try to be careful to keep from passing the lower-level code anything that could muck things up. Well... it turns out that it's nearly impossible to keep python's object types from being converted to pyobjc objects. This isn't too surprising, given that many ints, strings, etc. have to make their way into objc arguments, though I was making the improper assumption that python objects were converted through some kind of transparent proxy only when crossing that boundary to the objc runtime. I find out now that python objects are sometimes just converted. That being the case, I didn't expect those converted objects to act like anything but your typical python object from the point of view of python (ala duck typing... sorta). Again. WRONG. Somehow, for instance, the integer type sometimes turns into an OC_PythonInt (which has a method intValue() to get to the python int it represents, FYI) and it doesn't have the same methods as a python int. Bummer. It's kinda hard to send that over the network.

What to do?

"assert" statements, I guess.

May 18, 2006

I did, I did ate a Zombie

From Ronald Oussoren to me (+ pyobjcdev and pythonmac-sig):

I haven't look at your example just yet, will do that later on. I'm
happy you took the time to create a small program that demonstrates
the problem you're seeing, that makes is so much easier to search the
problem.

> What did I learn from this:
>
> 1. Try to use cocoa objects instead of python objects in code that
> uses bindings; pay special attention to collections (lists, etc.).
> At least this *seems* safer because a python object being
> referenced from cocoa is probably more likely to cause problems
> than a cocoa object controlled from python. (?) Then again, it's
> pretty stupid to generalize from one experience...

Using Cocoa datastructures instead of python ones when KVO is
involved is always a good idea. Python doesn't have enough hooks to
allow reliable interception __setitem__. We could (but don't)
get 95% of the way by using the same class-swiffling technique as
used by the ObjC runtime, but could never go all the way.

> 2. GDB is very useful for debugging pyobjc.
> 3. There are a lot of nice pyobjc debugging features, but you have
> to turn them on (See my example project referenced above).
>
> Things I want to know:
> 1. Is there a way, when one gets the memory address of a pyobjc
> proxy object (Like OC_PythonArray) from gdb to figure out which
> python object it's proxying?
The PyObject* is stored as the instance variable 'value' on the proxy
object.

> 2. Is there a way to get the python object from a memory address?

You mean like "(PyObject*)0xDEADBEEF"?

> 3. Is there a reliable way to get (in gdb or pdb) the "Python List
> Object at 0x03423blahblahblah information from the python object
> being proxied

> 4. Can I compile pyobjc with debugging symbols? GDB without them
> hurts my brain.

PyObjC is compiled with debugging symbols by default. Py2app strips
debugging symbols, unless you build with the -A flag.

Ronald

May 04, 2006

I think I just ate a Zombie

Well, I think I've figured out the *WTF* part of my little NSZombie problem.

It really boils down to this:

Bind an NSPopubButton (contents) to a Python List object that is an attribute of a python class placed in an NSArray controlled by an NSArrayController and the OC_PythonArray object from PyObjC corresponding to the Python List gets freed too early. (There's a mouthful... Confusing enough?) Wrap that Python List object in an NSArray.alloc().initWithArray_copyItems_([u'the', u'list'], objc.NO) and (I guess) the NSArray...init... adds one more -retain than does OC_PythonArray and the binding doesn't break.

I'm always nervous to call things like this a bug because maybe I'm not *supposed* to be able to do what I'm trying to do in the way that I'm trying to do it, but this one looks like a bug to me. (With the caveat that I am currently learning pyobjc/cocoa and don't always know the *right* way to do things...)

Continue reading "I think I just ate a Zombie" »

April 30, 2006

NSZombie update

I wonder if I'm using cocoa bindings incorrectly... or maybe there's a bug. Usually when I start to think "maybe there's a bug in somebody else's code," I look for ways in which I'm using that code in weird (wrong) ways. I figure that the pyobjc people are about 7 orders of magnitude better at this than I am.

Continue reading "NSZombie update" »

April 10, 2006

NSZombie eating my brain!

I've been learning cocoa bindings (I like this voodoo) and have hit a brick wall. I've been asking pythonmac-sig if they've any ideas and they pointed me in the direction of NSZombieEnabled, but i haven't been able to get very far.

I have an NSArray controller with a python object subclassing NSObject. I've put a + button on the gui to add the python object like this:::

def addTriggerModel_(self, sender): # BUTTON
self.setCanAddTriggerModel_(False)
newTriggerModel = scNSDrumTriggerModel.alloc().init()
newTriggerModel.resetWithNodeBusAndInput(node = self.nextNode, bus = self.nextBus, \
input = self.nextInput, sendInfo = self.sendingTriggersToClient)
self.nextNode += 100
self.nextBus += 10
self.nextInput += 1
NSLog("Adding newTriggerModel")
self.triggerArrayController.addObject_(newTriggerModel)
NSLog("Added newTriggerModel")
self.setCanAddTriggerModel_(True)


This works just peachy the first time I do it, but fails on a second addition of the new scNSDrumTriggerModel object. At first I was getting Signal 5/6 errors, then I did:

from PyObjCTools import Signals
Signals.dumpStackOnFatalSignal()
from PyObjCTools import Debugging
Debugging.installVerboseExceptionHandler()

This told me:

NSGenericException - *** Selector 'retain' sent to dealloced instance 0x1147cb0 of class OC_PythonArray

So I turned on NSZombieEnabled and tried running in gdb with a breakpoint on -[_NSZombie retain], but I don't really know what I'm looking for. I'm looking at a lot of hex memory addresses with very little human-readable stuff in there.

I tried setting a breakpoint at (+[OC_PythonArray newWithPythonObject:]) to see perhaps what proxy objects are being instantiated, but I'm clearly in over my depth. The variable corresponding to the pythonObject in OC_PythonArray newWithPythonObject: up there ^ has address 0x0 (Is that a null pointer?) in gdb each time I hit that breakpoint.

When I run malloc_history on the memory address that the NSZombie has, I get this:

Continue reading "NSZombie eating my brain!" »

February 26, 2006

xCode and pyObjc "build and run"

For those of us who live with pyobjc's xcode templates, there is an annoying little bug when creating a new project, at least on my machines. There are no executables created when you make a new python/cocoa project of any kind which causes xCode to disable "build and run" button. Sure, we can build in Xcode, navigate to the build directory, and run the application, but that's what the "build and run" button is for! How do we fix this? Add the project executable to the Executables group in xcode!

Like this:

In your xCode session, there is a pane down the left side that shows the contents of the project. In that pane, ctrl-click the "Executables" group, select "Add," then "New Custom Executable". Put the name of your application appended by .app in the "Executable Name field." (i.e. if your app is called "Trigger," put "Trigger.app" in this field). Use the "choose" button to navigate to your application's build directory on your hard disk and choose your application bundle. (If it doesn't exist, try building your application with the build button once first.) Now in the "Project" menu of xCode, "Set Active Executable" to your application name. This should enable the "build and run" button.

UPDATE: Once you've done that ^, you can then change the path to the executable to $BUILT_PRODUCTS_DIR/YourApplicationNameHere.app so that your project doesn't have any hard-coded paths.

February 23, 2006

Cocoa Bindings 1: the resolution

OK. It's a little late for a resolution for the New Year.

I am finally going to learn cocoa bindings. I have the right app for it. I've a couple of books with info. I've got tutorials all over my dev documentation folder.

Come along. I'll chronicle the ride here.

It's going to happen. I can feel it. This time, PyObjC. Next time, objc

jonathansaggau.com/trigger.jpg

January 18, 2006

python performance suck

Stupid nerd trick:  (File under... DUH!)

When working on real-time audio control, it's probably not a bad idea to try to get the best possible time-slicing quantum possible.  What with latency to think about and generally wanting everything to just-happen-right-the-heck-now(TM)...

Continue reading "python performance suck" »