Один из создателей Django и автор Datasette, Simon Willison, опубликовал короткий, но ценный рецепт: как запускать Python-инструменты через uvx в GitHub Actions так, чтобы каждый прогон не делал лишних запросов на PyPI. Решение умещается в одну переменную окружения — UV_EXCLUDE_NEWER — которая одновременно фиксирует версии пакетов и служит cache key.
Контекст
uv — ультрабыстрый менеджер Python-пакетов от Astral, написанный на Rust. uvx — его подкоманда для запуска инструментов без постоянной установки в окружение: аналог npx для Node.js или pipx run для Python, только значительно быстрее. Инструмент набирает популярность в CI-сценариях: запустить ruff, mypy, black или кастомный CLI без захламления виртуального окружения.
Проблема классическая: uvx tool-name без дополнительных флагов всегда тянет последнюю версию пакета с PyPI. Это ломает кэш GitHub Actions — cache key меняется при каждом обновлении пакета. Итог: на каждом прогоне CI идёт в сеть, скачивает зависимости, тратит минуты и деньги.
GitHub Actions предоставляет механизм кэширования через actions/cache, но он требует стабильного детерминированного ключа. При работе с динамически разрешаемыми версиями пакетов этот ключ либо слишком волатильный, либо его сложно корректно вычислить — особенно когда инструмент тянет транзитивные зависимости.
Аналитика
Трюк Уиллисона элегантен. Переменная UV_EXCLUDE_NEWER: "2026-07-12" говорит uv не использовать версии пакетов, опубликованные после указанной даты. Разрешение зависимостей становится детерминированным: тот же инструмент, та же версия, те же транзитивные зависимости — пока дата не изменится. Та же переменная включается в cache key GitHub Actions. Кэш бьётся только при смене даты — то есть только тогда, когда разработчик сознательно решает обновить инструменты.
Это решение без компромисса: не нужно писать lock-файлы, поддерживать отдельный requirements-tools.txt или городить скрипты. Обновление — один коммит: поменял дату, следующий прогон получает свежие версии и кэширует их заново. Обновляй так часто или так редко, как удобно команде.
Паттерн попадает в важный тренд: LLM-инструменты и AI-агенты переезжают в CI-пайплайны. Генерация release notes, автоматическая проверка PR-описаний, анализ diff через LLM, оценка качества кода — всё это нужно запускать воспроизводимо. Неожиданный апгрейд зависимости может изменить поведение AI-инструмента на выходе. Контроль через дату — один из самых прозрачных способов держать это под контролем.
Кейсы применения в бизнесе
B2B-SaaS стартап с активной разработкой. Если пайплайны запускаются при каждом PR и команда использует uvx для линтинга, форматирования или кастомных проверок — добавление UV_EXCLUDE_NEWER в верхний env workflow и включение переменной в cache key уберёт сетевые задержки от PyPI из большинства прогонов. Инструменты качества кода не меняются чаще раза в несколько недель; незачем скачивать их при каждом коммите.
IT-студия или аутсорс-команда в КР и СНГ. При работе с несколькими клиентскими репозиториями предсказуемость CI критична для приёмки. Фиксация даты означает: инструмент ведёт себя одинаково сегодня и через три месяца — удобно при сдаче проекта и последующей поддержке без сюрпризов от обновлений зависимостей в ночи перед дедлайном.
Команда с legacy Python-стеком. Там, где нет нормального lock-файла и обновление зависимостей — отдельная болезненная операция, UV_EXCLUDE_NEWER позволяет заморозить инструментальную экосистему на проверенной дате без рефакторинга всего CI. Особенно ценно при аудите или подготовке к сертификации, когда нужна воспроизводимая среда.
Кейсы в личной жизни
Разработчик-одиночка с open source проектами. Добавь рецепт один раз в шаблон workflow — и больше не разбирайся, почему прогон вчера работал, а сегодня упал из-за мажорного релиза инструмента в пятницу вечером. Спокойные выходные дороже.
Технический блогер или контент-мейкер, автоматизирующий публикацию через CI: генерация sitemap, проверка ссылок, сборка статики, автопостинг. Стабильный кэш ускоряет пайплайн и убирает шум от случайных поломок, не связанных с твоим кодом.
Студент или джун, осваивающий GitHub Actions. Паттерн с датой — хорошая учебная модель: он объясняет, почему детерминированность важна в CI, и учит думать об инвалидации кэша через понятный рычаг, а не через непрозрачные хэши зависимостей.
«Моя цель — использовать Python-инструменты в GitHub Actions без того, чтобы каждый прогон ходил на PyPI за свежей копией инструмента и его зависимостей» — Simon Willison
Как применить сегодня
- В
envверхнего уровня GitHub Actions workflow добавь:UV_EXCLUDE_NEWER: "2026-07-14"— сегодняшняя дата или любая точка фиксации. - В шаге
actions/cacheвключи дату в cache key, например:key: uvx-cache-${{ env.UV_EXCLUDE_NEWER }}-${{ runner.os }}. - Используй
uvx tool-nameвместоpip install tool && tool— uvx изолирует окружение и не загрязняет системный Python раннера. - Для обновления инструментов — поменяй дату в
env. Следующий прогон скачает актуальные версии и закэширует их заново. - Посмотри документацию uv по переменной
UV_EXCLUDE_NEWER— инструмент активно развивается и добавляет новые опции для управления воспроизводимостью.