Announcement: PyApp 0.15.0

PyApp is a wrapper for Python applications that bootstrap themselves at runtime.

GitHub release

Most changes in this release came from contributors :slightly_smiling_face:. One such feature is a brand-new execution mode that allows the binary to run Jupyter notebooks.

Since the last discussion, I’ve also added (among other improvements) a How-to page to help folks get started.


No short description of what this is?

The first line on the README and docs home page has the following:

PyApp is a wrapper for Python applications that bootstrap themselves at runtime.

I ping’ed you to add this becuase a lot of people will not bother to follow the links in an announcemment unless the announced software is possibly useful to them.

Oh I see, thanks! I just added to the top post.


Interesting. Users are always asking for a way to compile or obfuscate their Python code.

How well does it play with binary libraries from PyPi etc. ?

Does PyApp embed the Python interpreter in the binary? And would that be RustPython?

There are two basic ways to solve this problem.

Build a single executable that has a bootstrap for python, the python interpreter and the app code. Typical of Windows .exe solutions.

The other way is to build a app bundle where there are a set of files
gathered together in an OS specific way. For example a macOS .app
is such a solution as would be containerised solutions.

The handling of .dll and .so binary dependencies requires special handling.
One way is to bundle them into the single executable and at run time save the .dll (or .so) to a temporary folder then load from there.
When the app quits delete the temporary files.

Weather this helps with obfuscation is up to the user to decide.
Any sufficiently incentervised person will be able to hack apart any of these solutions and get some version of the source into their hands.

See: Runtime behavior - PyApp

It’s completely compatible with PyPI and other package indices because it uses a real virtual environment on-disk.

That’s great - like pipx but self contained. I really like the self sub command too.

I’d just like to understand the high level architecture of what I would actually be shipping to my users.

To use PyApp have you basically got to use the whole boilerplate and PyApp specific configuration, as opposed to the typical pyproject.toml or setup, and as opposed to however conda and zipapp etc. do it?

I know cargo’s a great build tool. I know it’s certainly one way of solving the frequent bug about installing cryptography sdists. And I know on your machine, or at least in your build env, you need Rust to produce PyApp binaries for use by your users.

But what’s the Rust compiler needed by your users (lets say, myself for example) for, if your users are only writing Python?

Or what value does Rust add - does it integrate with PyO3 and Maturin out of the box, and let you drive MSVC or GCC more easily, to streamline shipping of binaries?

Is the goal of self boot strapping really that hard to achieve for pure Python projects, with a pure Python framework? Is a bootstrapping wrapper really such a blocker, that Rust level performance is desirable?

PyApp does looks great. And I’m not opposed to Rust at all - far from it. It’s just that to my mind, the obvious question PyApp leads to when considering it for a project is, “if it requires Rust itself, then why don’t we just write the whole thing in Rust ourselves, and have visibility of, and even own, all the code we ship to our users?”. Instead of having to study the internals of the PyApp black box for reassurance.

There is no runtime dependence on Rust, you merely ship an executable for a specific target and your user invokes that on the command line. The very first time it happens it will download (or unpack if embedded) the proper pre-built Python distribution, create a virtual environment, and install the project and/or dependencies. All of the runtime behavior is configurable but that is the default behavior.

It’s basically simulating what the user would do themselves without the user having to do it. The distributions are cached based on the hash at build time so if multiple projects that use PyApp use the same distribution then everything after the first run is quite zippy because the distribution is already unpacked on disk somewhere to use for creating virtual environments.