pip install, requirements.txt, virtualenv, black, isort, flake8, mypy, setup.py… Если вы настраиваете Python-проект так же, как в 2020 году, эта статья для вас. Показываю современный стек, который заменяет всё вышеперечисленное.
В 2026 году экосистема Python-инструментов наконец собралась в нечто цельное. Два инструмента (uv и ruff) + один файл (pyproject.toml) заменяют 7+ отдельных утилит. Вот как это работает.
Что заменяем и на что
|
Было |
Стало |
|---|---|
|
pip + pip-tools |
uv |
|
virtualenv / venv |
uv |
|
pyenv |
uv |
|
poetry / pipenv |
uv |
|
black (форматирование) |
ruff format |
|
isort (сортировка импортов) |
ruff |
|
flake8 (линтинг) |
ruff check |
|
setup.py / setup.cfg |
pyproject.toml |
|
requirements.txt |
pyproject.toml + uv.lock |
Два инструмента вместо девяти. Оба написаны на Rust, оба от Astral. Работают в 10-100 раз быстрее аналогов на Python.
Шаг 1. Установка uv
Одна команда:
# macOS / Linuxcurl -LsSf https://astral.sh/uv/install.sh | sh# Windowspowershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"# Или через pip (если хочется по-старому)pip install uv
Проверяем:
$ uv --versionuv 0.7.x
ruff ставить отдельно не нужно. uv умеет запускать его через uvx ruff. Но если хотите глобально:
uv tool install ruff
Шаг 2. Создаём проект
$ uv init myprojectInitialized project `myproject` at `./myproject`$ cd myproject$ lspyproject.toml src/ README.md .python-version
uv создал структуру проекта с pyproject.toml, папку src/ и файл .python-version. Никаких setup.py, requirements.txt, Makefile.
Если нужен Python конкретной версии:
# uv сам скачает и установит нужную версию Pythonuv python install 3.13uv python pin 3.13
Да, uv заменяет pyenv. Он сам управляет версиями Python.
Шаг 3. Зависимости
Забудьте pip install. Теперь так:
# Добавить зависимостьuv add requestsuv add pandas numpy# Добавить dev-зависимостьuv add --dev pytest ruff# Удалить зависимостьuv remove pandas
uv автоматически:
1. Создаёт виртуальное окружение (если его нет).
2. Добавляет пакет в pyproject.toml.
3. Обновляет lock-файл uv.lock.
4. Устанавливает пакет.
Всё за одну команду. Никаких pip freeze > requirements.txt.
Скорость
uv устанавливает пакеты в 10-100 раз быстрее pip. Холодная установка numpy + pandas + requests:
|
Инструмент |
Время |
|---|---|
|
pip |
~12 сек |
|
poetry |
~8 сек |
|
uv |
~0.5 сек |
Это не опечатка. uv кэширует пакеты глобально и использует жёсткие ссылки вместо копирования файлов.
Шаг 4. pyproject.toml
Вот как выглядит типичный pyproject.toml после настройки:
[project]name = "myproject"version = "0.1.0"description = "My awesome project"readme = "README.md"requires-python = ">=3.12"dependencies = [ "requests>=2.32", "numpy>=2.0",][dependency-groups]dev = [ "pytest>=8.0", "ruff>=0.9",][tool.ruff]target-version = "py312"line-length = 88[tool.ruff.lint]select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "UP", # pyupgrade "B", # flake8-bugbear "SIM", # flake8-simplify][tool.ruff.format]quote-style = "double"[tool.pytest.ini_options]testpaths = ["tests"]
Один файл. Зависимости, линтер, форматтер, тесты. Всё здесь.
Шаг 5. Линтинг и форматирование (ruff)
ruff заменяет flake8 + black + isort + pyupgrade. Одна команда вместо четырёх.
# Проверить кодuvx ruff check .# Проверить и автоматически исправитьuvx ruff check --fix .# Отформатировать код (замена black)uvx ruff format .# Проверить форматирование без измененийuvx ruff format --check .
Скорость ruff
ruff проверяет код в 10-100 раз быстрее flake8. На проекте из 1000 файлов:
|
Инструмент |
Время |
|---|---|
|
flake8 |
~12 сек |
|
flake8 + isort + black |
~25 сек |
|
ruff check + ruff format |
~0.3 сек |
Пример: что ruff ловит
# Доimport osimport sysfrom typing import Optional, List, Dictimport jsondef process(data: Optional[List[Dict[str, str]]] = None): if data == None: data = list() for item in data: if len(item.keys()) > 0: print(item)
# После ruff check --fix + ruff formatimport jsondef process(data: list[dict[str, str]] | None = None): if data is None: data = [] for item in data: if item: print(item)
Что ruff сделал:
1. Убрал неиспользуемые импорты (os, sys).
2. Отсортировал оставшиеся импорты.
3. Заменил Optional[List[Dict]] на list[dict] | None (Python 3.10+).
4. Заменил == None на is None.
5. Заменил list() на [].
6. Упростил len(item.keys()) > 0 до item.
Шаг 6. Запуск скриптов
Для запуска скриптов внутри виртуального окружения:
# Запуск скриптаuv run python src/myproject/main.py# Запуск тестовuv run pytest# Запуск любой команды в окруженииuv run mycommand
uv run автоматически активирует виртуальное окружение. Не нужно никаких source .venv/bin/activate.
Одноразовые скрипты
Нужно быстро запустить скрипт с зависимостями, не создавая проект?
# Запустить скрипт, который требует requests, без установкиuv run --with requests python script.py# Запустить инструмент одноразово (npx-стиль)uvx black .uvx httpie https://api.github.com
uvx = npx для Python. Скачивает, запускает, не засоряет систему.
Шаг 7. CI/CD
Минимальный GitHub Actions workflow:
# .github/workflows/ci.ymlname: CIon: [push, pull_request]jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: astral-sh/setup-uv@v5 - run: uv sync - run: uvx ruff check . - run: uvx ruff format --check . - run: uv run pytest
4 строки. Установка зависимостей, линтинг, форматирование, тесты. Всё.
Время CI на типичном проекте:
|
Стек |
Время |
|---|---|
|
pip + flake8 + black + pytest |
~45 сек |
|
poetry + flake8 + black + pytest |
~60 сек |
|
uv + ruff + pytest |
~12 сек |
Шаг 8. Docker
Минимальный Dockerfile:
FROM python:3.13-slim# Установить uvCOPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv# Копировать файлы проектаWORKDIR /appCOPY pyproject.toml uv.lock ./# Установить зависимости (кэшируется Docker layer)RUN uv sync --no-dev --frozen# Копировать кодCOPY src/ src/CMD ["uv", "run", "python", "-m", "myproject"]
Важный момент: pyproject.toml и uv.lock копируются отдельно от кода. Это позволяет Docker кэшировать слой с зависимостями. Если код изменился, а зависимости нет, переустановки не будет.
Миграция с pip/poetry за 2 минуты
С requirements.txt
# Инициализировать проектuv init# Импортировать зависимости из requirements.txtuv add $(cat requirements.txt)
С poetry
uv понимает pyproject.toml в формате Poetry. Просто:
# Удалить poetry.lock, создать uv.lockrm poetry.lockuv lockuv sync
Если в pyproject.toml есть секция [tool.poetry], uv прочитает зависимости оттуда.
Полный чеклист нового проекта
# 1. Создать проектuv init myproject && cd myproject# 2. Добавить зависимостиuv add requests pydantic# 3. Добавить dev-зависимостиuv add --dev pytest ruff# 4. Написать код# ...# 5. Проверить и отформатироватьuvx ruff check --fix .uvx ruff format .# 6. Запустить тестыuv run pytest# 7. Готово
Пять минут. Никаких setup.py, MANIFEST.in, requirements.txt, tox.ini, .flake8, .isort.cfg, pyproject.toml на 200 строк.
uv + ruff + pyproject.toml = всё, что нужно для Python-проекта в 2026 году.
Ссылки
uv на GitHub (80k+ звёзд)
ruff на GitHub (40k+ звёзд)
Документация uv
Документация ruff
PEP 621: стандарт pyproject.toml
ссылка на оригинал статьи https://habr.com/ru/articles/1044550/