py2app – Create standalone Mac OS X applications with Python

在 Windows 是用 py2exe 把 python 變 standalone,  在  Mac 是用 py2app, 滿神奇的,Mac OS X原本就有內建 python 和 pip 還有已經有  py2app.

官方網站:
https://pythonhosted.org/py2app/

 

和 py2exe 一樣,要先來一個  setup.py:
https://pythonhosted.org/py2app/tutorial.html#create-a-setup-py-file

直接下 py2applet –make-setup MyApplication.py 會顯示:
-bash: py2applet: command not found

實際上檔案有,在這裡:
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/bin/py2applet

 

所以,使用完整路徑,就可以使用, ex:

/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/bin/py2applet –make-setup MyApplication.py

 


有了 setup.py 後,下指令:

python setup.py py2app -A

新的錯誤訊息:

error: [Errno 1] Operation not permitted:

 

禁用 System Integrity Protection (SIP) 的圖文教學1:
http://www.macworld.com/article/2986118/security/how-to-modify-system-integrity-protection-in-el-capitan.html

禁用 System Integrity Protection (SIP) 的教學2:
http://stackoverflow.com/questions/33197412/py2app-operation-not-permitted

After I upgraded my operating system to OS X EI Capitan (10.11.2), I got similar error when packaging my app using py2app:

*** creating application bundle: MyApp ***
error: [Errno 1] Operation not permitted: '/Users/jake/work/my-app/dist/MyApp.app/Contents/MacOS/MyApp'

I did some research and found a solution: 1) disable SIP; 2) remove restricted file flag on Python.framework. It worked for me.

Disable SIP

  1. Restart your Mac.
  2. Before OS X starts up, hold down Command+R and keep it held down until you see an Apple icon and a progress bar. Release. This boots you into Recovery.
  3. From the Utilities menu, select Terminal.
  4. At the prompt type the following:
    csrutil status
    csrutil disable
    reboot

You can re-enable SIP by following the above steps, but using:

csrutil enable

References:

Remove Restricted File Flag

sudo chflags -R norestricted /System/Library/Frameworks/Python.framework

As it’s mentioned in https://forums.developer.apple.com/thread/6987

 


不想禁用 SIP, 可以改用 virtualenv

Creating standalone Mac OS X applications with Python and py2app
https://www.metachris.com/2015/11/create-standalone-mac-os-x-applications-with-python-and-py2app/

 

virtualenv 基礎教學:
http://docs.python-guide.org/en/latest/dev/virtualenvs/

 


通過pip安裝virtualenv:

pip install virtualenv

教學:
http://pythonguidecn.readthedocs.io/zh/latest/dev/virtualenvs.html


cd your_project_folder
virtualenv venv
. venv/bin/activate

滿有趣的,提示字元前多了一個(venv)

要退出,就是下 deactivate 即可。

只有第1次需要下 virtualenv venv 之後要進去,就是 activiate 就進去了。

滿神奇的,可以不需要下 sudo 就可以透過 pip 安裝所有的程式。virtualenv 裡是乾淨的,所以所有第3方的 package 需要重新 pip install 一次。


先下 /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/bin/py2applet –make-setup MyApplication.py


再下:

sudo python setup.py py2app -A

就成功了,原來  -A 是用來測試的。實際發行要拿掉 -A,  開始研究 sandwish 裡的參數:

This setup.py is a basic definition of the app:

from setuptools import setup

APP = ['Sandwich.py']
DATA_FILES = []
OPTIONS = {'argv_emulation': True}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

If your application uses some data files, like a JSON, text files or images, you should include them in DATA_FILES. For example:

DATA_FILES = ['testdata.json', 'picture.png']

Build the app for development and testing

py2app builds the standalone application based on the definition in setup.py.

For testing and development, py2app provides an “alias mode”, which builds an app with symbolic links to the development files:

$ python setup.py py2app -A

This creates the following files and directories:

.
├── build
│   └── bdist.macosx-10.10-x86_64
│       └── python2.7-standalone
│           └── app
│               ├── Frameworks
│               ├── collect
│               ├── lib-dynload
│               └── temp
├── Sandwich.py
├── dist
│   └── Sandwich.app
│       └── Contents
│           ├── Info.plist
│           ├── MacOS
│           │   ├── Sandwich
│           │   └── python -> /Users/chris/Projects/chris/python-gui/tkinter/env/bin/../bin/python
│           ├── PkgInfo
│           └── Resources
│               ├── __boot__.py
│               ├── __error__.sh
│               ├── lib
│               │   └── python2.7
│               │       ├── config -> /Users/chris/Projects/chris/python-gui/tkinter/env/bin/../lib/python2.7/config
│               │       └── site.pyc -> ../../site.pyc
│               ├── site.py
│               └── site.pyc
└── setup.py

This is not a standalone application, and the applications built in alias mode are not portable to other machines!

The app built with alias mode simply references the original code files, so any changes you make to the original Sandwich.py file are instantly available on the next app start.

The resulting development app in dist/Sandwich.app can be opened just like any other .app with the Finder or the open command ($ open dist/Sandwich.app). To run your application directly from the Terminal you can just run:

$ ./dist/Sandwich.app/Contents/MacOS/Sandwich

Building for deployment

When everything is tested you can produce a build for deployment with a calling python setup.py py2app. Make sure that any old build and dist directories are removed:

$ rm -rf build dist
$ python setup.py py2app

This will assemble your application as dist/Sandwich.app. Since this application is self-contained, you will have to run the py2app command again any time you change any source code, data files, options, etc.

The original py2app has a bug which would display “AttributeError: 'ModuleGraph' object has no attribute 'scan_code'” or load_module. If you encounter this error, take a look at this StackOverflow thread or use my fork of py2app.

The easiest way to wrap your application up for distribution at this point is simply to right-click the application from Finder and choose “Create Archive”.

Adding an icon

Simply add "iconfile": "youricon.icns" to the OPTIONS dict:

from setuptools import setup

APP = ['Sandwich.py']
DATA_FILES = []
OPTIONS = {
    'argv_emulation': True,
    'iconfile': 'app.icns'
}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

You can find free icons in icns format around the web (eg. on IconFinder or freepik).

Advanced app settings

You can tweak the application information and behaviour with modifications to the Info.plist. The most complete reference for the keys available is Apple’s Runtime Configuration Guidelines.

Here is an example with more modifications:

# -*- coding: utf-8 -*-
from setuptools import setup

APP = ['Sandwich.py']
APP_NAME = "SuperSandwich"
DATA_FILES = []

OPTIONS = {
    'argv_emulation': True,
    'iconfile': 'app.icns',
    'plist': {
        'CFBundleName': APP_NAME,
        'CFBundleDisplayName': APP_NAME,
        'CFBundleGetInfoString': "Making Sandwiches",
        'CFBundleIdentifier': "com.metachris.osx.sandwich",
        'CFBundleVersion': "0.1.0",
        'CFBundleShortVersionString': "0.1.0",
        'NSHumanReadableCopyright': u"Copyright © 2015, Chris Hager, All Rights Reserved"
    }
}

setup(
    name=APP_NAME,
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *