惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Full Disclosure
WordPress大学
WordPress大学
小众软件
小众软件
Cloudbric
Cloudbric
AWS News Blog
AWS News Blog
腾讯CDC
量子位
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
Vulnerabilities – Threatpost
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
IT之家
IT之家
Jina AI
Jina AI
Attack and Defense Labs
Attack and Defense Labs
S
SegmentFault 最新的问题
Simon Willison's Weblog
Simon Willison's Weblog
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
T
Tailwind CSS Blog
Last Week in AI
Last Week in AI
博客园 - 【当耐特】
Google Online Security Blog
Google Online Security Blog
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
罗磊的独立博客
L
LINUX DO - 最新话题
博客园 - Franky
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
The Last Watchdog
The Last Watchdog
J
Java Code Geeks
AI
AI
C
Cisco Blogs
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
Help Net Security
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
云风的 BLOG
云风的 BLOG
I
Intezer
S
Securelist

Anže's Blog

The 15-Year-Old iptables Rule That Broke My DNS Fedidevs 9h Outage Postmortem Letting Claude Upgrade My Raspberry Pi Agents Day Lisbon DjangoCon Europe 2026 How to Safely Update Your Dependencies Speeding Up Django Startup Times with Lazy Imports Typing Your Django Project in 2026 Claude Fixes User Bug Jekyll to Hugo Migration Advent of Code 2025 🎄 Django bulk_update Memory Issue Migrating Gunicorn to Granian Disable Network Requests When Running Pytest Disable Runserver Warning in Django 5.2 Autogenerating og:images with Jekyll Power Outages and Gunicorn PID Files UV with Django Go-like Error Handling Makes No Sense in JavaScript or Python Packages Do Not Match the Hashes Pip Error Gotchas with SQLite in Production Fedidevs Dev Update #2 Django SQLite Production Config Django Streaming HTTP Responses Deploying a Django Project to My Raspberry Pi (Video) Thoughts on Code Reviews Django SQLite Benchmark Django, SQLite, and the Database Is Locked Error No Downtime Deployments with Gunicorn SQLite Write-Ahead Logging Writing a Pytest Plugin Fedidevs Dev Update #1 Django-TUI: A Text User Interface for Django Commands Automate Hatch Publish with GitHub Actions Words TUI: App for Daily Writing Textual App Auto Reload RDS Blue/Green Deployments Fly.io Certificate Renewal Using Testing Library with Selenium in Python The Fastest Way to Build a Read-only JSON API import __hello__ Enum with `str` or `int` Mixin Breaking Change in Python 3.11 Your Code Doesn't Have to Be Perfect Fixing _SixMetaPathImporter.find_spec() Not Found Warnings in Python 3.10 Upgrading Django App to Python 3.10 Integer Overflow Error in a Python Application MySQL Performance Degradation in Django 3.1 New Features in Python 3.8 and 3.9 The Code Review Batch Size The Code Review Bottleneck
Python Dependency Management
Anže Pečar · 2022-02-10 · via Anže's Blog
10 Feb 2022

Python has multiple ways for delaing with dependecies and the options can seem intimidating. This blogpost explains the most common dependency management tools and some of the most common commands that one would run.

requirements.txt

If you worked in Python you probably stumbled onto a file named requirements.txt. It’s a file containing a list of items to be installed using pip install. An example file could have the following content:

And you can install it with

pip install -r requirements.txt

The result of the command would look somewhat like:

pip install -r requirements.txt
Collecting django
  Downloading Django-4.0.2-py3-none-any.whl (8.0 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.0/8.0 MB 1.7 MB/s eta 0:00:00
Collecting sqlparse>=0.2.2
  Using cached sqlparse-0.4.2-py3-none-any.whl (42 kB)
Collecting asgiref<4,>=3.4.1
  Using cached asgiref-3.5.0-py3-none-any.whl (22 kB)
Installing collected packages: sqlparse, asgiref, django
Successfully installed asgiref-3.5.0 django-4.0.2 sqlparse-0.4.2

And we can see that our requirements.txt file installed 3 packages. asgiref-3.5.0 django-4.0.2 sqlparse-0.4.2.

The issue with this is that you might install a newer version of Django, sqlparse, or asgiref anytime you run pip install -r requirements.txt. This might break your application code and is considered a bad practice.

To solve this problem you can lock all of the pacakges with pip freeze > requirements.txt that will save all the versions:

django==4.0.2
asgiref==3.5.2
sqlparse==0.4.2

But now we have a different problem. We no longer know which dependencies are direct dependencies for our application (django) and which came from our dependencies’ dependencies. This makes upgrading dependencies tricky.

Only use this approach for small side projects.

pip-tools is a suite of tools that automate pinning and installing dependencies. You give it a list of dependencies that your project depends on (in our case that would be django) and it generates a requirements.txt file for us automatically. This way we can clearly separate the dependencies that we need from the dependencies or dependencies need, thus solving the main problem from the previous section.

We can create a file called requirements.in (although setup.py and pyproject.toml are also supported) with the following content:

And then we can run pip-compile requirements.in which will generate the following requirements.txt file:

#
# This file is autogenerated by pip-compile with python 3.10
# To update, run:
#
#    pip-compile requirements.in
#
asgiref==3.5.0
    # via django
django==4.0.2
    # via -r requirements.in
sqlparse==0.4.2
    # via django

Now that we have the generatd requirement.txt filem, we can install all the dependencies with pip install -r requirements.txt or with pip-sync requirements.txt. The advantage of using pip-sync is that it will also uninstall all the packages not in requirements.txt making sure your environment matches the specification.

Upgrading dependencies

Upgrading dependencies is done with pip-compile --upgrade. The command will respect the version pins in your requirements.in file. This means that if your requirements.in file contains django<4.1 it will never upgrade django to Django 4.1.

Dev dependencies

pip-tools doesn’t have a way a built in way to separate your production dependencies with your development dependencies like some of the other tools do. Instead, we define a new requirements file and name it something like requirements-dev.in:

-c requirements.txt
black

We can generate a compiled requirements-dev.txt file that will include our dev dependencies.

Pipenv

Pipenv is not just a dependency management tool like pip-tools, but also a Python virtual enviornment manager. To start using pipenv we need to tell it which python version the project will be using: pipenv --python 3.10:

pipenv --python 3.10
Creating a virtualenv for this project...
Pipfile: /Users/anze/coding/python-package-managers/Pipfile
Using /usr/local/bin/python3 (3.10.2) to create virtualenv...
 Creating virtual environment...created virtual environment CPython3.10.2.final.0-64 in 240ms
  creator CPython3Posix(dest=/Users/anze/.local/share/virtualenvs/python-package-managers-KVHa45pe, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/Users/anze/Library/Application Support/virtualenv)
    added seed packages: pip==21.3.1, setuptools==60.3.1, wheel==0.37.1
  activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

 Successfully created virtual environment!
Virtualenv location: /Users/anze/.local/share/virtualenvs/python-package-managers-KVHa45pe

This command will do two things:

  1. Generate a new development virtual environment using Python 3.10
  2. Create a Pipfile with the following content:
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]

[dev-packages]

[requires]
python_version = "3.10"

Now if we wanted to add django we would run pipenv install django

after running this our pipfile will look like this:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
django = "*"

[dev-packages]

[requires]
python_version = "3.10"

And we will also have a Pipenv.lock file with the following content:

{
    "_meta": {
        "hash": {
            "sha256": "7e6dca07b964c2888324e576ba6c1bc240d74a27b75619fc88bca2ee3979baf8"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.10"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "asgiref": {
            "hashes": [
                "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0",
                "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"
            ],
            "markers": "python_version >= '3.7'",
            "version": "==3.5.0"
        },
        "django": {
            "hashes": [
                "sha256:110fb58fb12eca59e072ad59fc42d771cd642dd7a2f2416582aa9da7a8ef954a",
                "sha256:996495c58bff749232426c88726d8cd38d24c94d7c1d80835aafffa9bc52985a"
            ],
            "index": "pypi",
            "version": "==4.0.2"
        },
        "sqlparse": {
            "hashes": [
                "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae",
                "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"
            ],
            "markers": "python_version >= '3.5'",
            "version": "==0.4.2"
        }
    },
    "develop": {}
}

We can see that like pip-tools from the section above, Pipfile.lock also includes the same version pins.

Upgrading dependencies

To upgrade the dependencies we can run pipenv update and it will update all the versions in Pipfile.lock, respecting the constraint in the Pipfile.

Dev dependencies

To add development dependencies we have to run pipenv install --dev black and this will place black into the development section of Pipenv.

Poetry

We can start a new Poetry project with

This will generate a new folder structrue for you that looks somewhat like this

poetry init

This command will guide you through creating your pyproject.toml config.

Package name [python-package-managers]:  django-demo
Version [0.1.0]:
Description []:
Author [Anže Pečar <anze@pecar.me>, n to skip]:
License []:
Compatible Python versions [^3.10]:

Would you like to define your main dependencies interactively? (yes/no) [yes]
You can specify a package in the following forms:
  - A single name (requests)
  - A name and a constraint (requests@^2.23.0)
  - A git url (git+https://github.com/python-poetry/poetry.git)
  - A git url with a revision (git+https://github.com/python-poetry/poetry.git#develop)
  - A file path (../my-package/my-package.whl)
  - A directory (../my-package/)
  - A url (https://example.com/packages/my-package-0.1.0.tar.gz)

Search for package to add (or leave blank to continue): django
Found 20 packages matching django

Enter package # to add, or the complete package name if it is not listed:
 [0] Django
 [1] django-503
 [2] django-scribbler-django2.0
 [3] django-filebrowser-django13
 [4] django-jchart-django3-uvm
 [5] django-tracking-analyzer-django2
 [6] django-totalsum-admin-django3
 [7] django-debug-toolbar-django13
 [8] django-django_csv_exports
 [9] django-suit-redactor-django2
 > 0
Enter the version constraint to require (or leave blank to use the latest version):
Using version ^4.0.2 for Django

Add a package:

Would you like to define your development dependencies interactively? (yes/no) [yes] no
Generated file

[tool.poetry]
name = "django-demo"
version = "0.1.0"
description = ""
authors = ["Anže Pečar <[email protected]>"]

[tool.poetry.dependencies]
python = "^3.10"
Django = "^4.0.2"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"


Do you confirm generation? (yes/no) [yes]

This created a pyproject.toml file so now the only thing left to do is to generate a lock file:

poetry lock
Creating virtualenv django-demo-4WB6S-3I-py3.10 in /Users/anze/Library/Caches/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies... (2.7s)

Writing lock file

The poetry.lock file looks like this:

[[package]]
name = "asgiref"
version = "3.5.0"
description = "ASGI specs, helper code, and adapters"
category = "main"
optional = false
python-versions = ">=3.7"

[package.extras]
tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"]

[[package]]
name = "django"
version = "4.0.2"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
category = "main"
optional = false
python-versions = ">=3.8"

[package.dependencies]
asgiref = ">=3.4.1,<4"
sqlparse = ">=0.2.2"
tzdata = {version = "*", markers = "sys_platform == \"win32\""}

[package.extras]
argon2 = ["argon2-cffi (>=19.1.0)"]
bcrypt = ["bcrypt"]

[[package]]
name = "sqlparse"
version = "0.4.2"
description = "A non-validating SQL parser."
category = "main"
optional = false
python-versions = ">=3.5"

[[package]]
name = "tzdata"
version = "2021.5"
description = "Provider of IANA time zone data"
category = "main"
optional = false
python-versions = ">=2"

[metadata]
lock-version = "1.1"
python-versions = "^3.10"
content-hash = "3fb42be116725996c36b953689fc39db958af54df415de893c3608be15d5b925"

[metadata.files]
asgiref = [
    {file = "asgiref-3.5.0-py3-none-any.whl", hash = "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"},
    {file = "asgiref-3.5.0.tar.gz", hash = "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0"},
]
django = [
    {file = "Django-4.0.2-py3-none-any.whl", hash = "sha256:996495c58bff749232426c88726d8cd38d24c94d7c1d80835aafffa9bc52985a"},
    {file = "Django-4.0.2.tar.gz", hash = "sha256:110fb58fb12eca59e072ad59fc42d771cd642dd7a2f2416582aa9da7a8ef954a"},
]
sqlparse = [
    {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"},
    {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"},
]
tzdata = [
    {file = "tzdata-2021.5-py2.py3-none-any.whl", hash = "sha256:3eee491e22ebfe1e5cfcc97a4137cd70f092ce59144d81f8924a844de05ba8f5"},
    {file = "tzdata-2021.5.tar.gz", hash = "sha256:68dbe41afd01b867894bbdfd54fa03f468cfa4f0086bfb4adcd8de8f24f3ee21"},
]

Upgrading dependencies

To upgrade the dependencies we can run poetry update and it will update all the versions in poetry.lock, respecting the constraint in the pyproject.toml.

Dev dependencies

To add development dependencies we have to run poetry add --dev black and this will place black into the development section of pyproject.toml.