4

I want to create a simple Mac application bundle which calls a simple Python script. I want to do that in Python.

Is there an easy way?

I tried to use py2app but that fails somehow, e.g.:

from setuptools import setup
setup(app=["foo.py"], setup_requires=["py2app"])

gives:

---------------------------------------------------------------------------
SystemExit                                Traceback (most recent call last)
/Users/az/<ipython console> in <module>()

/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/distutils/core.pyc in setup(**attrs)
    138         ok = dist.parse_command_line()
    139     except DistutilsArgError, msg:
--> 140         raise SystemExit, gen_usage(dist.script_name) + "\nerror: %s" % msg
    141 
    142     if DEBUG:

SystemExit: usage: ipython [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
   or: ipython --help [cmd1 cmd2 ...]
   or: ipython --help-commands
   or: ipython cmd --help

error: no commands supplied
Type %exit or %quit to exit IPython (%Exit or %Quit do so unconditionally).

I also tried:

import py2app.build_app
py2app.build_app.py2app("foo.py")

which also doesn't work (TypeError: dist must be a Distribution instance) (I'm not really sure how to use py2app.build_app.py2app and also haven't really found much examples / documentation about it).

Maybe setuptools/py2app or so are anyway overkill for my use case. I just want to create a simple empty app bundle, copy a Python script into it and configure its Info.plist in such a way that it calls the Python script.

3

3 Answers 3

10

This is exactly what I wanted and works just fine:

#!/usr/bin/python

import sys
assert len(sys.argv) > 1

apppath = sys.argv[1]

import os, os.path
assert os.path.splitext(apppath)[1] == ".app"

os.makedirs(apppath + "/Contents/MacOS")

version = "1.0.0"
bundleName = "Test"
bundleIdentifier = "org.test.test"

f = open(apppath + "/Contents/Info.plist", "w")
f.write("""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleExecutable</key>
    <string>main.py</string>
    <key>CFBundleGetInfoString</key>
    <string>%s</string>
    <key>CFBundleIconFile</key>
    <string>app.icns</string>
    <key>CFBundleIdentifier</key>
    <string>%s</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>%s</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>%s</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>%s</string>
    <key>NSAppleScriptEnabled</key>
    <string>YES</string>
    <key>NSMainNibFile</key>
    <string>MainMenu</string>
    <key>NSPrincipalClass</key>
    <string>NSApplication</string>
</dict>
</plist>
""" % (bundleName + " " + version, bundleIdentifier, bundleName, bundleName + " " + version, version))
f.close()

f = open(apppath + "/Contents/PkgInfo", "w")
f.write("APPL????")
f.close()

f = open(apppath + "/Contents/MacOS/main.py", "w")
f.write("""#!/usr/bin/python
print "Hi there"
""")
f.close()

import stat
oldmode = os.stat(apppath + "/Contents/MacOS/main.py").st_mode
os.chmod(apppath + "/Contents/MacOS/main.py", oldmode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
Sign up to request clarification or add additional context in comments.

1 Comment

You could take a look at Platypus, which creates Mac application wrappers from interpreted scripts. sveinbjorn.org/platypus
4

Check out PyInstaller.

You give it the path to your python script and it analyzes all of your package imports, extracting any binary files that are needed and placing them into an archive.

I've used it for a fairly complex python program, and it worked for me.

5 Comments

I don't want all that. I just want to create an empty app bundle.
Then your app won't be portable.
Why wouldn't it? See my own answer. That should be portable.
What if the user has a different /usr/bin/python than what you expect? What if the user's python installation is missing a module you require?
I'm only using standard (MacOSX) includes. Anyway, that is not really the scope of my question. Of course, if I would need additional stuff, I could add that.
0

cxFreeze is best solution available as it is simple and time-saving.

first, create your program or application using python and then make setup file for your application.

And then build the app using build command python setup.py build, according to your requirement you need to make some changes, to make mac bundle or mac app refer this

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.