- The easiest way to change a file's extension is to save the file as a different file type from within a software program. Changing the file extension in the file name won't change the file type, but will cause the computer to misidentify the file. In Windows and Mac OS X, file extensions are often hidden.
- The application bundle will be named after your script; if your script was named MyApplication.py, then your application bundle will be named MyApplication.app. Note that Finder displays application bundles without the.app extension. You only need to run this command again when you add data files or change options.
- How To Change Py To Dmg Files
- How To Change Py To Dmg File
- How To Change Py To Dmg Converter
- How To Change Py To Dmg Reader
While I was working on the Quaver Lyrics Finder project (it’s my first time writing Python, please be gentle), I wanted to make it into an easy-to-use program that most people to use. That meant:
A PY file is a program file or script written in Python, an interpreted object-oriented programming language. It can be created and edited with a text editor, but requires a Python interpreter to run. PY files are often used for programming web servers and other administrative computer systems. So, unless you need to change the setup.py, you do not need to rebuild the alias bundle. This means that you can simply edit the source, and restart the application! An alias bundle is similar to BundleBuilder 's -link option, and is roughly equivalent to the idea of Xcode 's ZeroLink feature.
- Looking native, presenting a GUI when clicked.
- Turning it into a self-contained executable file that does not rely on having Python or other dependencies being installed.
- Creating a file that users could download in an expected file format. This means having a .exe or .msi for Windows, a .dmg for macOS, and a .deb for Ubuntu.
Here’s what I did.
This is the first part of the series where I write about things I learned while writing a desktop app. The second post can be found here.
- Turning the project into a self-contained executable file
- 2.1 Using PyInstaller
- 2.2 Customizing the spec file
- Creating a package in an expected file format
1. Looking native
For creating a GUI in Python, I chose to use PyQt5, a framework that provides Python bindings for the great C++ Qt framework.
Reasons in favour of PyQt:
- Looks like native elements.
- Compatibility with Python 3.5+.
- Well tested and documented.
Something that you should consider about PyQt5 is that licensed under the GPL 3.0 license. That means that if you distribute the Qt Gui Toolkit as part of your application binary, your program must also be licensed under a GPL-compatible license. Since my project was open-source anyway and uses the MIT license, this was fine by me.
Other possible choices:
- Pyside: Another framework for bindings for Qt. In favour: Less restrictive licensing (LGPL instead of GPL). Against: Does not support Qt5, a little bit less well-documented because it’s less well funded than PyQt.
- TkInter: A GUI framework that comes pre-installed with Python. In favour: Easy to set up, since it’s pre-installed with Python. Against: Does not look native, less popular than PyQt/PySide.
- Kivy: Another GUI framework. Against: Not Qt, but seems decent otherwise.
- wxPython: Doesn’t support Python 3, so this was out.
I’ve used PyQt on four different platforms - macOS, Windows, Ubuntu, and elementary OS. The GUI looks pretty good on all of them, so the cross-platform claim checks out!
2. Turning the project into a self-contained executable file
I’m using PyInstaller to generate an executable for my python files.
- Checks for dependencies for all files, and puts them into your executable.
- Works cross-platform: same commands in macOS, Windows, Linux.
- Is easy to use - one command in whatever shell you prefer.
- Is actively maintained, has decent documentation, and relatively popular.
Since it’s popular, chances are that when you have a problem, there’s somebody else who’s already run into it. Stack Overflow, the GitHub page, and even just the documentation are life-savers. Keep in mind also that PyInstaller is not a cross-compiler, i.e. you can’t build Windows .exe files when using macOS, etc. Use PyInstaller in a VM to do that.
Other possibilities include:
- bbfreeze: But it’s unmaintained and does not support Python 3.
- py2app: It’s not being maintained, and not cross-platform (you need to use py2exe to create an executable for Windows).
- cx_Freeze: Less actively maintained compared to PyInstaller.
- pyqtdeploy: More fussy than PyInstaller, and harder to set up.
2.1 Using PyInstaller
PyInstaller can be downloaded with pip:
Then, starting off with PyInstaller should be as simple as running:
It checks for dependencies, analyzes
<your_file>.py, and generates an executable file in
dist/ as well as a
<your_file>.spec file in the same directory as
<your_file>.py. If all goes according to plan, there should now be a single executable file that you can click to open in
dist/ and it should run as if you had run your script from the command line.
For more details, read their docs.
2.1.1 Useful options
--onefile allows you to create a single executable.
--onedir creates executables in a folder structure. Useful for debugging.
pyinstaller <your_file>.spec will use the specified spec file to build the executable. This is very useful if you’ve customized the spec file.
2.2 Customizing the spec file
The spec file is a Python script that PyInstaller uses to determine what to build and where to build it. Understanding this is essential to understanding PyInstaller. There are several customizations that I’ve done to my spec files that have come in handy.
A spec file is generated automatically in the same directory as your file when you run
pyinstaller <your_file>py. You can customize it from there on. Note that if you run
pyinstaller <your_file.py again, it will generate another spec file that overwrites any customizations that you made! To avoid this, give pyinstaller a spec file as an argument, e.g.
If you refer to assets by a relative path in Python file
QtGui.QIcon('./assets/icon.png'),the executable that PyInstaller generates won’t include them in the correct place, and your program will not be able to find the assets. This happens for images, text files, data files, and more.
The workaround that I’ve found:
- Add these lines after the
a = Analysis(...)code block in the spec file, with more entries as appropriate:
Note that in certain filesystems, case matters! This bit me in Ubuntu.
The path to the file is always relative to the directory where you the .py file you are asking PyInstaller to analyse is. As an example, this is what the directory structure could look like:
With that directory structure, the code snippet would become:
- After having modified your spec file, you’ll need to go back to
<your_file>.pyand add the following code somewhere:
Explanation: PyInstaller creates a temporary folder called _MEIPASS, that contains the files as named in
a.datas. Thus, the _MEIPASS folder exists only when the code is running as an executable bundle generated by PyInstaller. This function checks for that folder, and if it exists, thus knows that it’s running the executable. When the code is in an executable bundle, this function will convert your relative path to the path in the _MEIPASS folder, and otherwise leaves it alone.
- Once you’ve added the function to your code, you’ll need to update every place that has a relative path to call that function.
As an example:
- And finally, run PyInstaller with your new spec file. For example, when I’m generating a bundle for Quaver, I do
2.2.2 Generating a bundle for macOS
PyInstaller is really good for creating bundles that conform to Apple’s Bundle Structure, making them easily code-signable. Here’s what I add to my spec file after the
pyz code block to generate a bundle for macOS.
In BUNDLE(), info_plist will create the appropriate <key> and <string> in the .app bundle structure. For example, the NSHighResolutionCapable example looks like this in the
Info.plist file in
Unfortunately, specifying the types of documents the app supports doesn’t work with this format. I have a post about this here, but you need a
CFBundleDocumentTypes key with an array of values, which is too complicated for PyInstaller’s spec file to handle. The only solution is to create and save a separate Info.plist file, then replace the one PyInstaller generates in
your_app.app/Contents/. See here for more details. :/
2.2.3 Generating a .exe for Windows and executable for Linux
Here’s what I’m using in my spec file for Windows and Linux:
3. Creating a package in an expected file format
After customizing the spec file and running PyInstaller, we now have a nice executable file. A .app on macOS, a .exe on Windows, and an executable file on Linux. The next step is to package it into something that users are used to downloading.
3.1 Creating a .dmg for macOS
I’m not fussy, so I used a simple command line tool that creates a .dmg from a .app, called create-dmg. It’s purposely simple, and doesn’t offer many options.
Assuming you have npm installed (otherwise,
brew install npm (and if you don’t have brew click here):
Now, cd into the directory containing your .app file generated by PyInstaller, and run:
You should now have a new
<your_app_name> <sem_ver>.dmg file in the directory where you ran create-dmg! Create-dmg pulls the version number from your app’s
Contents/Info.plist folder, so if it’s wrong, update the Info.plist file first.
How To Change Py To Dmg Files
3.2 Creating a .msi file for Windows
If you don’t need to change the registry, you could just distribute the .exe file that PyInstaller generated, since the .exe file is basically a portable version of your program. Otherwise, you’ll need to create a separate installer executable to set things up correctly. Another benefit of an msi file is that it can properly integrate with the start menu and create desktop shortcuts easily.
I’m using the free version of Advanced Installer to do this. Some gotchas: make sure you create a “Simple” project instead of a “Professional” or anything else, because “Simple” is the only one that’s free, and you cannot convert one type of project to another later on. Advanced Installer lets you create Professional projects when you download by automatically activating a trial, which is sneaky.
Customize as necessary. See their website for a simple tutorial on how to get started and their professional guide which walks through a few more tools.
- WiX Toolset:
- ++ Immensely powerful and more customizable.
- ++ Uses text files for configuration, which simplifies version control and portability.
- ++ Free and open source.
- ++ Well documented, and tested.
- -- Significantly harder to learn and get started with. Since my project didn’t have big requirements (all I wanted to do was add a few registry keys), learning to use WiX would have been overkill.
- ++ Powerful, solid, and well-liked.
- ++ Good GUI.
- ++ Good support.
- ---- Literally costs thousands of dollars. I’m not exactly going to spend that much for a one-time project.
3.3 Creating a .deb file for Ubuntu
Unlike macOS and Windows, the tools to create a .deb file are built-in to the operating system!
You’ll need to create a directory structure as follows:
The control file is what the advanced package tool reads to see what needs to be changed and which app is being installed. See more in the documentation. A basic control file might look something like this:
How To Change Py To Dmg File
The <project>.svg file should contain an SVG of your app icon.
The <project>.desktop file allows the launcher to discover your program, and integrates it with your system. See here for more information. A basic .desktop file might look something like this:
Once all that is done, all that you have to do is a simple command, and your .deb file will be created in the same directory as the folder.
How To Change Py To Dmg Converter
4. Closing notes
Writing the functionality isn’t the last thing that needs to be done – just look at this entire blog post as an example. Keep working through it, and it’ll all work out.
How To Change Py To Dmg Reader
If you’re interested in finding out more about the “Open with” functionality and the second post of this series, see here!