[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