When I was tasked with looking into alternative ways to set up a new Python project (not just using the good ol' pip
and requirements.txt
setup), I decided to try to find the tools that felt best to me, as someone who writes Python and Ruby. On this journey, I found a way to manage dependencies in Python that felt as good as bundler, among other great tools.
The Runtime Version Manager #
asdf has been my primary tool of choice for language version management for multiple years now. The ease of adding plugins and switching between versions of those plugins at a local or global level has saved me massive amounts of time compared to alternatives.
If you've never set up asdf before, follow the instructions here to get it set up. For reference, I use fish for my shell, so I installed asdf using the "Fish & Git" section.
Once you have asdf on your machine, the next step is to add the plugins you need for your project. Plugins are the actual tools that you want to manage the versions of, like NodeJS, Python, Ruby, etc. For the purposes here, I'll start with adding the plugin for Python:
asdf plugin-add python
Once you have added a plugin to asdf, you're ready to install various versions of that plugin. Since we just installed Python, we can install the version we want:
asdf install python 3.12.4
# OR if we want to just use whatever the latest version is
asdf install python latest
Once the version you want is installed, you can tell asdf to use that version in the current directory by running:
asdf local python 3.12.4
# OR
asdf local python latest
depending on which version of python you installed.
The Dependency Manager #
In the past, I just used pip install
and requirements file(s) to handle most of this. I knew of other options, like pipx
or pipenv
, but I still have never tried using them. I was more interested in finding a dependency manager that did these things in a significantly different way than what I was used to with pip
.
Therefore, I wanted to find something that felt similar to bundler for Ruby. Luckily, very early on in my journey here, I found PDM.
Upon reading what PDM did, I immediately decided to try it out and get a feel for what it offered. Some key notes for me that piqued my interest:
- Lockfile support
- Can run scripts in the "PDM environment"
pdm run flask run -p 3000
executes the normal flask run -p 3000
command within the context of your installed packages with PDM.
- In other words, it adheres to PEP 582 and allows you to run project commands without needing to be in a virtual environment, which to me is a big plus.
- Similar commands to bundler
pdm run
=> bundle exec
pdm install
=> bundle install
pdm add <package>
=> bundle add <gem-name>
- Note: My workflow was almost always to just add
gem <gem-name>
to the Gemfile
rather than using bundle add
, but there is no direct 1:1 equivalent of a Gemfile
with PDM.
Installing PDM #
PDM has its own asdf plugin, so let's just use that here as well! Running:
asdf plugin-add pdm
adds the plugin itself to asdf, and running:
asdf install pdm latest
# can replace 'latest' with a specific version number here too
installs the latest version of PDM. Finally, set the local version with:
asdf local pdm latest