.venvPyPIreqeustsmy-app1certifi==2024.8.302charset-normalizer==3.4.03idna==3.104requests==2.32.35urllib3==2.2.3requests2.32.3charset-normalizer3.4.0idna3.10urllib32.2.3certifi2024.8.301# requirements.txt2requests>=2.32,<3MAJOR2MINOR32PATCH301
Back: the PyPI registry and the lock file; front: your project, its requirements and the virtual environmentThe tree: requests (what you declared) and the four packages it needs (transitive)Tokens: packages hopping from the registry, version tags hopping into the lock fileBack: the PyPI registry and the lock file. Front: your project with its requirements.txt (one dependency, requests>=2.32,<3), a version row that tests versions against the rule >=2.32,<3, and a virtual environment holding the dependency tree. pip picks requests 2.32.3, then the four packages it needs; pip freeze writes all five exact versions to the lock file, and installing from it gives the same versions again. The versions are real PyPI releases, frozen at 1 November 2024. Install today and pip picks newer ones (requests itself has moved on), which is exactly why lock files exist.

Reusing code

  1. Your project, my-app, needs to download web pages. Writing that from scratch would take weeks. Instead you reuse a package: code someone else wrote, tested and shared so anyone can install it. Your project then depends on it.

Declaring and installing

Repeatable installs

Staying safe

What happens

;; step 1/10 · reuse
project    my-app: your own code
needs      to download web pages over HTTP
package    code someone else wrote and shared, ready to install
           here: requests
dependency a package your project needs to run

The versions are real PyPI releases, frozen at 1 November 2024. Install today and pip picks newer ones (requests itself has moved on), which is exactly why lock files exist. pip’s real resolver also backtracks when two packages need clashing versions, and it skips yanked releases. Here nothing clashes, so the newest version that fits always wins.