Deploying Python 3 to the Homes of Children Everywhere (on macOS)

(This is an edited transcript of an SF Python lightning talk I gave on .)

I’m the co-author of a book called Hello World!: Computer Programming for Kids and Other Beginners. It’s an introductory programming book that uses Python, and it’s currently in its third edition. Our book uses a lot of different Python modules to teach various programming concepts: we introduce things like Pygame and PyQt to talk about different approaches to graphics, and new in the Third Edition, we’re using the built-in socket module and the telnet command to teach network programming.

One of the unique challenges you run into when you write a kids’ book is how do you actually get all of this software—Python, IDLE, and all these modules—onto the kid’s computer? Because the kind of people who buy our book are not necessarily going to be comfortable with computers themselves. They’re not necessarily going to want to open up their console and use pip to install different packages.

On Windows, we asked our friend Sean Cavanagh to create a “combo installer” that runs all of the official installers for Python, PyQt, Pygame, and so on, one after the other. This approach works really well on Windows; we don’t need to update it very frequently, and we receive very few reports of readers running into problems with this installer. (If you do run into a problem with the Windows installer, please email us at cp4khelp@gmail.com.)

On macOS, the situation is a little bit more complicated.

We started out by trying to do the same thing that we do on Windows. macOS has an Installer package system, so we made a single big metapackage that included all the software needed for the book. This sort of worked initially, but we discovered a couple issues. First, it’s difficult to uninstall software that people install this way. Also, as it turns out, the Second Edition of our book lived longer than a lot of the open-source software it used, so we needed to do things like build Qt 4 with custom patches to get it to run on the latest macOS versions. Re-creating the official Installer packages was pretty difficult!

So what we tried next was using Homebrew. Homebrew is a very popular open-source package manager for macOS. It has a whole bunch of packages, including Python and all sorts of Python-related things, so we built a single big metapackage that included everything we needed. Again, this sort of worked initially, but we ran into some trouble. Readers in countries like China that have Internet restrictions couldn’t use Homebrew. We had issues with multi-user systems, because Homebrew was designed mainly for individual developers who have their own laptops. And the Homebrew maintainers like to do things like renaming packages that, while they may make things nicer for individual users, do create a bit of a maintenance burden for people like us who are building software that depends on Homebrew.

For the Third Edition, I decided to roll up my sleeves and create what will definitely be the best and final solution to the “installing Python on macOS for kids” problem: HelloWorld3.app. This is a single, self-contained app bundle you can drag-and-drop anywhere on your file system, including on a USB drive. You don’t even have to be an administrator. You open it up, and you get a little window with buttons to open IDLE, Qt Designer, and Terminal:

A screenshot of a small window with buttons to open IDLE, Qt Designer, and Terminal

The way this works under the hood is that macOS app bundles are basically just fancy folders. For a typical Objective-C application, you might have a “Launcher” binary executable and stuff like the icon.

The folder layout of a typical Objective-C application.

If you’re packaging up a Python application to distribute to people, you’ll include a couple of extra things, like a copy of Python.framework and the .py file that runs your program. (Usually, you’d use a tool like PyInstaller or py2app to do this automatically for you.) So you might think that, for our book, creating the app bundle would be as easy as drag-and-dropping stuff like IDLE and Qt Designer in there. And it almost was!

The trouble is, how does IDLE find Python.framework? Normally, if you just install Python from the official python.org download, it hard-codes it. There’s a piece of code in IDLE.app that says, “Find Python at /Library/Frameworks/Python.framework.” That wouldn’t work for our app bundle because users can drag it anywhere on their filesystem, so we had to rewrite those paths to awful relative @executable_path/../../../../Frameworks/Python.framework ones.

Rewriting the path pointing from IDLE to Python.framework.

Again, if you’re using something like PyInstaller or py2app, they’ll rewrite all those paths automatically for you as needed. But we couldn’t really use those because as it turns out, when you’re shipping an entire Python development environment, the dependency tree is a little bit more complicated.

A complicated dependency tree.

If you’d like to see the results of this effort, they’re up on GitHub. If you want to download the finished installer and try it out, or if you’re interested in getting the book, you can do that at helloworldbook3.com. And if you run into any issues with our macOS installer or any other aspect of our book, please let us know at cp4khelp@gmail.com.