I want to build and deploy a hello world using a homebrewed python + py2app.
Build machine: MacOS X 10.12.6
Target machine: MacOS X 10.11
Following many posts I modified the python.rb formula by setting inside MACOSX_DEPLOYMENT_TARGET=10.10 to insure backward compatibility with older macos kernels.
The build is OK but when I run the application on the target machine it crashes due to an Illegal Instruction 4. Digging a bit further, this crash is raised by calling the python bundled with the application.
Following that post this might be due to the very nature of the homebrewed python that might be built with hardware specific optimization flags. Checking the output of my command
brew install -v --build-from-source python
I do not see any exotic flag but I can confirm that the deployment works when the application is built with a python that does not come from brew (e.g. from www.python.org).
Would you have any idea from where this problem comes from and how to modify the python brew recipe to make it work ?
Here are my codes:
hello.py
#!/usr/bin/env python2.7
if __name__ == "__main__":
print "Hello world"
build.py
import sys
import os
from setuptools import setup
version = "1.0"
APP = ['hello.py']
PLIST = {
u'CFBundleName': u'Hello',
u'CFBundleShortVersionString': version,
u'CFBundleVersion': version,
u'CFBundleIdentifier': u'-',
u'LSApplicationCategoryType': u'public.app-category.science'
}
OPTIONS = {
'argv_emulation': True,
'plist': PLIST,
'bdist_base': './Build/build',
'dist_dir': './Build/dist',
'graph': False,
'xref': False
}
setup(
name="hello",
app=APP,
options={'py2app': OPTIONS},
setup_requires=['py2app']
)
Related
I'm using PythonKit in my Swift project for MacOS. At the moment I'm using Python 2.7 but from MacOs 12.3 it isn't no more supported so I'm trying to migrate to Python 3 but it doesn't work.
func applicationDidFinishLaunching(_ notification: Notification) {
if #available(OSX 12, *) {
PythonLibrary.useVersion(3)
}
else {
PythonLibrary.useVersion(2)
}
let sys = Python.import("sys")
print("Python \(sys.version_info.major).\(sys.version_info.minor)")
print("Python Version: \(sys.version)")
print("Python Encoding: \(sys.getdefaultencoding().upper())")
sys.path.append(Bundle.main.resourceURL!.absoluteURL.path)
let checker = Python.import("checkLibrary")
_ = Array(checker.check())
}
This is the error message:
PythonKit/PythonLibrary.swift:46: Fatal error: Python library not found. Set the PYTHON_LIBRARY environment variable with the path to a Python library.
The code fail on MacOs 12 on line 9th line (let sys = Python.import("sys")), so I can't interact so sys in any way.
I've already tried to disable sandbox and Hardened Runtime but is seems useless.
I was having the same issue.
where python3
which python3
type -a python3
I could clearly see that Python3 was present using any of the above commands from terminal. Python3 wasnt something that I directly installed, (probably something I added during an install of XCode) but I could see it located at "/usr/bin/python3"
I had already removed the sandbox and disabled the hardened runtime.
Adding the environment variable to XCode did not work and Google ultimately told me to do what had already been done.
Finally, I decided to just perform a fresh install, following the blog as guidance.
https://www.dataquest.io/blog/installing-python-on-mac/#installing-python-mac
https://www.python.org/downloads/macos/ (direct URL for Python download)
After installing, everything worked as expected.
PythonLibrary.useVersion(3)
PythonLibrary.useLibrary(at: "/usr/local/bin/python3")
I could use either of the above methods, without adding the environment variable to the XCode scheme.
Hopefully that helps
When I install one of my own Python applications from PyPi, it fails to run citing
File "/home/me/.local/lib/python3.9/site-packages/refrapt/refrapy.py", line 20, in
from classes import (
ModuleNotFoundError: No module named 'classes'.
I have the following directory layout in my local area:
/refrapt
setup.py
/refrapt
classes.py
helpers.py
refrapt.conf
refrapt.py
settings.py
__init__.py
To build the project, I'm using setuptools, running the following command:
python setup.py sdist bdist_wheel
This builds and works happily enough, and I'm able to upload the resulting /dist.
I then install the project using pip3 install refrapt. When I run it using refrapt, I get the error ModuleNotFoundError above.
When I run the development code locally, it runs fine, but installed via pip, it is failing. I assume it's a problem with my setup.py, but this is my first time and I haven't really a clue what is correct. I tried adding the init.py (which is empty) as suggested by some python docs, but to no avail. The contents of setup.py are as follows:
import pathlib
from setuptools import setup, find_packages
HERE = pathlib.Path(__file__).parent
README = (HERE / "README.md").read_text()
setup(
name='Refrapt',
version='0.1.5',
description='A tool to mirror Debian repositories for use as a local mirror.',
python_requires='>=3.9',
long_description=README,
long_description_content_type="text/markdown",
packages=find_packages(),
install_requires=[
'Click >= 7.1.2',
'Colorama >= 0.4.4',
'tqdm >= 4.60.0',
'wget >= 3.2',
'filelock >= 3.0.12'
],
classifiers=[
"Development Status :: 4 - Beta",
"Operating System :: Microsoft :: Windows :: Windows 10",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: Implementation",
"Topic :: System :: Archiving :: Mirroring"
],
keywords=['Mirror', 'Debian', 'Repository'],
entry_points='''
[console_scripts]
refrapt=refrapt:refrapt
''',
)
If anyone could help, I'd greatly appreciate. I'm out of my depth on this one, and haven't been able to find an answer so far.
from classes import …
In Python 2 this was relative import — the statements imports classes from the current directory of the importing module.
But in Python 3 it was changed to absolute import. The import fails because there is no a global module or a package named classes. You need to convert the import to absolute or relative. Either
from refrapt.classes import …
or
from .classes import …
Potentially I've found out the answer to my question, but it's not the answer I wanted.
I spun up a virtual environment, and installed an application that I've used before via pip. When I went to run the app, I got the ModuleNotFoundError: No module named 'app'.
I tried to run it manually via the .py file by using python .\.venv\Lib\site-packages\app\cli.py, which resulting in the same error.
Seems to be something about the environment setup in Windows VS Code that just doesn't operate the same as on a Linux machine.
I guess I'll just have to remove the "refrapt." prefix from import statements when developing locally, and then add it back when pushing to GitHub.
Context:
I am developping a simple Python application using a PySide2 GUI. It currently works fine in Windows, Linux and Mac. On Windows, I could use PyInstaller and InnoSetup to build a simple installer. Then I tried to do the same thing on Mac. It soon broke, because the system refused to start the command or the app generated by PyInstaller because it was not correctly signed. And as I am not an apple developper, I cannot sign anything...
After some research, I tried py2app. I can go one step further here. With
python setup.py py2app -A
I can create a runnable app. Which obviously cannot be ported to a different system because it uses my development folders. And if I use python setup.py py2app the generated program cannot start because py2app did not copy all the required Qt stuff. I tried to add one by one the missing libraries, but on the end the system could not find the plugins and I gave up...
Question:
Can someone help me with a recipe to convert a python script or package using a Qt GUI into a portable app on Mac? Ideally, the recipe should say how to use a custom application icon, but this is not required.
References:
Python 3.8.5
macOS 10.15.7 Catalina
PySide2 5.15.1
PyInstaller 4.0
py2app 0.22
As my real package is too large for a SO question I trimmed it down to a minimal reproducible example:
from PySide3.QtWidgets import *
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
hello = QLabel('Hello', self)
hello.move(50, 50)
def run(args):
app = QApplication(args)
main = MainWindow()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
run(sys.argv)
And here is the setup.py file used for py2app:
from setuptools import setup
APP = ['app.py']
DATA_FILES = []
OPTIONS = {}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
Requirements
works with Python 3.8.5
macOS 10.15.7 Catalina
uses PySide2 and py2app
Problems
PySide2 must be added under OPTIONS to the packages list
when running the app then still an error occurs: Library not loaded: #rpath/libshiboken2.abi3.5.15.dylib, Reason: image not found
Solution
The slightly modified setup.py could look like this:
from setuptools import setup
APP = ['app.py']
DATA_FILES = []
OPTIONS = {
'packages': ['PySide2'],
'iconfile': 'some_icon.icns',
'plist': {
'CFBundleDevelopmentRegion': 'English',
'CFBundleIdentifier': "com.ballesta.xxx",
'CFBundleVersion': "1.0.0",
'NSHumanReadableCopyright': u"Copyright © 2020, Serge Ballesta, All Rights Reserved"
}
}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
Additionally, an icon definition and a few plist entries for some basic information have been added.
The whole build is best triggered with a script that could look like this:
#!/bin/sh
python3 -m venv venv
. venv/bin/activate
pip install PySide2
pip install py2app
python setup.py py2app
cp ./venv/lib/python3.8/site-packages/shiboken2/libshiboken2.abi3.5.15.dylib ./dist/app.app/Contents/Resources/lib/python3.8/lib-dynload/shiboken2
Test
Here the screenshot of a test run:
I think what you're missing is the inclusion of the Python3 Framework in your application bundle. I've developed a simple macOS app myself recently, however I wanted to have a little more insight on how to do so, so I did a bit of digging into the actual structure of an application. Basically, you are going to put everything into a normal folder with the name of your application. Call this folder MyApp. Inside this folder we'll have another called Contents. From my understanding, py2app just takes all of the things that make up your app, and structures them inside of this folder as well as creates an Info.plist file, which also goes inside of Contents. So far, here is what you have:
MyApp
-> Contents
-> -> Info.plist
In addition to the Info.plist file with all of the necessary properties, in your Contents folder you will have a MacOS folder and a Resources folder at minimum. Your issue is that you also need a Frameworks folder, where you would add the required version of Python.
Now, your app hierarchy should look like:
MyApp
-> Contents
-> -> Info.plist
-> -> MacOS
-> -> Resources
-> -> Frameworks
In the Frameworks folder, you can put the full Python 3 framework you're working with to build the app, as well as any site-packages that you require to run the application, and then you can reflect all of those changes in the executable so that you are pointing to the correct installations.
To my understanding, all that's necessary to make the application functional on MacOS is to ensure that your main executable is placed in the MacOS folder and points to the Python located in your Frameworks folder, your icon .icns file is placed in the Resources folder, and your Info.plist file is built.
In order for MacOS to recognize it as a full application, I believe you possibly need to use productbuild and include a Developer license certificate, but it's really only necessary if you want the application to be distributed. Otherwise, I just added the extension .app to MyApp, which converts it into an application.
Without the above-mentioned license/certificate whatever, it probably won't recognize that it should find your icon file and add it, so if you open it in Preview, select-all, and copy it, you should be able to right-click on the application, press 'Get Info', and paste the icon on top of the current icon in the window to make it display correctly.
EDIT: My resources for learning about making macOS apps:
Bundle structure
Including frameworks
Signing your application
productbuild manpage
If you want to package for OSX, you should either
Create a Brew Tap
This probably makes the most sense for an open source developer
General Instructions https://docs.brew.sh/How-to-Create-and-Maintain-a-Tap
host your code in git (does not need to be GitHub)
create a Formula (Formula Cookbook)
fork homebrew-core on GitHub
add your Formula and create a pull request to get it into the main repo
support your pull request such that it is completed
Join the Apple Developer Program
This probably makes the most sense for a closed source developer
Overview: https://developer.apple.com/programs/how-it-works/
This program costs 99USD annually, but will allow you to sign your package/final binary and distribute it yourself or on their App Store
After creating your account, here's a guide for packaging and signing for OSX https://developer.apple.com/forums/thread/128166
structure your code to support signing (add a build step to copy your work into a clean path to avoid frustrating rework)
% codesign -s <Developer ID Application signing identity> /path/to/code
pick a storage format (.zip, .dmg, .pkg) and bundle your application as it
After fiddling around a lot with the different options to build a macOS bundle for a PySide2 application I found the following steps to work pretty much out of the box.
This recipe using pyinstaller to create a macOS app bundle was tested with Python 3.9.1, PySide2 5.15.2, pyinstaller 4.2 on macOS Catalina 10.15.7.
Install pyenv and latest Python with Framework support (see Pyenv, How to manage multiple Python versions and virtual environments for a general introduction into how pyenv works):
brew install pyenv
PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.9.1
Create a folder for the example, create an example pyside application:
mkdir hello && cd hello
nano hello.py
hello.py:
import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setWindowTitle("Hello World")
self.button = QPushButton("Click me")
self.button.clicked.connect(self.say_hello)
self.setCentralWidget(self.button)
#Slot()
def say_hello(self, url):
self.button.setText("Hello!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Create a venv for the project, install python packages:
pyenv local 3.9.1
python3 -m venv venv
source venv/bin/activate
pip install pip pyside2 pyinstaller --upgrade
Try running the app using the python interpreter:
python3 hello.py
Create a macos app bundle:
pyinstaller --windowed hello.py
Run the app using the app bundle:
open dist/hello.app
Check out the generated hello.spec for the build configuration, re-build the app with pyinstaller hello.spec.
I have successfully build apps using fbs.
It is intended to build Python+PyQt5 apps (you can also use PySide2) and it should work on Mac OS as well (according to the documentation/tutorial).
Using PyInstaller it failed very often for including PyQt5 dependencies (especially when I was working with pyqtgraph), but with fbs it works great.
I think the solution to your problem can be found here. First, create a virtual environment and install all modules to the same virtual environment.
mkvirtualenv --python="PATH/TO/PYTHON3.6.5/python.exe" venv
Install Qt framework
# Install qt via homebrew
brew install qt
# Switch to version 5.11.1
brew switch qt 5.11.1
# Do this to link qmake with qt
brew link qt5 --force
Then, install the PySide2
git clone --recursive https://code.qt.io/pyside/pyside-setup
After that,
cd pyside-setup && git checkout 5.11
Build, and install PySide2 and make sure to set the path of QMAKE that comes with the Qt installation
#To get the path
which qmake
# Make sure that your virtual environment is activated
# Build PySide2 from source
python setup.py install --qmake=<PATH/TO/QMAKE> --build-tests --ignore-git --jobs=8
# Install PySide2
python setup.py build --qmake=/path/to/qmake --build-tests --ignore-git --jobs=8
Update
First, make sure that you run your code in the same virtual environment, and to convert it to a standard mac OS app you can use py2app or pyinstaller . Also, try to downgrade your py2app if it is not working with your current version after you follow the same process.
sudo easy_install py2app
#or
pip install -U git+https://github.com/metachris/py2app.git#master
Create setup.py
py2applet --make-setup app.py
Wrote setup.py
and you have to create a config file or see this example and include any file that you have
from setuptools import setup
APP = ['app.py']
DATA_FILES = []
OPTIONS = {
'argv_emulation': True,
'iconfile': 'app.icns'
}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
To build the application use
python setup.py py2app -A
To run the app you have to use this way
./dist/app.app/Contents/MacOS/app
If it is work with python setup.py py2app -A that means that everything is going ok and you need to use
rm -rf build dist
python setup.py py2app
If any things go wrongs please refer to these references1, 2, and 3. Also, there are alternatives ways to convert your app to os.
After I read your comment, I tried to see what is the problem and I found this and it may solve the problem or you can use alternatives tools such as bbFreeze, pyInstaller or cx_Freeze
I am attempting to use py2app to bundle a small Python app that I've made in Python 2.7 on Mac. My app uses the Watchdog library, which is imported at the top of my main file:
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
When running my program, these import statements work just fine, and the program works as expected. However, after running py2app, launching the bundled application generates the following error:
ImportError: No module named watchdog.observers
At first I thought it was something to do with the observers module being nested inside watchdog, but to test that, I added the line
import watchdog
to the top of my program, and then upon running the app, got the error
ImportError: No module named watchdog
so it seems that it actually can't find the watchdog package, for some reason.
I tried manually adding the watchdog package using py2app's --packages option:
$ python setup.py py2app --packages watchdog
but it had no effect.
My unbundled Python program runs just fine from the command line; other downloaded modules I've imported are giving no errors; and I have successfully bundled a simple "Hello World!" app using py2app, so I believe my setup is correct.
But I'm kind of out of ideas for how to get py2app to find the watchdog package. Any ideas or help would be greatly appreciated.
Edit: Here is the text of my setup.py, as generated by py2applet. I haven't modified it.
from setuptools import setup
APP = ['watcher.py']
DATA_FILES = []
OPTIONS = {'argv_emulation': True}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
Try manually including the desired packages in the setup.py file:
from setuptools import setup
APP = ['watcher.py']
DATA_FILES = []
PKGS = ['watchdog', /*whatever other packages you want to include*/]
OPTIONS = {
'argv_emulation': True,
'packages' : PKGS,
}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
I had installed watchdog 0.5.4, a very old version as it turns out, and got the same error. The error was fixed after upgrading it to 0.8.3:
pip install watchdog --upgrade
Your problem generally indicates that the package (in your case "watchdog", or one of its dependencies) isn't installed, or at least not in a location that py2app expects to find packages.
Do you use the same python command for running py2app as for running the script from the command-line? What is the message of the ImportError you're getting (both when importing "watchdog" and importing "watchdog.observers"?
The (way too long) output of py2app should also mention that it cannot find some packages, and which ones.
As alluded to in one of the answers py2app does not seem to search the same set of paths that are used by the python interpreter, so you need to copy the python library to one of those locations.
For example I've got the MacPorts version of Python installed and found that when I had a module installed in /Library/Python/2.7/site-packages/ py2app wasn't finding it, but it would find it when I copied it into /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages. So to copy it over run :
sudo cp /Library/Python/2.7/site-packages/thatmodule.so /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
Then run the py2applet script again and build the app to check. If it's elsewhere you can do a search for all site-packages locations using Spotlight's command line interface:
mdfind -name site-packages
I am using buildout to create a local python environment, and then using the local python to create my app with py2app. But, when I go into the .app file, specifically into Contents/MacOS/, there is just a shortcut to the system python. I want py2app to somehow take the local python with it so that it only depends on itself, not on the system python.
So my question is: How can I fix this so that py2app will bundle my custom local version of python2.7 so that my app will be totally standalone, regardless of the local python version?
Please let me know if more information would be helpful.
My setup.py
from setuptools import setup
APP = ['main.py']
DATA_FILES = ['src/icon.xib']
OPTIONS = {
'argv_emulation': True,
'packages': [ 'requests' ],
'iconfile':'src/myApp.icns',
'plist': {'CFBundleShortVersionString':'0.1.0',
'LSUIElement': True
}
}
setup(
name='myApp',
package_dir = {'':'src'},
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
Py2app will not include system files, such as the python installation in /System/Library/Frameworks, in your application bundle.
To create a bundle that also includes Python you need to install a separate version of Python (and all libraries that you use).
However, note that the app created with the system version of Python should work properly on machines with the same release of OSX, or a later release.