[Pythonmac-SIG] obtaining versions of application bundles

Bob Ippolito bob at redivi.com
Fri Oct 22 07:48:34 CEST 2004


On Oct 22, 2004, at 0:58, brad.allen at omsdal.com wrote:

>
> Bob Ippolito <bob at redivi.com> wrote on 10/21/2004 07:08:49 PM:
>
>> With PyObjC:
>>
>>>>> from Foundation import *
>>>>> bndl = NSBundle.bundleWithPath_(u'/Applications/iTunes.app')
>>>>> bndl.infoDictionary()[u'CFBundleVersion']
>> u'4.6'
>>
>> Without:
>>
>>>>> import plistlib
>>>>>
>> plistlib.Plist.fromFile(u'/Applications/iTunes.app/Contents/
>> Info.plist')[u'CFBundleVersion']
>> '4.6'
>
> Thanks! I'm glad to know there's an easy way to get this done in the 
> short
> term without having to install PyObjC, even though long term I will
> probably want to have PyObjC deployed as part of our standard Mac
> configuration.

Do it!  If not now, then when 1.2 is released.  1.2 adds a couple 
useful things that let you have more control from Python (a la ctypes). 
  A big one is that you can bridge a certain class of functions that 
aren't even Obj-C, as long as they are in a bundle (current somewhat 
arbitrary restriction).. for example, I was able to get access to 
LaunchServices today using only this bridge.

>> (note that neither of these approaches will work for CFM applications
>> that are not an application bundle.. you would need to read the
>> resource fork and get the plist resource.. I think it's 'plst',..)
>
> We have already crossed that bridge by hiring a developer (Walker 
> Hale) to
> build a Python module to do that. He came up with a way to do it using
> Python's built-in support for Carbon on OS X. I'm hoping my employer 
> will
> allow me to post more of the project code publicly, because we can 
> benefit
> from "open source" scrutiny, and because some of it may prove useful to
> others.

Yeah, Carbon is annoying.. It would look something like this:

from Carbon.File import FSRef, FSGetResourceForkName
from Carbon.Files import fsRdPerm
from Carbon.Res import FSOpenResourceFile, CloseResFile, UseResFile, 
Get1Resource
from cStringIO import StringIO
import os, plistlib

def getInfoPlistForApp(app):
     if os.path.isdir(app):
         return plistlib.Plist.fromFile(os.path.join(app, 'Contents', 
'Info.plist'))
     fsRef = FSRef('/Applications/Remote Desktop Connection/Remote 
Desktop Connection')
     resId = FSOpenResourceFile(fsRef, FSGetResourceForkName(), fsRdPerm)
     UseResFile(resId)
     plistData = StringIO(Get1Resource('plst', 0).data)
     CloseResFile(resId)
     return plistlib.Plist.fromFile(plistData)

def appVersion(app):
     return getInfoPlistForApp(app)['CFBundleVersion']

# Mach-O
 >>> appVersion('/Applications/iTunes.app')
'4.6'

# CFM
 >>> appVersion('/Applications/Remote Desktop Connection/Remote Desktop 
Connection')
'1.0.3'

... though I would use LaunchServices, not paths, to find applications, 
which you *can't* do with a standard MacPython distribution without 
fetching at least one extension :)

-bob



More information about the Pythonmac-SIG mailing list