Python is growing incredibly fast, and it's found its place in many facets of the developer and
computational space. One area that is still shaky and uncertain is packaging and shipping software
to users. I'm not talking about building reusable libraries and hosting them on PyPI. I'm talking
about shipping executable software to non-developers. Take a moment and stop and think about the ways
you would send an end-user a program built with Python that they can simply run. It's a bit of a
mixed bag, isn't it? On this episode, we welcome back Christian Medina to run through the state of
Python packaging. This is Talk Python to Me, episode 245, recorded November 21st, 2019.
Welcome to Talk Python to Me, a weekly podcast on Python, the language, the libraries, the
ecosystem, and the personalities. This is your host, Michael Kennedy. Follow me on Twitter,
where I'm @mkennedy. Keep up with the show and listen to past episodes at talkpython.fm,
and follow the show on Twitter via at Talk Python. This episode is brought to you by Tidelift and
Linode. Please check out what they're offering during their segments. It really helps support
the show. Chris, welcome back to Talk Python to Me.
Hey, thanks. How's it going? It's been a while.
It has been a while. It has been since the summer of 2018, so not quite two years, but it's definitely
been a while since you were on. Previously, you were on to talk about continuous integration,
continuous delivery with Python. That's right.
And you know, that was a really popular episode, actually. I thought the topic would be popular,
but you came across with all these little tools and techniques that people just loved. And so,
yeah, it was really great. And we'll probably learn some more about cool tools and techniques
this time around, too.
Yeah, sure. It was a good episode to kind of get everything plugged together and a nice little
summary for all that. So, yeah, anybody that's interested, it's a good one.
So, let's maybe fill people in on what you've been up to lately, day to day.
Sure.
You were on the software development side, but it sounds a little bit like you're also on the testing
and process, making sure stuff works for the folks around you, like that they don't build bad software
as well.
Yeah. So, when we recorded that last episode, yeah, I was mostly doing development side,
but I was in a small team, so I was tied into everything, QA builds and everything. But since then,
I've transitioned to a different organization and I'm mostly doing QA now. So, QA tooling,
which still involves build stuff, but not really developing a product, more developing tools to
help test and release code.
That's cool. So, you're basically in the developer tool space, but internally for your company,
not like JetBrains or Microsoft or something like that.
Right, right. And I've done that in my career a lot. I actually like it because I can walk over
and talk to my customers and tell them, did you like this? And they were like, no, it sucked.
Okay, so I'll go fix it.
That is a super cool feeling. I've worked in small offices where basically the users of the software,
they were a few offices or a little lab space down. And it was like, all right, what we need
for next week is this. Come back three or four days later. This is what I've built. I know you
asked for this, but I think this part can be automated too. What do you think about it?
Like either like, oh, that's amazing or no, what were you doing? Like, of course you can't do that.
And so on and so on. Yeah. It's that quick feedback loop is pretty cool.
Yeah. It just helps you produce something productive for people that'll help their productivity.
Yeah.
Yeah. Yeah. Cool. So, well, that sounds really fun. And, also related a little bit to what
we're going to be talking about now.
Yeah. Slightly. Slightly. Yeah. So I want to start really high level with our conversation.
So the idea is we're going to dig into some of the options for packaging Python applications.
And I think before we even dig into the details of how we do that, some of the cool tools
that are out there, honestly, I think we have to define what the heck that means. And it's not
because we just need to be precise, but I think some different people, they have vastly different
expectations and needs and some tools completely solve that. And if your, your desire is different,
it's completely broken. Like imagine I want to get my web app onto a server to run consistently.
Maybe Docker and Kubernetes is the perfect answer. If I have a accounting application,
I want to give to accountants running a Kubernetes cluster is not the right answer, right? Like these
are really, really different. So maybe what are some of the definitions and like of what packaging
might mean for different people? What's the spectrum out there?
Right. So even in the org I'm in right now, we actually have this problem because we have a wide
range of tools, right? So if you're building a bunch of services with REST APIs to help you
deliver something to that's remote or let's call it cloud-like to people, right? That might,
like you said, that's something you might want to package as a Docker container, as a service running
on a server, which is a different deliverable than say a double click this icon here, desktop application
that you'd want to deliver if you're wanting to say, create a log viewer for somebody to help them
process that information, right? Right.
Which then is completely different from some utility where you just want to provide a quick library
for other people to write more code using your library, right? And all that you'd want to deliverable
for all of that would be different and something that makes more sense to the user in the environment
that they're in because they're all different environments.
Yeah, absolutely. Like I suspect you're kind of on the border at work, right? Because you are working
with developers. So it's probably reasonable to say, well, there's a REST endpoint or there is a command
line tool. You type this in the command line and magic happens.
Right. So the REST endpoint, easy, right? So there's this GUI uses some REST API and you can track your
execution of your tests, for example, right? And then you can see how things are going. But when you're talking
about the actual test you wrote, then that needs a library for you to access the infrastructure
and a bunch of services in that infrastructure that might relate to just stuff you need, requesting
resources for testing or using other, you know, integrating with other tooling that will help you
with that, right? Which is then completely different from some utility that'll tell me, give me the list
all my compute that I have available to run tests on, right? Yeah. And then that utility needs to run
on every developer's machine. And then how you distribute that starts getting complicated.
Yeah. And do you help these developers that you're working with? Do you help them
distribute their tools, maybe to more end user type folks?
Not so much. Some of the libraries that the organization runs are or might soon be open
sourced. So we might wind up using IPI and GitHub to distribute some of that stuff. Internally,
we have like internal private IPI repos and Docker registries and things like that today.
Okay. Yeah. Yeah. Very cool. All right. Now I'm going to throw out as part of this high level
discussion, an idea. I don't know if it's popular or not. It's not super positive, but I do want to kind
of start there because I think this is a pretty serious issue. And I'm going to say that Python's
in this broad sense that we've set it up, not necessarily like virtual environments and like
pip install, but in the broad sense, Python's packaging of for applications in particular,
it's fairly broken. How does that say with you?
There's definitely a number of areas that need improvement, mostly because of the part of the
problem is that we just have so many different ways of distributing say virtual environments or
just the packages themselves or just putting the code together and giving it out to somebody.
And part of it is good because just Python is flexible enough for you for allowing you to
build whatever makes sense for your org, right? And then everybody puts it out there and then some
people use it, some people don't. But if we had the one official supported thing that goes beyond
just pip install because pip install involves a pre-existing Python executable, which is when
things start getting complicated.
Exactly. You've got to have a well-known, somewhat decent environment. You've got to have a certain
version of Python or a range of version. It's got to be over 3.5 or say over 3.6 if you're using
f-strings or whatever version it has to be. That has to all be in place and set up.
Even when that works, it's usually difficult to give somebody an icon to double click to make their
app go, right? Like, why is my thing not like Firefox? Well, you see, there's all these rules. Let me tell
you about dependencies. Nobody wants to hear that, right? They want to go, I want the icon that I click.
Yeah. It gets even more complicated once you're distributing compiled code along with it, like some
of the machine learning stuff or whatnot, which is why you see all these alternative systems like,
say, Anaconda exists to just help with that, right?
Right. Yeah, yeah. That's a good point. That is sort of why Anaconda exists. I mean, it also focused a
little more on the developer side, but right, it kind of tries to solve some of the challenges of how do I
get some of the foundational bits in place for the developer users, right? Yep. So there was, here's a
quote from the PyOxidizer page. So Greg, I believe, is on board with this idea. And this is from Russell
Keith McGee's PyCon 2019 keynote talk. So he's on idea. He's on board with this idea. But he gave a talk
basically about these black swan events for Python. Are you familiar with this idea? Did you see his talk?
Yep. And it was discussed in a couple episodes. I think you guys talked about it probably in a Python
bytes episode before as well. Yeah, I do think we might have done that. Yeah. Yeah. So the idea of the
black swan event roughly is like this thing that is very rare that people don't see coming in an
ecosystem and society and cycles, whatever, that are potentially existentially critically bad,
right? So the original example was something like a turkey thinks the farmer loves them. Every day,
the farmer comes in and greets them, treats them really well. Feeds them. Yeah, feeds them. And nobody saw
Thanksgiving coming, right? Something like that or, you know, things along those lines. I guess maybe
another one might be traditional photography and Kodak and digital cameras, right? Like that might like
nobody saw that coming in the sense, like well enough, I guess. I'll give you one more with server
development and the commoditization of that and what happened with the larger manufacturers when
all the cloud companies started to develop their own servers. Yeah, probably first they're like,
you know what? It's no big deal that there's all these cloud hosting places because they're just
going to buy our servers and put them in their data centers and we'll be fine until they said,
you know what? We could do better on efficiency and our biggest cost is electricity. So thanks,
but no thanks. Yeah, exactly. Yeah. Yeah. So Russell Keith McGee said there are a couple of things that he
believes are these black swan type of threats for different parts of Python, right? He loves Python,
but like what might undo this great success that Python has had over the last couple of years and
one of them is definitely about packaging. Yeah. Look, I believe some of the others, there was mobile,
there was packaging and there was a few others, but those are the two that really stood out to me.
It was like, you know, people who are coming into programming,
why would they come into Python if they can't take the cool little app they built and share it with
their friends, right? They're going to do it in JavaScript or they're going to do it in something
else where they can package it up and share their game or whatever, right? Exactly. Yeah. So that's
why I think this is a big challenge, right? I think it's important. It's also tricky, but I think it's,
I do think it's really important. Also, you probably heard me go on and on about like building GUIs in
Python, right? Like this is another, another one. And I've done my GUI thing too. So yeah. Yes,
you have. That's right. You gave a talk at PyCaribbean about it. That's cool. And
I think one of the reasons people don't build more desktop applications and GUI applications in Python
is because one, yeah, there's a, there's a little bit of a gap in the tooling there, but things like
cute and what, whatnot, they're actually quite decent. Cocoa touch and not Cocoa touch, but some of the
PI OBJC or whatever, the wrappers around the Cocoa APIs, those are probably pretty much okay. But
even once you build those, then you come back to this packaging problem that we're talking about here.
I think it's, it's so much of a problem that people don't put any energy to build out the GUI apps,
the GUI capabilities, because heck, once you build them, it's, you still can't really give them to
anybody in like a super decent way. So why, why bother building, like, you're just going to build a web
app or, or whatever. I think there's a bit of a chicken and egg problem where like people don't work on
trying to distribute their application because it's so hard to build the type of applications that get
distributed. So like, it's just kind of like, it's a little anemic in that space. So what I'm trying to
say.
No, no, I'm with you. And, and even, so when I said like, I did my GUI thing. And so I have my attempt
at a GUI framework where I, I went through the analysis or what you're just talking about. And I
just pretty much just gave up and said, well, the web one, we can just make our GUIs in the web.
Let's figure out how to do that a little bit easier and just go down the Chromium distribution
kind of electron JS equivalent to do everything. And then everybody just gets a web browser,
which is cool that that works. But then when you start thinking about the, what else you're
distributing with your application, just to do a simple GUI or whatever, like an entire web browser
or whatnot, then just seems kind of wasteful as well. Yeah.
Yeah. Yeah. I do think actually that might be something that happens for Python, something
like electron, right? That's actually really totally possible. And the WebAssembly stuff
could make that really interesting as well. If you could package up the runtime as a web
assembly and just drop that with your, your electron distribution.
I managed to do it. It works. I'm not using electron itself. I'm just using the stuff that
electron uses in the backend. So it's all totally possible.
This portion of Talk Python to Me is brought to you by Tidelift. Tidelift is the first managed
open source subscription, giving you commercial support and maintenance for the open source
dependencies you use to build your applications. And with Tidelift, you not only get more dependable
software, but you pay the maintainers of the exact packages you're using, which means your
software will keep getting better. The Tidelift subscription covers millions of open source projects
across Python, JavaScript, Java, PHP, Ruby, .NET, and more. And the subscription includes
security updates, licensing, verification, and indemnification, maintenance and code improvements,
package selection and version guidance, roadmap input, and tooling and cloud integration.
The bottom line is you get the capabilities you'd expect and require from commercial software.
But now for all the key open source software you depend upon, just visit talkpython.fm
slash Tidelift to get started today.
All of this conversation sort of started from this, it's almost like a retrospective on a journey
that you went on. This blog post that you wrote, four attempts at packaging Python as an executable.
I'll put the link for that original article over there. So maybe just tell us a little bit about
what that was all about in the journey and then we can dive into some of the details that we pulled
out of there. Sure. So in the, even in the previous episode, when I was working on mostly CICD stuff,
as part of that CICD system, there's a, you know, you need to execute some code inside it to like keep
your process going. Right. And one of the limitations I had at the time was that the containers that I was
using required Python to be installed in it. And I wanted to remove that dependency. I knew it was
possible to compile my code down to an executable. I wanted to figure out what, what method worked for
me. And I tried, I didn't have a lot of time. So I tried four systems, which at the time was
Cython, PyInstaller, Nutka and PyOxidizer. Right. And each one had, you know, I fumbled through most of
them and, and, you know, I'd use PyInstaller before. For simple cases, you could get it to work,
right? Like Cython, you sort of got it to work, but only for a simple app. Yeah, exactly.
I got what I wanted. It works pretty well. It's been in production for my side of the world for a
while. So I'm, I'm happy with it. But yeah, so out of that came, you know, this analysis of where we're
at with like how to turn your Python script into a double click executable kind of thing.
Yeah. And I definitely think it depends on what level you need to be at, right? If you're building
a tool for fellow developers, that's one thing. If you're building a tool, like I said, for accountants
or lawyers, exactly. They expect something to put next to their word icon in their macOS doc or
whatever, like that's a different type of thing. Right. So let's go through it. I guess we've got
it broken up into some, some nice taxonomy here. Let's talk about delivering an application first.
Yeah, sure. So just to give the overall taxonomy a little bit, right? We have three things based on
what deliverable, what your end goal is from having this Python package, this distribution to your end
user, right? And we have the idea of putting it together as an application that you run or putting
it together where you just distribute a virtual environment with it, or you just give out a specific
executable. And then there's some other things along with it that we talk about later. But if you want
to deliver an application or a service type of application, one of the best things to use these
days is Docker. I've used it successfully to run pretty much everything Python related. And in fact,
there's an official Docker image that you can run that's based on Debian, I believe. And I use that in
my automated testing all the time.
That's supported by the PSF. I've learned, right? That's pretty interesting.
Somewhere in the Python builder, a little bit after that comes an official Python Docker image
that you can just pull from and use.
Yeah, that's cool. Docker is cool. But it makes me a little bit nervous because you're taking like
layers of customized operating system that maybe different people have, you know, changed or built
on stuff. And then, you know, how sure are you that those are not, you know, that somebody hasn't
slipped something in there. I think the Docker files are maybe a safer bet, of course, right?
To just like build it yourself rather than to download the full container.
But you still need to start from an image, right?
Yeah.
So if you start from, say, some official distribution of something like the Python one,
but just the same, there's like all kinds of other images from Postgres, Ubuntu, MySQL,
whatever that you can use. You can, you know, slowly build up with your Docker file,
whatever dependencies it is that you need.
Now, the advantage of this is that you're distributing all the dependencies for your
operating system along with the Python executable that you need along with your actual application,
right?
Yeah.
That makes the, it worked on my machine problem go away, essentially.
I do think Docker is a pretty cool solution. If having Docker running on your operating system,
it's not a big deal to you, right? You've already got the desktop Docker or whatever.
Or it's installed on your server.
Right.
Then this is a pretty solid way, certainly to deliver like services and stuff.
If it's just a matter of pulling it down and say, you know, Docker run this container or whatever,
then it's, it's okay.
Yeah. I've also come across a couple of applications, I would call them that where you,
you run a CLI and the, your interface is the CLI, but in the backend of CLI,
Docker runs something for you. So it all runs in its own little contained environment.
And then just exits.
Yeah. One of the slicker instances of this was from Gigantum. Are you familiar with them? They're pretty new.
Nope.
So I just had them on the show three or four episodes ago, not very long ago.
Okay.
And basically what they are is they are like a collaboration environment for data science.
So they distribute their application to you as a Docker container. And then each environment you create starts from one of these containers as well.
So either it's like an Anaconda pre-configured container or it's a, you know, just a bare one with Python or whatnot.
But yeah, it's really cool that the PS has enough PSF has an official Docker container. Cause I didn't, I didn't realize it. That's great.
Yeah. Yeah. It really does help it along.
Yeah. The other thing that can be tricky with Docker is you're trading that,
well now set up this version of Python in this way for now make sure you expose these ports and the right way.
And you map that volume over there. There's just like, there's still some friction to distribute and stuff as a Docker container, right?
Yes, that's correct. So if once your application, if you get like something that's really somewhat complicated and you need to have persistent data and things like that,
then you got to worry about making the proper volumes or mapping the correct directories into it so that you can persist the data outside the container or even access it without having to get into the container.
And then when you have to do things like when you depend on networking in some way, like if say you're running HTTP server, then you need to make sure you pass in the right commands to open the correct ports for it to work for you.
So that's some of the complications you get there.
But it could get wrapped up, right? Like you don't, the example you pointed out where you don't really know that you're doing Docker when you're working with your CLI.
It just happens to Docker behind the scenes to make things reliable. Like that's a pretty good use case.
Yeah, I think so.
Cool. All right. So another one that you have out there, which is maybe pre-Docker.
Yes.
I'm just going to give you a virtual machine and you can just run that.
Yep. And along with that. And so like the original thing was, yeah, here's your virtual machine application, essentially.
And you just, it starts an entire operating system that you can run in VirtualBox, but along as well as other virtual machine environments.
But along with that came Vagrant, which was kind of like a Docker file for virtual machines, except before Docker files.
And so you can sit there and say, oh, it's a VM. It's going to have this configuration for your network, for memory, CPU, whatever, file systems and whatnot.
And spins up essentially a pre-configured OS, fully packaged OS for you.
And now, of course, when you distribute a VM, you're distributing a whole OS.
So it's going to be a large image that you're giving out, which is the difference with something like Docker, because it's a layered file system.
Then you only need to, you only distribute the pieces that you're adding on top of some basic image.
Any changes you make to that virtual machine maybe requires like a new 5 gig download, whereas a change or two Docker file might just, well, you just rebuild like the last layer of that Docker image.
Yeah. And then you can find, like for the Docker side, you can find, you know, tiny OS images in the tens of megs versus a full VM, right?
That'll be like probably a couple of gigs. You can get small VMs too.
Yeah, a couple of gigs to start. Yeah, yeah, true.
The other thing that seems like a challenge with the VM option is it's now your puppy.
You've got to caretake it, right? So if it has a security vulnerability or something like that, then you've got to go in there and like patch it and whatnot.
Right. Which you technically still have to do with Docker.
But if you spin off your image on top of an existing one, for example, let's go back to the Python thing.
If I have my application built on Python 3.6 and 3.7 comes out, I just need to change my base image to 3.7 and stuff just starts working on top of that.
Right. Or you could just live a little bit out on the edge and do something like Ubuntu Python colon latest.
Right. Exactly.
Something like, right. Whatever's the latest. If there happens to be a new latest when I rebuild it, get the new latest and then give me that.
That one's probably patched at the OS level and got the newer version of whatever in it.
Right. Exactly.
There's a risk that it's not 100% repeatable potentially, but things like Linux and Python, they're pretty backwards compatible.
Yep.
As opposed to I now have to log into my Docker images and patch them. That's another level of effort.
Yeah, exactly. That's a lot more complicated.
Usually, it's just considerably easier to just update the base image.
Right, right, right.
It's also a great little test thing, right? If you want to check whether your code works in 3.7 versus 3.5, for example, just start an image with 3.7 in it and you're done.
Yeah, and run it through your CI and see what happens.
Yep.
Another thing that might be a benefit of the Vagrant VM style, though, could be background work, background jobs and whatnot.
Like, Docker, typically, it has the Docker container, but then there's, like, the one thing it runs as its life, right?
Like, there's not a system D in Docker that I'm aware of and things like that, right?
Right. Depending on what you want to do, right?
Because you can configure it to do whatever, pretty much.
And there's, like, privileged containers, too, right?
So, you got some limitations on your normal stuff, but you can also add other kernel privileges to it to help it communicate or create new devices and whatnot.
And, yes, the process manager and service managers inside the container aren't there by default.
So, if you want to do that, you get to configure it yourself.
Right.
Right, which is complicated, but it can be complicated, but it's also good because you get, like, a really base thing.
So, if you don't need it, you don't have it.
Yeah.
One of the things that's cool about that, though, is you have all the control, right?
That's correct.
Once you set it up, it might be painful to set it up, create that Docker file that's just right, but once you got it, like, you put it in version control and you just forget about it, right?
You just build on top of it.
Yeah, exactly.
Yeah.
And you can have, like, a build container, for example, in version control just exists to build your code, for example, or package your code.
Yeah.
And then just gets destroyed afterwards.
Yeah.
So, we've got these different container technologies, like, really big shipping container style, and then, like, the small, I don't know, Tupperware style with Docker and VMs.
Right.
But we also have, you know, things like PyInstaller, right?
Yep.
So, with PyInstaller, it has been around for a while.
That's what I used to distribute the GUI stuff we were just talking about earlier.
So, PyInstaller can take your Python application, like you pointed to your directory, and it can output fully installable application in both Linux, Windows, and Mac.
So, in Mac, you'll get a .app, you know, in Windows, you'll get an executable, and for Linux, you'll get another executable file.
I used it recently to do something simpler, which is what I discussed in my recent article, but I used it in the past to not only write a Python app that ran, say, a WebSocket server in it, right?
It also included an entire Chromium browser along with it and got delivered almost like an Electron application.
Yeah, that's super cool.
Yeah.
I do think PyInstaller is quite nice.
It's been around for a while, but it seems to be, like, one of the go-tos that people are keeping around.
Yeah.
So, actually, after I wrote my post, I got a number of folks that pinged me when, like, talking about how great PyInstaller is, and they've been using it for a while.
Yeah, yeah, super cool.
This is pretty close to here's your executable you can have and run.
Yeah, just double-click and go.
Yeah, I've had pretty good success for it.
I used GUI, you know, GUI, G-O-O-E-Y.
Yep.
I used GUI to build a little app, which was a super simple thing, and then I packaged it up with PyInstaller.
And it was good except for it ran fine on Windows.
Like, it had a .exe.
It, like, had an icon.
You double-clicked it.
It did the thing.
On macOS, I had a .app file.
Mm-hmm.
And you double-clicked it and did its thing, except for it also opened a terminal kind of off to the side.
Oh, really?
Which, for the life of me, I couldn't get it to go away.
Like, the commands to make the terminal not show were obviously working on Windows, but not on Mac.
And I was like, ah, it's so close to working.
Oh, that's interesting.
Yeah, yeah, yeah.
So, I still think there's some rough edges, but it definitely seems...
Like, the other stuff I tried didn't get that far, right?
So, that was cool.
Yeah, so I haven't had that experience.
But I have had complications, because when you package your application, now you have to worry about things that depend on some of the Dunder methods to come in with Python, like the Dunder file stuff.
Which is supposed to tell you the directory in which the file that you're working on is located.
Right.
Well, that's kind of different, because the way PyInstaller works is it bundles your application, all the files, and whatever extra data you want with it, and it bundles a Python interpreter in it.
So, when it runs, it just extracts all this stuff into some internal directory that you're not aware of.
So, Dunder file just doesn't work.
It gives you anything.
I can't remember.
It's wrong, right?
So, but PyInstaller provides its own little API to get the actual directory where the files actually exist.
So, you just got to be aware.
You do a check in your Python code to say, oh, we're inside PyInstaller, so we need to check here and go here instead.
Okay, that's interesting.
Yep.
Can you use the Dunder file to still get, like, I need to go up one folder and get that other file next to it, or is it even relative stuff is not really working?
Even relative stuff is not quite set up right.
Okay, but if you build for it, it's not a big deal, it sounds like.
Yeah.
And then another option is, I mentioned Russell Keith McGee.
Right.
And his big project is the whole Beware project.
And one of those is about packaging, right?
Yeah, briefcase.
And so, you know, Beware is a whole slew of individual repositories that provide different functions, specifically a way to, together, they provide a way to build cross-platform Python applications, which involve GUIs in mobile devices, as well as your desktop app or the web.
And as part of that, they need a way to package the application.
And so they built a briefcase, which is the repo that lets them do that.
And so you can take, essentially, write a base app and using briefcase, produce, you know, an Android application and iOS application and everything else.
I haven't particularly used it to do anything major.
So I don't know a lot about the internal details, but I know it's there and people are working with it.
Yeah, certainly it's pretty interesting that it has iOS and Android.
Yeah.
And I have seen the apps work.
And, you know, Russell's done several talks on how that all does all this stuff.
It's actually pretty neat, all the things that they're doing.
Some of the Android stuff, last I checked, was transpiling some of the Python code.
Some of the iOS stuff was directly calling into Objective-C, a few things.
So it's pretty neat.
Yeah.
So that is some subset of the options for delivering an application, right?
Like, I want to have the whole environment come along and whatever that takes, if that's a VM or bundling stuff up like Chrome or whatever you need, do that.
Maybe another level is delivering a virtual environment, right?
This sounds like it's most useful kind of for developer and automation and server type stuff.
Great.
So say you have an organization or customers that you know are on a set Python interpreter.
So you don't need to bundle your Python interpreter with you.
Then you can use some of these tools to bundle your application along with all of its dependencies into one file.
So the ones I'm talking about here are PEX, for example, which was built by the folks at Twitter and SHIV, which was built by the folks at LinkedIn based on the PEX stuff.
And the idea is they take all your code and they bundle it into one file and you can feed that file into Python and it follows a, I forget, I should have made note of that.
There's a PEP that explains how to build these zip apps.
PEP 441.
There you go.
Python zip applications.
Yeah.
Right.
And so then with one command, you can just feed that into your Python interpreter and it knows how to unpack it and run all the stuff in it.
Nice.
And does PEX and SHIV, do these package up the dependencies?
Yes.
Like if I depend upon HTTPX or requests or Sook Alchemy, it'll take it with it?
It'll do it.
Yeah.
That's pretty cool.
But typically the virtual environments, at least on the Unix, Linux, macOS systems, are like symlinks back to the real Python, right?
They're not full copies of Python.
Right.
Yeah.
So is that kind of how it works?
It's like, here's a little virtual environment shell and just link back to the main Python and then run?
Right.
So you'll be using whatever the Python it is.
And I haven't done this, but I imagine you could make a virtual env with your Python interpreter that you want to use.
And then in that virtual env run your PECS or your SHIV package code.
Yeah.
I would think so as well.
Yeah.
So you still, basically the idea is you still got to have Python bare bones as a thing, the version that you need as a thing.
There to bootstrap.
But once you have that, at least you don't have to say, first step is create the virtual environment.
Second step is pip install dash are the requirements.
Like you can skip all of that.
Long as Python is present, you can basically run it potentially.
That's correct.
Yeah.
Okay.
Yeah.
That looks really cool.
When I first saw that, I was like, oh, please let this package up the Python runtime with it.
And no, you're right.
It just builds on top of that PEP 441 to say, basically you can create these zip versions that are directly executable by Python.
That's it.
Yeah.
So if you have like a, in a large organization, sometimes you have a standard virtual developer, virtual machine or developer laptop or desktop stuff that you distribute to everybody.
And if you have the stuff in place, which not everybody does to automatically keep that up to date with say whatever Python interpreter it is that you're running, then you can make a safe assumption that your customers, your users are all going to have this Python environment and just go from there.
Yeah.
It definitely seems like an interesting way to ship stuff to a server.
Right.
Instead of creating the environments and setting them up there and installing the packages, just like, I'm going to take this zipped up virtual environment, send it over there and say run.
It's not quite Docker works on my machine level, but it's closer.
Right.
So other things you'd have to think about at sites from the interpreter would be any other like external dependencies of your package.
Those will probably not get zipped up with it.
I think there's some options to help that along on both of them, but I'm, I don't know all the details with that specifically.
Right.
But maybe you need Redis on the machine and like, that's not a Python thing.
Or you need lib MySQL.
I see.
Yeah.
Or something like that.
I'll throw one more into this part of the taxonomy delivering as a virtual environment.
PIPX.
Are you familiar with PIPX?
I am.
I use it a little bit.
Yeah.
I haven't done much else after initial config.
Yeah.
So PIPX is interesting because PIPX, if you have Python on your machine and you pip install PIPX, from then on, you can do basically the way things like homebrew or chocolatey work for installing like utilities into your, your OS.
If those utilities are based on Python, PIPX serves the same role as say homebrew.
Right.
So I can go, and if I pip install --user PIPX, from then on, I now have a PIPX command.
And I could say like PIPX install glances.
And glances is like a cool terminal sort of process explorer type thing with, you know, ASCII bar graphs and whatnot.
Right.
So if I wanted that, I could say PIPX install glances and we'll create a dedicated virtual environment just to run and install glances.
And if then, if I want HTTPY, which is a cool alternative to curl, that's Python basic, I say PIPX install HTTPY and it'll actually go and create a dedicated isolated environment for that command line tool.
So if you've got a command line option that you want to, a command line tool that is Python based and you want to be able to have it upgrade itself because you can say PIPX upgrade all and stuff like that.
And it's isolated.
It's not being installed in one of your projects.
It's just something you want on your machine.
PIPX is actually a pretty cool option.
Yeah.
Like I would use it for, I would even use it for something like a linter or a, you know, install flacate.
And then you can use, when you type flacate anywhere, it'll just run your PIPX frozen essentially.
environment for that.
Yeah.
That is pretty cool.
And then along with that, if you want to create a package that fits into that world, I want to create a package that I'm going to create as a tool for somebody.
Then you can create an entry point in your package, right?
Which is a thing you can do in your, I think in the setup PY, where you put it.
Yep.
And you say, here's the command and here's the entry point.
And like, here's actually what that means in terms of my package, right?
Like black or whatever.
Right.
Yep.
So you can set those up.
And then if you install them with PIPX, now you're managing that almost as a separate command line set of APIs.
Right.
That could automatically be updated.
Obviously you can install them with PEP elsewhere, but PIPX is cool because it's isolated and automatically, well, upon request will automatically upgrade stuff for you.
Yeah, no, that's another cool utility.
This portion of Talk Python to Me is brought to you by Linode.
Whether you're working on a personal project or managing your enterprise's infrastructure, Linode has the pricing, support, and scale that you need to take your project to the next level.
With 11 data centers worldwide, Linode delivers the performance that you expect at a price that you don't.
Get started on Linode today with a $20 credit and you get access to native SSD storage, a 40 gigabit network, industry-leading processors, their revamped cloud manager at cloud.linode.com, root access to your server, along with their newest API and a Python CLI.
Just visit talkpython.com.com when creating a new Linode account and you'll automatically get $20 credit for your next project.
Oh, and one last thing.
They're hiring.
Go to linode.com slash careers to find out more.
Let them know that we sent you.
All right.
And then the third part of our trifecta, three or four, something like that, is basically what I started with.
I want an icon next to Firefox and Word in my doc.
I click it and I want to see it run and do its thing.
Right?
Like that type of thing.
Take us through what our options are here.
Great.
So we already kind of discussed PyInstaller and that's the best one for the icon, double click and go.
Yeah, it works for all the operating systems, right?
It works for macOS and Windows and Linux.
But don't you need those systems in place to build the deliverables?
That's correct.
Right?
Like if I just have Windows, I'm in trouble because I don't have a Mac to build my Mac version.
Right.
In fact, to the point where I even considered it would be interesting to set up some online stuff that creates PyInstaller packages for you
that just somebody that's essentially renting out the Windows or the Macs for doing it.
Right?
Yeah.
That would actually be a really cool service.
It's like, here's my Python application.
Here's its icon.
Here's what I wanted to just make that for all the operating systems and give it back to me as like an MSI installer on Windows,
a .app on a Mac and a Linux binary or something like that.
Right?
That would be a super cool project.
And yeah.
So PyInstaller gives you that.
And, you know, we mentioned it earlier.
And you can also get just a package application without all the extra pretty stuff along with it.
But the one that makes it the most pretty so far for me has been PyInstaller.
Yeah.
Now the next contender.
So actually, before I go with that, let's just talk about Newtka a little bit.
So that package has been around for a while.
And so PyInstaller produces and packages all of your stuff together for you.
It doesn't compile it for you.
Right?
Okay.
Yeah.
It just takes Python along with it.
And then it like drops your files out and then like runs those.
It doesn't fundamentally change what's happening.
That's right.
It just delivers the two pieces and it clicks them together and says go.
Like CPython already.
Yeah.
Right.
If you want to actually compile it and get some extra speed boosts out of having an actual compiled C code instead of an interpreted language,
then you can use something like Newtka, which actually produces the one file.
You can just .slash run or double click and get it to run your stuff.
Right?
Now there's, of course, since you're compiling it, things get a little bit more complicated and you have to start thinking about having compilers,
having the correct libraries in order to do all of that and the dependencies of those libraries.
So it's slightly harder to do it.
But you'll get in the end code that doesn't, you know, when you run your application in PyInstaller, you're extracting the application and then running it.
But if you run it on something like Newtka, you don't need to extract it.
It's just the one file that just runs.
Right.
It's converted to machine instructions that just do its thing.
That's correct.
Yeah.
So that sounds actually like an incredibly good option.
Right?
It's got to run pretty fast.
It sounds like it's nice and independent.
That's great.
But what if I depend on other complex things?
Like I'm using NumPy or I'm using SeqAlchemy, which has its own compiled bits or something like that.
So if you're using something like NumPy, then you're not going to get a lot of speed boosts out of it.
Right?
Right.
Because you're already running at C.
Is it going to take NumPy along with it?
Like, can it handle like dependencies of this type?
Do you know?
Pretty sure it can.
I haven't had to do it myself.
Yeah.
I've not tried either.
Yeah.
I mean, if it could, that would be pretty cool, actually.
Yeah.
All right.
Want to talk about the new kid on the block?
The new kid on the block is PyOxidizer, which has come up a few times this year already.
Clever name.
Yep.
It's built on the packaging tools that the Rust programming language brought with it.
And so it can produce executables for you.
It still bundles things as well.
The difference is that instead of extracting them into the file system like PyInstaller does,
it extracts it into memory.
So you'll get a faster startup time when, and all your library loads are going to happen
straight off of memory because it's all mapped in there.
That sounds really good.
I know that you tried this on your example in the article that you wrote and you didn't
go with this.
That's correct.
Like, if I had to just guess, close my eyes and say, all right, I don't really know too
much, but I'm going to guess, I would, I would actually guess PyOxidizer might be the
place to start because it's a little fresher, but what was the challenge there?
So there's just a couple of different things similar to the PyInstaller stuff.
Dunder file doesn't work.
So you got to configure a few things.
And in this case, it's a slightly more complicated because it's not like it's a different directory
because there's no directories in memory.
In memory.
Yeah.
Right.
But they have like very extensive documentation on how to get past it.
And so that, that was like my biggest holdup, which at the time to me just kind of felt like,
I need to think about it a little more.
So I just put it on the side as a come back to this later.
But the thing I really liked about it was it's like the config options you have for the, for what
you can, the output that you can get out of it are really neat.
And so you can get an executable that runs a function inside a module, or it just runs file,
works as if you were running your file from the CLI, your Python file from the CLI.
Or you can get, which is what I like because I can play with, you run it and it just starts
your Python interpreter, your REPL with your entire virtual environment along there available.
So you just say, create my REST API application, a client application, and I can just run client,
not that PI because it's compiled, right?
And well, it's an executable and I'll get a Python REPL with, you know, requests already
available for me to import it.
And I don't have to pip install anything.
That's cool.
So in that sense, it's slight.
And I think you can do that with pecs and shiv as well.
There's a way of doing that.
But this was really neat.
You have a lot of control over it and you can watch it, pull in all the dependencies.
You can have it, it'll pip install everything for you into this, this kind of directory structure
when it's trying to put itself together.
And so it grabs all the dependencies fresh out of PI PI or whatever indexes you feed it and
then creates your final environment from that.
It sounds pretty promising.
It seems like it's got a nice modern take.
I like the making your code run faster.
It's already in memory.
Yeah.
It's all pretty cool.
This one does all the OSs as well, right?
Yes.
Cool.
As I'm sitting here listening to talk about all this stuff, it seems to me like one of
the big challenges is how do I get Python to come over correctly?
How do I get the dependencies to come over correctly?
Sometimes it's a little bit tricky to get the program to actually start.
You know, it seems like there's some challenges on around some of the platform stuff.
What I don't see with any of these is what do you think the viability of saying like you
can take CPython and embed it into any application, right?
Yeah.
Like you can host CPython.
What if you created an app that is just a C-based app that obviously runs, no problem.
It already has Python compiled into it.
And its job is to unravel the virtual environment and run your code alongside.
So you're just shipping this, your EXE that already comes with Python and like it already
knows how to run totally reliably.
It's just a matter of executing your Python code as part of its like internal automation
or whatever.
Yeah.
So I haven't done too much work into all of that, but I think it's things like PyOxidizer
will help with that or even something that the ones that do the compilation for you, if
you're trying to deliver an executable like Nutca or even Cython, it can help you along
those lines.
Okay.
Interesting.
All right.
Yeah.
So you mentioned Cython, that one in your article sounded like I'm a fan of Cython.
I've used it for a couple of things.
It's really cool that it supports the Python type hints.
Now it doesn't have its own like type language necessarily.
It still has it, but it used to be, you'd have to describe your types in the Cython way.
Now, if you just describe them in the CPython way, Cython goes along with that, which is really
cool.
That means you can write kind of just annotated Python in the traditional sense or the normal
sense and you get compiled machine instruction type stuff.
That's pretty awesome.
But it's not really built for packaging, is it?
The end goal of Cython was really to integrate C and Python essentially so that you can go
into C code and use Python libraries from it, or you can go into, which is the more common
part, go into Python code and use a C library inside Python code, like say NumPy or something
like that.
Yeah.
Something beyond just C types and some of the base stuff that Python already has.
But it'll compile your Python code for you.
And it has an option to produce a single file executable.
It just isn't going to do a lot of like, for example, if you do it with Nuka, it'll traverse
all of your dependencies and compile and put them together.
But Cython will only do a little bit of that.
It won't traverse dependencies.
Right.
It probably expects like, you're going to compile these three files and then put them together
or something.
Right.
And you just want to give it a Python application and say, put these pieces together for me.
And it's just, it's not really for that, is it?
Yeah.
It's not really built for that.
But it's one of the things I tried.
Yeah.
Sure.
And it, you know, it does get you C code, which is, and you can compile.
And yeah, it's, it's a possibility, but it's, yeah, it just seems like it's abusing Cython
because you, because you could probably make it work, but it's not like it's goal, right?
Like PyOxidizer doesn't have another purpose other than to package up your thing.
And so it's kind of what it's for.
Yep.
Then two of the things that didn't fit in the taxonomy were Flatpak and Snapcraft, both
of which are ways to package up an application.
It's for Linux.
Is it?
And specifically Linux.
Yeah.
Linux.
And, and, but what's cool is they, they both have like their own little app store.
It's kind of like the macOS app store or the Windows 10 app store, but it's the Snapcraft
or Flat, Flat, Flatpak app store.
Yes.
It's more like apt or yum, like its own little package manager type thing.
And it, it packages everything together with you, Flatpak.
I don't have a lot of, it's been a while since I've gone into all the details of how
Flatpak did its, its thing.
And I think it even included some, some OS stuff when it did all its packaging.
So you run in a completely isolated environment, your application and Snapcraft does something
similar.
And on top of it, it's an app store.
So type experience.
So if you push an update, it'll, if you enable it, it'll automatically update your application
for you.
Yeah.
I think that's actually pretty cool.
Yeah.
I think that's neat.
There's actually a lot, actually a lot of use cases for that, even in, in large organizations,
beyond just, typical customer stuff.
Like if you're talking about developers, if you have a bunch of developer tools and
you just produce some new Python package with these tools in it, then you got to go ask all
the developers to go pip install --upgrade.
Right.
Yeah.
But if you do, if you have something like this and everybody's on Linux, which may or may not
be true, then you can just push the update out to the developers.
And since I'm on that, that just reminded me, there's another system, which isn't a packaging
system, but it's a distribution system called pulp that works a little bit like artifactory.
If you're aware of that, which is essentially a package distribution system.
Uh, it will do like a private PI PI server.
Yeah.
But yeah, it covers like all the different types and languages.
Yeah.
Docker registries and all that.
But pulp has agents that you can install on your systems and push updates to them.
Oh, I see.
And then like, Hey, run this script to make sure everybody's got like the newest engine
X or the newest whatever.
Right.
Yep.
Okay.
That's pretty cool.
I definitely like the auto update.
Now you should be able to a very strong should not necessarily could, but should, if you could
get high oxidizer or PI installer to truly work correctly, you should be able to take that
output and put it in the macOS app store or in the windows 10 app store.
I think so.
Yes.
Right.
And then you get the benefits of doing that.
Those app stores always have weird restrictions.
Yeah.
I know one of the worst parts of my mobile app.
I know you had your experiences.
Yeah.
Oh man.
I'm still, I don't want to go into it, but I'm still having, let's call them disagreements
at very strong levels with some of the app stores, right?
Like just some of them were completely weird and out of place.
Other are just, I don't know.
They're just, no, you have to change your app to be like this for no particular reason.
But they're very frustrating.
But if it works, it's actually a great experience for the user.
Right.
When I install an app on my Mac, if it has a version in the app store or I could buy it
separately, I get it in the app store because then I know it's going to be just be on all
my machines.
Yeah.
I don't have to worry about what happens if I lose the license code or I've activated it
twice, but that one machine actually died.
So I'm not actually using it, but I can't deactivate it because it's actually dead.
Like, you know, like how often have you been through this experience of like, you've over,
you've used up your five activations.
It's like, well, but the machines were virtual machines and I threw them away.
I can't unactivate them.
I don't know what you want from me, you know?
So the app stores are good in that regard.
They are.
And you can also have the experience of, well, I have all the, all of these devices that are
registered on my app store and I want to install this application.
Please install it on all of them for me.
Right.
Yeah.
Because the system's already built with the permissions to do that.
Then you're set.
Yep.
Absolutely.
Well, I think these are all really good options and I think it's most important to break it
into that taxonomy.
Like first, what are you even trying to do?
Because the fix for one of these is definitely not the fix for another one of them necessarily.
Right.
So, yeah.
But this gives people a lot to think about and a lot to go play around with.
So, yeah, it's cool.
Yeah, for sure.
Yeah.
Now, I do have one plea, one request for the folks maintaining all of these things.
Maybe not all of them.
Like Cython, Cython's off the hook.
But for many of these things, right?
For Pi Installer, for Briefcase, for a lot of these, have one or two showcase applications.
That when you go there.
And guess what?
We found this awesome open source GUI application and we built a Mac, Linux, and Windows version of it.
Here's a screenshot.
Click to download and run it and see what the experience is as a user.
Right.
Briefcase is really cool.
But I go there.
There's not like a single example of anything built with it or what.
Right.
There's no evidence to me before I commit to trying it out.
Like, look at this amazing stuff that's built with Briefcase or Pi Installer.
Right.
Like, here's three applications that are well-known apps that you probably didn't even know were built on Python.
Right.
So anyway, I'm going on and on.
I'm with you.
If people are out there like, please put this.
This will do so much to help the adoption.
If people can go see like that.
And it doesn't have to be the owner of that application.
Find an open source application that's awesome that you could package up and then package it up.
Like, you know, it doesn't even have to.
Right.
You could just do it as your own proof of concept and then tell, like, do a PR back.
Who knows?
Yep.
All right.
Well, let's maybe wrap it up there for the.
Oh, go ahead, Chris.
I was going to say maybe we need one of those awesome lists.
Awesome lists of Pi Installer applications.
Awesome list of.
That's right.
Mahmoud Hashemi just recently did an awesome Python applications.
I'm sure there's a bunch.
I know that there are a bunch of GUI applications there.
You could go and package one or two of those up and put it on your site.
Exactly.
No doubt.
Cool.
All right.
Well, let's leave it there for the packaging exploration landscape.
And just, you know, talk about a few things really quick before I let you get out of here.
Sure.
Is there a rumor that you might be doing less typing and more talking and communicating with the world?
Maybe.
I've been exploring the idea of starting up my own podcast, something short form type thing,
kind of 10 minute, 15 minute episodes with the idea.
A little bit like developer tea?
A little bit like developer tea where we just pick a technical topic based on some online article.
People can send suggestions and we read through it, not in complete detail, but just kind of give you my take on it and just kind of analyze what it's talking about and how it affects just development topics in general and technologies.
Well, if you get that out, I'm definitely looking forward.
Are you going to call it the Try Accept Pass podcast?
That's the plan for now.
The Try Accept Pass podcast.
I might change my mind on that, but I think that's good for now.
That's cool.
It could be Try Accept podcast.
Try Accept podcast.
Yeah.
If it doesn't work, make a podcast about it.
Why not?
Yeah, exactly.
Right.
That's the finally clause of the podcast.
Either way, you're going to podcast.
Exactly.
Yeah.
So I was looking for a way to kind of diversify the content I'm putting out with the website, try acceptpass.org, which lately has been doing, well, just finishing up a series on CICD and all the different aspects of it.
Yeah.
And you have a newsletter too, right?
That people can go sign up and hear about it.
That's correct.
If you're interested in the site and keeping an eye out for the podcast and everything that's coming up, just feel free to drop by the website and sign up for the newsletter.
We're also open for any suggestions of anything you want to hear more about.
Like my biggest request so far has been async stuff.
So I'm going to be doing a few more things on that.
Or if you want to contribute an article, it's a good way of getting yourself out there.
Yeah, absolutely.
Cool.
Well, I know the articles you have out there so far are pretty good.
So people should check it out for sure.
Yeah.
The articles are long form too.
So expect 2,000 word articles more or less every couple of weeks.
A little bit like a magazine type of article or something.
Yeah.
Yeah, cool.
Yes.
All right.
Well, excellent.
Yeah.
So keep up the good work over there at trixatpass.org.
I will keep on chugging.
Yeah.
The content creation, it never ends.
No, it doesn't.
It's fun though.
I have lots of fun doing it.
Yeah, that's awesome.
All right.
Now, time for the final two questions before you get out of here.
If you're going to write some Python code, what editor do you use?
These days I am using VS Code.
All right.
Right on.
The remote extension is awesome.
Yeah.
Very cool.
I just read that Facebook has made VS Code their official editor.
Oh, really?
Yeah.
Interesting.
Which is a pretty interesting move there.
Yeah.
So it's cool.
And then notable PyPI package.
There's probably some in our list here.
But what comes to mind, you're like, oh, you should totally know about this thing.
I'm going to throw out Sanic.
I've been using Sanic a lot lately as a REST framework.
But it also has WebSockets integrated with it.
And so you can provide both endpoints that answer HTTP requests and endpoints that answer WebSockets.
And it's asynchronous.
So I've been playing with async APIs, REST APIs using Sanic lately.
Oh, that's super cool.
Yeah.
Sanic is one of the contenders for the hot new async ASGI Python web framework.
So yeah, it definitely seems like it's a good one.
Yep.
I've had great experience so far.
Oh, that's good to hear.
All right.
Final call to action.
People, they got some kind of Python app.
They got to package it up.
What do they do?
Yep.
Just have a listen to the podcast and see where you land.
Make a decision on who your users are going to be and what your best deliverable is.
And make your choice based on that.
If you can help out anybody to, like we were just talking about, produce some examples of
how their packaging systems work, that would be great.
Yeah.
And if you're out there and you've built a cool application and you've bundled it up with
one of these things, shoot a note back to the maintainer.
Say if you use PyOxidizer, shoot a message back to them and say, hey, here's a cool thing
I did.
Could you feature this?
Here's a picture you can feature on the site.
Like, I don't know.
I just think we need more of that.
Yeah.
I'm with you.
And some of it, I know there's lots of apps already.
And some of them might not even be using any of these systems.
I think that just having examples of Python producing these types of system applications
is just good for the language.
I agree.
It would start to break the chicken and egg cycle.
Yeah.
And I'm tired of hearing that Python is only a scripting language.
Yeah.
So am I.
Awesome.
Well, thanks so much for being here, Chris.
It was a lot of fun to go through all this stuff with you.
Yeah.
Loads of fun.
Thanks for having me.
Yep.
Bye.
This has been another episode of Talk Python to Me.
Our guest on this episode was Chris Medina.
It's been brought to you by Tidelift and Linode.
If you run an open source project, Tidelift wants to help you get paid for keeping it going
strong.
Just visit talkpython.fm/Tidelift.
Search for your package and get started today.
Start your next Python project on Linode's state-of-the-art cloud service.
Just visit talkpython.fm/Linode, L-I-N-O-D-E.
You'll automatically get a $20 credit when you create a new account.
Want to level up your Python?
If you're just getting started, try my Python Jumpstart by Building 10 Apps course.
Or if you're looking for something more advanced, check out our new Async course that digs into
all the different types of Async programming you can do in Python.
And of course, if you're interested in more than one of these, be sure to check out our
Everything Bundle.
It's like a subscription that never expires.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play, and the
direct RSS feed at /rss on talkpython.fm.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
We'll see you next week.
Thank you.