|
|
|
|
|
by ghshephard
2023 days ago
|
|
I'm not sure what you mean by, "How do you deal with keeping your top level dependencies and exact versions of all of your dependencies of dependencies separate in a way that's sane and 100% reproduceable for a typical web app / repo that might not in itself be a Python package?" We use requirements.txt + Docker/k8s to lock in the OS. All of the versions of python modules are defined like: six==1.11.0
sqlalchemy==1.2.7
squarify==0.3.0
Which locks them to a particular version.What type of dependencies aren't covered by this (I genuinely am a novice here so would love to be informed where this runs into problems) |
|
The dependencies of the dependencies of what you have listed aren't guaranteed to be locked.
For example, let's say for arguments sake you were using celery.
When you install celery, by default these deps will also be installed: https://github.com/celery/celery/blob/master/requirements/de...
Those aren't very locked down. If you install celery today you might get vine 5.0.0 but in X months from now you might get 5.9.4 which could have backwards compatibility issues with what celery expects.
So now you build your app today and everything works but X months from now you build your same app with the same celery version and things break because celery isn't compatible with that version of vine.
This happened a few months ago. Celery 4.3.0 didn't version lock vine at all and suddenly all celery 4.3.0 versions broke when they worked in the past. That was tracked at https://github.com/celery/celery/issues/3547.
Docker doesn't help you here either because your workflow might be something like this:
- Dev works locally and everything builds nicely when you docker-compose build
- Dev pushes to CI
- CI builds new image based on your requirements.txt
- CI runs tests and probably passes
- PR gets merged into master
- CI kicks in again and builds + tests + pushes the built image to a Docker registry if all is good
- Your apps use this built image
But there's no guarantee what you built in dev ends up in prod. Newer versions of certain deps could have been built in CI. Especially if a PR has been lingering for days before it gets merged.
A lock file prevents this because if a lock file is present the lock file gets used, so if you built and included a lock file in version control, then CI will build what you pushed from dev, so the chain is complete from dev to prod for guaranteeing the versions you want. That is how it works with Ruby, Elixir, Node and other languages too. They have 2 files (a regular file where you put your top level deps and a machine generated lock file). A lock file in Python's world would translate to what pip3 freeze returns.