Simpler than having to worry about Python versions, let alone dependencies.
Most of them were so old that I would have had to skip like 3 generations of package managers to get to the one that's used this year (dunno about next year) if I wanted to upgrade or add dependencies.
With Go I can just develop on my own computer, (cross)compile and scp to the destination and it'll keep working.
I'm thinking of trying out Mojo in large part because they say they're aiming for Python compatibility, and they produce single-file executables.
Previous to that I was using PyInstaller but it was always a little fragile (I had to run the build script a couple of times before it would successfully complete).
Currently I'm using pipx and Poetry, which seems pretty good (100% success rate on builds, and when my 5-line build script fails it's because of an actual error on my part).
Which is a round-about way of asking everyone:
Does anyone have any other good way(s) to build single-file executables with Python?
From the website, "D's blazingly fast compilation allows it to be used as a high level, productive scripting language, but with the advantages of static type checking" [3].
[1]Why I use the D programming language for scripting (2021):
https://news.ycombinator.com/item?id=36928485
[2]Adding ANSI C11 C compiler to D so it can import and compile C files directly:
It can do the Python venv stuff behind the scenes for you and it just looks like a single Python file.
[1]: https://nuitka.net/
like deno or bun, but for Ruby
artichoke ruby is the closest we've got
I’ve used rust for this task but people get mad that I’m calling it a “script”. “That’s not a script that’s a program” which…sure. But so maybe we need another term for it? “Production-scripts” or something.
My experience is rewriting Ruby and bash buildpacks for the open spec CNCF Cloud Native Buildpack project (CNB) https://github.com/heroku/buildpacks
I agree that Ruby is easier to start and grow complexity, that would be a good place to start.
Even with a good type system, a trimmer/linker has to be enlightened of many special idioms and patterns and perform flow analysis, and in the case of dynamically typed languages or languages with reflection - to analyze reachability of reflectable members and trim otherwise spaceous metadata. It took significant amount of work in .NET's ILLink in order for it to be able to produce as compact binaries/libraries as it does today with .NET's AOT build target, and it still required a degree of metdata compression and dehydration of pointer-rich data structures (something which, funnily enough, Go doesn't do, resulting in worse binary size).
https://github.com/oracle/truffleruby
Unlike GraalVM Java, as far as I can tell TruffleRuby doesn't provide a bundler that can create a single executable out of everything, but in principle I don't see why it couldn't.
https://www.graalvm.org/latest/reference-manual/python/stand...
I'm not sure I'd try replacing shell scripts with natively compiled Python binaries. That said, I use a Kotlin Scripting based bash replacement in my own work that has many useful features for shell scripting and is generally much more pleasant. You have to "install" it in the sense of having it extracted somewhere, but it runs on Win/Mac/Linux and can be used without root etc.
It works well but with one huge caveat: although you bring the stuff required to reconstitute the venv with you, you’re actually still using the system’s python executable and stdlib!! So for example if you want to make a project targeting all supported Ubuntu LTS versions, you have to include the wheels for every possible python version you might hit.
Ultimately this boils down to there not really being a story for statically compiled python, so in most normal cases you end up wanting a chroot and at that point you’re in a container anyway.
There are other options I didnt look too much into, e.g. Beeware
The way inline script metadata works is that your script declares arbitrary dependencies in a structured top comment, and a compliant script runner must provide them. Here is an example from a real script:
#! /usr/bin/env -S pipx run
# /// script
# dependencies = [
# "click==8.*",
# "Jinja2==3.*",
# "tomli==2.*",
# ]
# requires-python = ">=3.8"
# ///
pipx implements the spec with cached per-script virtual environments.
It will download the dependencies, create a venv for your script, and install the dependencies in the venv the first time you invoke the script.
The idea isn't new: you could do more or less the same with https://github.com/PyAr/fades (2014) and https://github.com/jaraco/pip-run (2015).
However, I only adopted it after I saw https://peps.python.org/pep-0722/, which PEP 723 replaced and became the current standard.
It is nice to have it standardized and part of pipx.For really arbitrary hosts with no guarantee of recent pipx, there is https://pip.wtf and my venv version https://github.com/dbohdan/pip-wtenv. Personally, I'd go with `pipx run` instead whenever possible.
[1] I recommend shiv over PEX for pure-Python dependencies because shiv builds faster. Have a look at https://shiv.readthedocs.io/en/stable/history.html.
I. E. ‘sed -i’ is only in GNU sed. Same with ‘grep -P’.
Otherwise nobody thinks of it because most likely it is not being distributed.
All of those have wildly different behavior depending on their "flavors" (GNU vs Busybox vs BSD) and almost all of them depend on libc being installed.
Other than that, OS scripting is done in traditional UNIX tools, or Powershell.