The problem is that plain pip does not resolve incompatible dependencies. Pipenv (and better: Poetry) do. Here's an example:
You project depends on packages Spam and Eggs. Both of them depend on another package, Foo. The problem is, maybe that don't depend on the same version:
Spam 1 depends on Foo 2 or newer.
Spam 2 depends on Foo major version 2, but it's known to be broken with Foo 3.
Eggs 1 depends on Foo 2 or newer.
Eggs 2 requires some of the new features in Foo3.
If you run "pip install spam eggs", it will do something like this:
- Spam version 2 is the newest, so I'll install that.
- Spam 2 depends on Foo 2, so I'll also install Foo 2.
- Eggs 2 is the newest, so grab it!
- Oh no! Eggs 2 depends on Foo 3, but we've already installed Foo 2, so I'll warn you that I couldn't install Foo 3 and then keep on going.
Now you're in a state where "import eggs" will fail because its dependency on Foo 3 wasn't satisfied.
Suppose you use Pipenv (or better: Poetry) instead. It will do something like this:
- What's the newest version of Foo that can satisfy requirements for both Spam and Eggs?
- What's the newest version of Spam and Eggs that can use the version of Foo we identified in the previous step?
- Install Foo 2, Spam 2, and Eggs 1.
Now you have Eggs 1 instead of Eggs 2, but all the versions play nicely together. And if you say "but I really want Eggs 2!", it would give you an error message like "well, that requires Foo 3, but that means you'll have to roll back to Spam 1. Are you OK with that?" The point is that it figures all this stuff out for you and gives you the information to make smart decisions.
This is "dependency resolution". Poetry is great at it. Pipenv is decent at it. Pip doesn't do it at all. That's the real reason these tools are becoming popular.
You project depends on packages Spam and Eggs. Both of them depend on another package, Foo. The problem is, maybe that don't depend on the same version:
Spam 1 depends on Foo 2 or newer. Spam 2 depends on Foo major version 2, but it's known to be broken with Foo 3.
Eggs 1 depends on Foo 2 or newer. Eggs 2 requires some of the new features in Foo3.
If you run "pip install spam eggs", it will do something like this:
- Spam version 2 is the newest, so I'll install that.
- Spam 2 depends on Foo 2, so I'll also install Foo 2.
- Eggs 2 is the newest, so grab it!
- Oh no! Eggs 2 depends on Foo 3, but we've already installed Foo 2, so I'll warn you that I couldn't install Foo 3 and then keep on going.
Now you're in a state where "import eggs" will fail because its dependency on Foo 3 wasn't satisfied.
Suppose you use Pipenv (or better: Poetry) instead. It will do something like this:
- What's the newest version of Foo that can satisfy requirements for both Spam and Eggs?
- What's the newest version of Spam and Eggs that can use the version of Foo we identified in the previous step?
- Install Foo 2, Spam 2, and Eggs 1.
Now you have Eggs 1 instead of Eggs 2, but all the versions play nicely together. And if you say "but I really want Eggs 2!", it would give you an error message like "well, that requires Foo 3, but that means you'll have to roll back to Spam 1. Are you OK with that?" The point is that it figures all this stuff out for you and gives you the information to make smart decisions.
This is "dependency resolution". Poetry is great at it. Pipenv is decent at it. Pip doesn't do it at all. That's the real reason these tools are becoming popular.