- MCP server with stdio transport for local use - Search episodes, transcripts, hosts, and series - 4,511 episodes with metadata and transcripts - Data loader with in-memory JSON storage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
359 lines
19 KiB
Plaintext
359 lines
19 KiB
Plaintext
Episode: 3072
|
|
Title: HPR3072: The joy of pip-tools and pyenv-virtualenv
|
|
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr3072/hpr3072.mp3
|
|
Transcribed: 2025-10-24 16:13:13
|
|
|
|
---
|
|
|
|
This is Hacker Public Radio Episode 3,072 for Tuesday 12 May 2020.
|
|
Today's show is entitled The Joy of Pittles and Pie and V Virtual NV,
|
|
and is part of the series A Little Bit of Python. It is hosted by Klacky
|
|
and is about 24 minutes long
|
|
and carries an explicit flag. The summary is
|
|
how to manage your dependencies and environment isolation when developing in Python.
|
|
This episode of HPR is brought to you by archive.org.
|
|
Support universal access to all knowledge by heading over to archive.org forward slash donate.
|
|
Thanks for watching.
|
|
Hi, I'm Klacky.
|
|
For the last year I've been working full time as a Python web application developer
|
|
and I learned many things along the way.
|
|
Now I knew Python the language and I've been using it for the better part of a decade
|
|
but working with build scripts and other automation that I was doing earlier
|
|
and working on an application that is going to be developed by maybe one core team
|
|
and then other temporary contributors which could be deployed in multiple places,
|
|
automatically installed and has a large set of dependencies.
|
|
That's quite a different thing.
|
|
Then you not only need to know the language, you also need to know the tooling around the language
|
|
and around all of these other concerns.
|
|
There's two main things that are really important.
|
|
First is the dependency management.
|
|
I have an application, I need these frameworks and libraries to make it work
|
|
and they in turn have their own dependencies that make them work.
|
|
That all needs to be handled especially when you start upgrading things
|
|
or otherwise playing around with different versions of things.
|
|
The other thing is you want to be able to develop these things in isolation.
|
|
Maybe I'm working on the latest version but there's a couple of days older version running in production
|
|
and there's an issue there.
|
|
I want to be able to check that out and not get a conflict between what's installed now
|
|
and the development version and what's installed in production.
|
|
Maybe I have several projects running.
|
|
Each project could have its own set of dependencies or it will have its own set of dependencies.
|
|
Between two different projects those dependencies might be in conflict
|
|
so you need to be able to isolate different projects from each other.
|
|
This is something you always want when you do application development doesn't really depend on the language
|
|
but the tooling is different for each language.
|
|
When you handle requirements you want to handle it in two steps.
|
|
First of all there's the requirements that I want.
|
|
We are using an application, it uses framework xyz and it needs to be version 4
|
|
because that's the API we're developing against.
|
|
Then there's the dependencies of xyz itself and the dependencies of those dependencies.
|
|
That's the set we call the transitive dependencies.
|
|
When we are developing on our level in the application we don't really care about these other dependencies
|
|
because we don't program against those interfaces.
|
|
When it comes to troubleshooting we want to be able to pinpoint where something is different
|
|
between this thing that is working and between this thing that is not working.
|
|
It's well known that in common developer excuses it works on my machine
|
|
and you want to be able to avoid that if it works on my machine it's supposed to work on your machine.
|
|
If I just say I'm depending on xyz version 4
|
|
maybe you have version 4 and I have version 4.1
|
|
or maybe we both have version 4.1 exactly
|
|
but your version 4.1 depends on some other package version 3
|
|
and maybe my xyz version 4.1 depends on that other package version 5
|
|
because maybe you installed your packages Thursday last week
|
|
when xyz dependency was released at version 4
|
|
and maybe I installed mine this week on Tuesday
|
|
and then maybe this dependency version 5 was out and xyz pulled in that instead.
|
|
So what you do is you define both.
|
|
You say here's the stuff that I want
|
|
and here's the stuff that that happens to mean today
|
|
and that's a snapshot of the situation right now
|
|
and that means if everyone installs from this same snapshot of versions
|
|
of all the dependencies and transitive dependencies
|
|
then if we ignore configuration and other such variation right now
|
|
then at least in terms of the software that is running
|
|
if it works on my machine it should work on your machine as well
|
|
and if I run into an issue you should be able to reproduce that issue
|
|
on your machine.
|
|
Let's call that first set of direct dependencies
|
|
the abstract dependencies and let's call the
|
|
very detailed locked down to each version of each transitive dependency
|
|
let's call that our locked dependencies.
|
|
Now some people say that if you develop a library
|
|
you should use abstract dependencies and if you develop an application
|
|
you should use these locked dependencies but I disagree
|
|
both are required whether you are developing an application
|
|
or you're developing a library because one describes the set of situations
|
|
where this thing is supposed to work that's the abstract dependencies
|
|
like according to all the documentation that we have
|
|
if you use version 4 of xyz with our library or application
|
|
it should work and if they break something they should call it version 5
|
|
but then there's the locked set of dependencies that we have actually verified
|
|
and which we can use to reproduce an issue from one system to another
|
|
and here comes the fun part in Python
|
|
there is no standard way to have abstract dependencies and locked dependencies
|
|
and here's where this distinction of application versus library comes in
|
|
so what people would do traditionally would be to say
|
|
okay I'm developing a library and in my setup.py
|
|
which is the project description that you need to have
|
|
to be able to upload your package to the Python package registry
|
|
in my setup.py if I'm developing a library I should say
|
|
a range of versions of my direct dependencies
|
|
because then someone who depends on my library
|
|
and depends on some other library needs to be able to allow the package manager
|
|
to figure out a set of dependencies that fits both of those dependencies
|
|
and then people who develop an application would say
|
|
well I want this application to always install the same versions of things
|
|
so they might have a locked down set of dependencies in their setup.py
|
|
and then there's requirements.text and that's what people would use
|
|
if they're just developing an application internally
|
|
and they're not really looking to upload it anywhere
|
|
so they don't need to have a full package description
|
|
they just want some executable documentation
|
|
that says here's what you need to install in order to run this thing
|
|
so what they would do would be to develop the application
|
|
install packages as they need them and then run pip frees
|
|
with output to this requirement.text and pip frees just looks at
|
|
what packages do I happen to have installed and dump that
|
|
and that's not really a way to manage a list of dependencies
|
|
so I started looking around and okay if there are no standard tools
|
|
that can keep an abstract set of dependencies and a locked set of dependencies
|
|
what other non-standard tools are there
|
|
but before we go into that let's talk about the other part
|
|
of the deployment and development problem
|
|
so we had this list of dependencies and how to manage that
|
|
and then we also have I have multiple applications
|
|
that I'm developing and they each have their own set of dependencies
|
|
so how do we isolate them from each other
|
|
and the way you do that in Python is you use virtual environments
|
|
a virtual environment is basically a directory that is a small fake
|
|
complete Python installation with Python and packages and everything
|
|
and when you are in a virtual environment
|
|
you install packages and you act as if you would be installing them globally on the system
|
|
but actually they are confined to this directory
|
|
it doesn't involve any kernel level containerization or anything like that
|
|
it's not a real virtual environment in that sense
|
|
it's just a Python virtual environment
|
|
like we pretend this is a system installation but actually it's contained to this directory
|
|
okay when I started my research I found two tools that seemed like the tools the people are using
|
|
and one was poetry and the other was PIPENF
|
|
so I looked at poetry first because it was supposed to be this modern thing
|
|
that addressed several issues with PIPEN with other tools
|
|
and it uses the standardized PIPROJECT.TOML
|
|
which is where you're supposed to put tools settings these days in Python
|
|
so that you don't spread it out over several different files
|
|
non-standard files
|
|
so I don't quite remember why I didn't like poetry
|
|
on paper it looks very good
|
|
but I think I felt like it was too big a tool
|
|
and it tries to do all kinds of things
|
|
and I really just wanted something to manage my requirements
|
|
I didn't need a tool to handle uploads to PIPI, the package index
|
|
and I didn't need to have a project specification and all that
|
|
I just wanted to go from list of abstract dependencies to list of log dependencies
|
|
so I may have running to some other issue also I don't know
|
|
but anyway I left poetry behind and I looked at PIPENF
|
|
PIPEN does pretty much what poetry does
|
|
except that it puts these package requirements in PIPFYLE
|
|
instead which is also a TOML file
|
|
it's just named PIPFYLE because PIPROJECT or TOML didn't exist at the time
|
|
and when you generate the locked dependencies
|
|
that ends up in a file called PIPFYLE.LOCK
|
|
so it's not in PIPROJECT or TOML
|
|
and I used PIPENF for my own personal use
|
|
but I didn't want to have to convince others to use this tool
|
|
or that tool I just wanted to have this simple requirements dot text
|
|
that people can just pip install dash R requirements dot text
|
|
and just get what they need
|
|
and all these others sophisticated stuff I felt was too much to try to explain
|
|
to maybe someone joining the team temporarily to just add some feature
|
|
or some external contributor
|
|
but then I learned from people on the Fediverse that what PIPENF does internally
|
|
is actually it uses PIPTools
|
|
PIPTools has a command line tool called PIPCompile
|
|
which just takes either it reads setup.py or runs setup.py and gets the requirements from there
|
|
or you can feed it a requirements dot in file
|
|
which is just a list of lines which would be parameters to a PIP install command
|
|
and that's your abstract dependencies
|
|
and then it outputs a requirements dot text
|
|
which is your locked dependencies
|
|
and that's also just in PIP install argument format
|
|
so it's all really neat and readable
|
|
and people have been using Python
|
|
know it and understand it
|
|
no tumble files, no built-in virtual van management
|
|
and just one text file
|
|
and you generate another text file
|
|
so we went with PIPTools and PIPCompile for all our projects
|
|
so that's the dependency management
|
|
just use PIPTools very simple
|
|
and what about the virtual end management?
|
|
well you could do it manually
|
|
just python.m virtual n which is an external package
|
|
or python.m vn which is the built-in functionality in Python 3
|
|
but it may or may not work depending on which version of Python
|
|
several different versions of Python break the vn functionality
|
|
and you might have to use virtual n anyway
|
|
and a condo which we use at office
|
|
is one example where vn doesn't work
|
|
and you have to use virtual n instead
|
|
so you can do that manually
|
|
python.m virtual n and then directory name
|
|
and then when you want to use that virtual environment
|
|
you source directory name slash bin slash activate
|
|
and then when you're done you deactivate
|
|
and these commands will put the right python on the path
|
|
and make sure that all the packages are handled
|
|
within this confined directory
|
|
but this is a little bit annoying
|
|
so there are several different ways to manage your virtual environments
|
|
first of all it could be nice to have the virtual environment
|
|
not be in your project directory
|
|
it's very common to create a virtual n vn inside your project directory
|
|
but then when you run some static analysis tools
|
|
or you search for things you might end up having this huge set of dependencies
|
|
that you're accidentally running analysis or searches on
|
|
so you want to keep it outside and then the path becomes longer to type
|
|
so then maybe you create some alias
|
|
so some people use something called virtual n wrapper
|
|
which basically allows you to have a global set of environments
|
|
and then when you want to work on your project
|
|
you just type work on project name
|
|
and that activates that particular virtual environment
|
|
now I had already been using pipnV
|
|
so even though I left the package management behind
|
|
I just ignored that there's a pip file in there
|
|
I still use the virtual n management of pipnV
|
|
so you can do pipnV shell then it creates a new shell
|
|
and in there now you're in the virtual environment for Python
|
|
or you can do pipnV run some command in that virtual environment
|
|
and then come back to you
|
|
so you don't have to activate and deactivate
|
|
and you just confine all that to a sub shell that runs this virtual environment
|
|
and when you exit then you're back in your normal world
|
|
but even that just running pipnV shell became a little bit annoying
|
|
especially if you're jumping back and forth
|
|
and now I need to fix something on production
|
|
or now I need to run this script over here
|
|
you have to exit and then pipnV shell somewhere else
|
|
so in the end I looked up how to use pinV and pinV virtual n
|
|
and I'm very satisfied with the result of that
|
|
so what pinV does is it's a manager for different Python versions
|
|
so you can use it to install these different Python versions
|
|
and then you can also use it to switch between them
|
|
so you could use Python 3.6 in this directory
|
|
and you could use Python 3.8 in another directory
|
|
and it has a file that you affect using just pinV local
|
|
and then name of one of these Python versions that you have installed
|
|
and then it runs it writes the name to this .python-version file in the directory
|
|
and it doesn't hijack the CD command or anything like that
|
|
it's just that you put the .pyn-slash-shims directory first in your path
|
|
and it has files there for any Python-related command
|
|
you might want to run and if you install a package
|
|
it adds the scripts of that package to the shims directory as well
|
|
so that when you run a Python-related command
|
|
in reality you run the shim from pin
|
|
and it looks up which Python version I'm also supposed to be using now
|
|
could be the default version or it could be something specific for this directory
|
|
and you can also even specify a specific version for this shell session
|
|
so you could say right now I want to use Python 3.5
|
|
and then you can do that in that shell and when you exit that preference is gone
|
|
that's pretty neat and pin-virtual-n adds virtual environments to this
|
|
and a virtual environment then becomes just like another Python
|
|
in the list of pythons that you can define
|
|
so you can say pin-virtual-n and then which Python version you want to use
|
|
and then name of a virtual environment that you want to create
|
|
and then you can say pin-v local name of that virtual environment
|
|
and now when you are in that project directory and you run Python
|
|
that means you run Python that belongs to that virtual environment
|
|
if you're somewhere else then you run Python
|
|
it means you are system Python for example or whatever Python you have set
|
|
in your pin-v preferences or for this specific shell
|
|
so you have a lot of flexibility here
|
|
installing PyNv is very easy
|
|
you just clone the PyNv repo to your home directory slash dot PyNv
|
|
and then installing PyNvirtual-n is very simple too
|
|
you just clone that repo into dot PyNv slash plugins
|
|
slash PyNvirtual-n and then to activate them you put three lines in your
|
|
dot bash profile
|
|
so first you need to add PyNv bin to your path
|
|
and then you run PyNv init- and eval the results of that
|
|
and then you run PyNvirtual-n init- and you evaluate the results of that
|
|
and that's all in the installation instructions for these packages
|
|
but I also show it in the show notes
|
|
now I mentioned that we use Anaconda in the office
|
|
and we have our own installation scripts for Anaconda
|
|
that configures it with our internal CA certificates and all of that stuff
|
|
so I don't use PyNv to install Python versions
|
|
but it works well together with Anaconda
|
|
so I can just do konda create dash p
|
|
and then I point inside dot PyNv slash versions
|
|
and I create a Python version there using Anaconda instead of using PyNv's built-in functionality
|
|
and it just works so that's pretty neat
|
|
and from that point I can use PyNv to create virtual n's for the Anaconda environment
|
|
and switch between different Python versions and virtual n's in different directories
|
|
even though they come from Anaconda originally
|
|
so that was a lot to unpack
|
|
and there's a lot of further here for more episodes
|
|
but I think this is good enough for today
|
|
so I think I owe you a show on just reproducible builds
|
|
what does it mean?
|
|
how can we make sure that runs on my machine?
|
|
it's not an excuse anymore
|
|
that's a whole episode
|
|
and when I'm working at home
|
|
or well I'm doing my hobby projects at home
|
|
I don't use PyNv or any of these things
|
|
I use Nix
|
|
and that's also a whole episode of its own
|
|
how do you use Nix together with Python?
|
|
and then of course
|
|
now that I mentioned setup Py
|
|
but actually setup Py is deprecated
|
|
and there's not really one standard to replace it
|
|
quite yet there's a bunch of tools
|
|
that do what setup Py used to do
|
|
there's poetry
|
|
which not only handles the dependencies part
|
|
but it also handles the project definition part
|
|
and one tool that I have come to like
|
|
is Flit I've used it in the office
|
|
to package some things that we actually want to package
|
|
to install them from somewhere else
|
|
Flit is very lightweight
|
|
and only does what you need to do
|
|
so that's worth all episode of its own as well
|
|
and also when you are handling all these environments
|
|
you're installing packages and all that
|
|
in the end you want to test this in a reliable way
|
|
and make sure you didn't make any human mistakes
|
|
so that the tests you run locally are the same
|
|
that the tests you run on for example Jenkins
|
|
and for that there's a tool called Talks
|
|
which is also worth an episode of its own
|
|
so I'll hold you a whole bunch of shows
|
|
we'll see when I get to them
|
|
my name is Klake
|
|
you can find me on the free social web
|
|
as Klake at Libranet.de
|
|
and until next time
|
|
this has been Hacker Public Radio
|
|
uh
|
|
uh
|
|
uh
|
|
uh
|
|
uh
|
|
uh
|
|
uh
|
|
uh
|
|
I've been listening to Hacker Public Radio
|
|
at Hacker Public Radio.ci
|
|
we are a community podcast network
|
|
work that releases shows every weekday Monday through Friday. Today's show, like all
|
|
our shows, was contributed by an HPR listener like yourself. If you ever thought of recording
|
|
a podcast and clicking our contribute link to find out how easy it really is, Tech
|
|
or Public Radio was founded by the Digital Dog Pound and the Infonomicon Computer Club,
|
|
and is part of the binary revolution at binwrap.com. If you have comments on today's show,
|
|
please email the host directly, leave a comment on the website, or record a follow-up
|
|
episode yourself. Unless otherwise stated, today's show is released under a creative
|
|
comment attribution. Share it like 3.0, isn't it?
|