Python and manually creating the requirements.txt vs. pip freeze
I just had an argument with a colleague that I feel like I had a million times before: Should the requirements.txt be manually created with only first-order dependencies or automatically created through `pip freeze` and hence contain all the transitive dependencies?
I am very strongly in favor of the `pip freeze` approach since it guarantees reproducible virtual environments (at least in theory). My colleague, who is, unfortunately, developing on Windows tells me that this regularly breaks on his machine and insists on the manual files with only the first-level dependencies.
Are there known cross-platform issues with `pip freeze` approach? I have searched the internet high and wide and I couldn't find a sound argument for either being right or wrong on this topic.
I would appreciate any input on this :)
25 comments
[ 2.8 ms ] story [ 69.9 ms ] threadMaybe this is something that is best learnt the hard way? Something you understand once you reflect back on how many hours you have lost fighting with dependencies, instead of doing what you actually wanted to do with the code (be it running it, developping, debugging, bisecting...).
Freezing dependencies comes at a cost though, especially since dependency management in python is a PITA. So this is a trade-off. For simpler, projects or scripts, I personally don't bother with freezing dependencies, and I handle issues when they happen. (And they do happen.)
requirements-base.txt:
requirements.txt generated via pip freeze:However, I'm using poetry since a while as it makes it easier for me to just focus on development and don't hassle with virtualenvs, broken APIs (pip search) and manually keeping files in sync.
If you install pex with pipx (or put pex in $PATH another way), you can declare your python script dependencies in the shebang line, like:
Then, you can `chmod +x` your script and call it with "--" between the script name and your arguments, if any: Requests will be installed the first time you run it, then pex should use its cache for subsequent invocations.I wonder if anyone's done this in earnest?
https://github.com/clhodapp/nix-runner
poetry should handle this, and you also get hashes for free!
EDIT: re: cross-platform concerns, I'll also note that since moving to an M1 Mac I've never been so annoyed with the Python packaging situation, and even my own libraries are routinely broken without obvious paths forward. Learning docker as a result, and looking to rust for new projects.
Instead, install pip-tools[0] then use the pip-compile command.
Why?
pip freeze will also pin dependencies of your dependencies, which makes your requirements.txt hard to read and extend.
Never manually create requirements.txt either because a programmer's job is to automate boring tasks like dependency pinning.
[0] https://github.com/jazzband/pip-tools
And I fully agree on the tools. I personally would always use something like pip-tools or poetry, but it's not always an option to use them, unfortunately.
- Manually created requirements.txt with top level production requirements
- Manually created requirements-dev.txt with top level dev requirements.
- pip freeze > requirements-lock.txt (with no dev dependencies)
When installing a new requirement:
1. Delete old venv and create new empty one.
2. pip install -r requirements.txt
3. pip freeze > requirements-lock.txt
4. pip install -r requirements-dev.txt
This ensures your requirements-freeze.txt doesn’t include dev dependencies. With most packages that have binaries now releasing wheels the install isn’t too slow.
Technically you could just save a copy of the venv after step 2 to speed up the process of installing new requirements.
Before constraints.txt came into play, I would've done what you said with pip freeze. With only first-order dependencies, that sounds more likely to break at some point due to the other potential version changes. I think your colleague needs to explain why things are breaking in his case.