Archive for the 'PyObjC' Category

Calling Python from Objective-C

Saturday, November 21st, 2009

Every six months or so, I run across a question along the lines of how do I invoke some Python code from Objective-C?

Kinda like here for which I posted the same conceptually concrete but technically vague pattern that I have posted for the last decade+.

Which led to this question.

OK — enough is enough. Here is a working example. Read the rest of this entry »

PyObjC Xcode Templates now in Subversion

Monday, December 3rd, 2007

Ronald and I realized that the Xcode templates that are included in Leopard didn’t make it into the PyObjC repository.

So, I moved ‘em over.

You can find them in the PyObjC subversion repository.

These aren’t just templates, though. See the README.txt.

As it implies, the project-tool.py script is used to effectively convert between Xcode templates and buildable projects. That is, you can create a project that builds/runs like a regular Xcode project, and then easily turn it into a template with the invocation of a simple command line like this:

project-tool.py -k -v --template Cocoa-Python\ Document-based\ Application/CocoaDocApp.xcodeproj/TemplateInfo.plist \
    Cocoa-Python\ Document-based\ Application/ \
    ~/Library/Application\ Support/Developer/Shared/Xcode/Project\ Templates/AA\ Testing/Cocoa-Python\ Document-based\ Application

Or, specifically:

./project-tool --help
Usage: project-tool.py [options]  

    Copies tree of templates or projects from  to .
    Before copying, it cleans up  by removing various bits of garbage.
    After copying, it transforms  by replacing strings with their Xcode
    template counterparts.

    The reverse flag can be used to reverse this process; turning an Xcode
    template into a working project.

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -v, --verbose         verbose
  -k, --kill-dest       erase  (no warning)
  -r, --reverse         reverse transformation (template -> editable project)
  -w, --working         try to make destination into a working project
  -n, --nib             rewrite NIB files to 10.5 text-only format
  -t TEMPLATEFILE, --template=TEMPLATEFILE
                        path to TemplateInfo.plist that should be used during
                        conversion

Nothing remotely Python specific about it. And, as some have noticed, the PyObjC Cocoa templates leverage the new Interface Builder file format (xib) such that all kinds of substitutions happen in the templated interfaces, too. As in: No more MyDocument ever again.

Can Ruby, Python and Objective-C Co-exist in a Single Application?

Sunday, November 25th, 2007

In short, Yes. But not without some pain.

You can grab an example of the Python and Ruby bridges working together in a Cocoa application from either this downloadable zip or from this Subversion repository (in case something actually changes).

It works. Sort of. Ironically, this likely would have worked better under the pre-BridgeSupport versions of RubyCocoa and PyObjC.

Specifically, RubyCocoa and PyObjC both assume that nothing else might have loaded the dynamic libraries that are automatically generated by the gen_bridge_metadata script. So, either bridge will quite happily attempt to load /System/Library/Frameworks/Foundation.framework/Resources/BridgeSupport/Foundation.dylib and then barf mightily when the other bridge has already loaded the same dylib.

The example is rife with silliness related to catching the resulting exceptions and ignoring them. Worse, the fallout is such that from Foundation import * doesn’t actually cause the Objective-C classes to be defined within the importing module.

There is a back door — objc.lookUpClass() — but this is yet further evidence that, at this time, mixing these two languages in a single Cocoa application is not anything more than a silly hacque (as the SVN repository subdir indicates).

What does it do?

Not much, really.

  • Start with RubyCocoa Application Template (because I can deal with brokeness in Python, I wanted to start with something working in Ruby)
  • NSApp Delegate written in Obj-C
  • Finish loading hooks used to bootstrap PyObjC/Python (with gross exception ignoring goofiness related to the dylib)
  • Bind a table view to an array of dicts where each dict has the key “name” leading to a string value bound through array controller.
  • Array controller bound through app delegate method.
  • App delegate returns array of dictionaries by calling python based NSObject subclass.
  • Python based NSObject subclass composes an array of dictionaries (all python) from a combinatio of Python strings and Ruby strings by calling an instance of a Ruby based subclass of NSObject.

Very little code. Lots of moving parts. Some gears grinding. Maybe even a gear tooth or four missing. Enjoy.

PyObjC 2.0 Source Available

Thursday, November 1st, 2007

Ronald comitted the source for PyObjC 2.0 into the public repository.

It can be found at PyObjC 2.0 trunk (http://svn.red-bean.com/pyobjc/branches/pyobjc2).

The NEWS.txt file is extremely illuminating as there were tons and tons of changes and bug fixes in 2.0.

It cannot be emphasized enough; this is a huge release for PyObjC. As big as when PyObjC first gained subclassing (which wasn’t until about 7 years into its 14 year history). Go read the NEWS file; both major enties on PyObjC 2.0.

Note that libffi on Leopard is fully 64 bit and, thus, PyObjC should be mostly ready for 64 bit, though it was neither built for, nor tested with, 64 bit.

PyObjC 2.0 (PyObjC in Leopard)

Saturday, October 27th, 2007

Leopard includes PyObjC 2.0, a huge upgrade over the 1.x series that will be hitting the public repository in the very near future (Ronald’s time permitting).

Both Ronald (who did all the work) and I (sort of) had posted previews of PyObjC 2.0. Now the full magnitude of this release can be publicly discussed.

In particular, Ronald’s post gives an excellent overview of the new features and capabilities of PyObjC.

There is a theme: “greatly tighten the integration with Mac OS X in a more consistent and less special-cased fashion”.

Read on for details:
Read the rest of this entry »

Preview of PyObjC 2.0

Friday, July 20th, 2007

While it appears that PyObjC development has stagnated, nothing could be further from the truth.

Ronald posted a very nice overview of the tasty goodness in PyObjC 2.0. He has been very very busy.

Yes, it fully leverages the metadata generated by the BridgeSupport project. Via BridgeSupport, PyObjC — and RubyCocoa, and anything else leveraging BridgeSupport — has enough metadata to bridge to just about any C or Objective-C API. The goal of BridgeSupport is to provide a machine readable description of system APIs with full fidelity; something that the Objective-C runtime metadata does not provide (including, for example, information about straight C functions).

Ronald: Thank you. 12 years is a long time for any open source project to remain active and the last year, largely through Ronald’s contributions, has proven to be one of the most vibrant years of development in the project’s history!

AAPL > DELL

Tuesday, May 2nd, 2006

Apple has surpassed Dell in the market cap department. This happened earlier in the year and then Apple’s stock got nailed.

Hopefully, that won’t be the pattern this time around.

Ronald Oussoren — of PyObjC and Universal Python fame (amongst other things) — is in town and will be joining us for Korean food and Bowling this evening. Korean food starts at 7:30pm at Fusion Korea next to Homestead Lanes (though we don’t bowl there — long story).


[ Yahoo! Maps ]

Map of Fusion Korea:
20956 Homestead Rd Ste A1
Cupertino, CA 95014-0310

Universal Python Build

Monday, April 10th, 2006

Bob Ippolito and Ronald Oussoren have been working on a branch of Python 2.4 with the intention of creating a universal build of Python.

They have done that and more. A lot more. In the process, many other aspects of Python on Mac OS X have been fixed or optimized. Furthermore, the Python build now uses SDKs as a part of the build. This lays the framework for being able to do development on one version of the OS while targeting older versions with Python. Very nice.

This is one of the areas of the world of universal binaries that few people really understand.

Building a correct universal binary of most open source projects is exceedingly hard.

Simply passing CFLAGS=-arch i386 -arch ppc will generally not yield a correct binary. Worse, if the project uses autoconf, you can rest assured that the result of ./configure ; sudo make install will only yield a correct result for the architecture the build is created on. While autoconf can support cross-compilation, very few developers using autoconf will jump through the hoops necessary to do so.

And that is really what this boils down to. Cross compilation is hard to get right. Xcode makes building universal binaries easy because the entire high level Mac OS X development model and all of the predecessor technology has been focused on cross-compilation for well over a decade.

If you are planning on developing or maintaining a body of source targeted to Mac OS X that cannot use the Xcode native build system — and there are certainly many reasons to do so — I would highly recommend that you go have a close look at Ronald’s and Bob’s work.

Tracing Python Execution

Thursday, October 27th, 2005

While working with Twisted and Nevow, I ran into a situation where something terribly nasty was happening well below any code I had written. Basically, I was faced with the classic high level development problem of “something I did long ago broke something deep within several layers of large scale systems I did not write”.

In these situations, a debugger does little good because there is little clue as to where things went awry. What I really needed was a way to trace execution.

It turns out that Python has excellent hooks for doing exactly that.

Add the following to any random hunk o’ code:

import sys
import linecache
import inspect

def traceit(frame, event, arg):
    if event == 'line':
        lineno = frame.f_lineno
        if '__file__' in frame.f_globals:
            filename = frame.f_globals['__file__']
            if (filename.endswith('.pyc') or
                filename.endswith('.pyo')):
                filename = filename[:-1]
            name = frame.f_globals['__name__']
            line = linecache.getline(filename, lineno)
        else:
            name = '[unknown]'
            try:
                src = inspect.getsourcelines(frame)
                line = src[lineno]
            except IOError:
                line = 'Unknown code named [%s].  VM instruction #%d' % \
                    (frame.f_code.co_name, frame.f_lasti)
        print '%s:%s: %s' % (name, lineno, line.rstrip())
    return traceit

Then, to turn it on, call sys.settrace(). You can easily toggle the trace functionality, thus reducing the tracing to a very limited portion of the overall execution. This prevents one from drowning in data.

sys.settrace(traceit)

Note that the function has a frame object as an argument. That frame object allows for extremely deep introspection of the execution state, including variable state and just about anything else you would like to find out about the underlying virtual machine.

The original code was cribbed from the dalke scientific site. That article has an awesome explanation of the details of tracing. I just added some error checking and fallback code in the case where the original file/source cannot be determined. This enables the tracing functionality to work seamlessly within the context of Twisted.

It has already saved me a ton of time and I’m about to throw this permanently into my local Python library.

Neat PyObjC Trick

Wednesday, October 19th, 2005

I demoed the latest build of PyObjC at the recent CocoaHeads meeting in Cupertino.

The demo concluded with a “show all [most, really] the tricks at once” sequence.

  • How py2app, a part of PyObjC, will automatically create an installer package from a standard Python package
  • Injecting a live Python interpreter into a running application
  • Introspecting the application
  • Interacting with Core Data, including dealing with ** style parameters
  • Modifying a managed object and having KVO automatically fire on assignment

First, grab the top-of-tree source from the pyobjc repository:

svn co http://svn.red-bean.com/pyobjc/trunk/pyobjc/

Alternatively, you can mount that URL in the finder (click cancel on all the bloody attempts to write .DS_Store files) and cp -r the source to somewhere from the Terminal.

Then:

cd pyobjc
python setup.py bdist_mpkg --open

That will build PyObjC and open an Installer package that contains the runtime, documentation, examples, and Xcode templates.

Next, grab the OutlineEdit examples from /Developer/Examples/CoreData/ and run it.

Now, from the PyObjC source directory:
Read the rest of this entry »