📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

🔥uv — швейцарский нож Python-разработчика

Диджитализируй!20:11

Transcription

Здорово, катаны! Если вы вдруг упустили современный Python инструментарий, то я буду очень рад познакомить вас с uv. UV, дорогие друзья, это такой, можно сказать, пакетный менеджер для Python, как pip или Poetry, только лучше. А ещё как venv, только лучше. А ещё как virtualenv, только опять же лучше. И что самое это главное, дорогие друзья, Blazing Fast! Написано на Rust. Blazing Fast, дорогие друзья! Давайте разбираться.

Значит, как эту петрушку замесить? Объем установить при помощи curl, конечно же. Такая вот команда значит установит нам великолепный пакетный менеджер uv. Если вдруг вы запускаете такую команду на вашем прекрасном Linux, и система вам говорит: "curl: command not found", да? Ну, значит, надо его поставить, дорогие друзья. У меня curl стоит, поэтому у меня команда, конечно же, прошла. Если вы пользуетесь Mac, у вас есть, наверно, при помощи Homebrew, тоже можете, конечно, поставить. Также у нас есть замечательное автодополнение этого пакетного менеджера для Bash и Zsh. Можно их тоже вот таким вот образом установить. Великолепно!

Начнём с того, как uv работает с версиями Python, дорогие друзья. Это совершенно потрясающе, дорогие друзья. `uv python list`. Опаньки! И что же нам здесь показывается? Показывается, что у нас оказывается установлен Python 3.11 в системе, и uv его подтянул, о нём знает. Да, ещё у нас есть, значит, что у нас есть 3.12. Вот, вот в таких, значит, расположениях. У нас есть ещё у нас есть Python 3.13.1, который я собирал из исходников. Вот Python 3.13 у нас лежит. А ещё у нас есть вот такие вот замечательные 3.7, 3.8, 3.9, 3.10. Значит, 3.14 даже альфа-версию можно поставить, да? При этом у меня вот 3.13.1, а уже вышло 3.13.2, дорогие друзья. Давайте её э поставим при помощи uv. `uv python install 3.13.2`. Вот прямо одной командой.

И вот, пожалуйста, в директории `.uv/local/share/uv/python/` и мы можем этим интерпретатором пользоваться. Посмотрите, как быстро! Ну, это же класс! Не надо ничего нигде искать, прямо вот все версии здесь под рукой. Можно прямо быстро установить и начать этим пользоваться. Конфеточка!

А ещё вот мы какой проект хотим написать. Вот у нас, значит, чистая директория, да? Мы тут хотим каких-нибудь питоновских файликов туда-сюда написать, и мы хотим использовать версию 3.13.2 в этом проекте. Прямо пишем `uv python pin 3.13.2`. Хоп! Что у нас здесь произошло? Произошло у нас здесь, собственно говоря, вот такое великолепие. Добавилось у нас вот такой вот файл `pyproject.toml`. И что в нём есть в этом файле? А там просто написано `3.13.2`. И, соответственно, весь Python код, который мы здесь будем в этой директории писать, в директории, в которой лежит `pyproject.toml`, будет запускаться при помощи 3.13.2. Прикиньте?

Что значит, создал я вот такой файлик `main.py`, дорогие друзья. И давайте его запустим при помощи, значит, Python 3.13.2, той версии, которая указана в файле `pyproject.toml`. `uv run main.py`. Хоп! Э программка совершенно простая, написана на Python, да? Она показывает версию Python, то есть версию интерпретатора Python, при помощи которого эта программа запущена. Да, 3.13.2, дорогие друзья! Класс вообще! То есть, прикиньте, что мы можем вот так вот на лету фактически это менять. Если мы хотим запустить при помощи 3.11, просто в этом файле меняем `3.11`, запускаем, и у нас этот запускается код при помощи интерпретатора 3.13.1.

Причём более того, дорогие друзья, `uv python uninstall 3.13.2`. Мы сейчас удалили этот Python. И вот `uv python list`. Да, мы видим, что 3.13.2 у нас уже не установлен, только 3.13.1. Но при этом, дорогие друзья, если у нас здесь нужна нам версия 3.13.2, то есть вот просто создан `pyproject.toml` `3.13.2`, и мы запускаем `uv run main.py`, то у нас сейчас скачается нужная версия 3.13.2 прямо на лету. Да, uv для нас эту версию скачает и запустит. И вот у нас, пожалуйста, 3.13.2. И когда мы посмотрим `uv python list`, мы убедимся, что у нас 3.13.2 здесь появился. Вообще кайф, дорогие друзья! Ну, то есть работать с разными версиями Python, ну, просто же конфеточка, просто конфеточка. Хотим поиграться с альфа-версией какой-нибудь новой, да? Там 3.14 накатили. Всё это изолировано, всё это безопасно. Поиграли. Супер! Очень удобно, прямо вот просто конфеточка.

Как можно запустить Python код, собственно, я уже показывал, да? `uv run main.py`. Пожалуйста, мы запустили `main.py` в текущем проекте, да? То есть текущей версии Python и, возможно, с теми настройками, с теми зависимостями, которые здесь есть. Как мы можем установить зависимости сюда, да? Потому что это же пакетный менеджер, вроде как пакеты надо, надо уметь добавлять, да? Собственно, `uv add requests`. Хотим добавить requests, и uv нам говорит, что нету `pyproject.toml`. Надо инициализировать проект. Ну, собственно, `uv init`. Хоп! `uv init`. Если мы здесь посмотрим, что у нас добавилось при помощи `uv init`, у нас добавилась точка git. То есть теперь это git-репозиторий. Это uv нам сама добавила, да? Добавился файл `.gitignore`. Давайте посмотрим, что у нас в `.gitignore` лежит. Ну, собственно, у нас игнорируется `__pycache__`, `build`, вот всё, что нам не нужно в питоновских проектах, да? И добавился `pyproject.toml` и `README.md`. Ну, `README.md` пустая. Давайте посмотрим `pyproject.toml`. Да, `[build-system]`. `[project]`. `pyproject.toml` — это значит, который описывает зависимости нашего проекта. В данном случае у нас зависимости нет, пустой, да? Какая версия нужна? 3.12 или старше. Здесь мы можем написать, значит, где у нас лежит `README.md`, какой версии нашего пакета и название нашего пакета. Отлично, дорогие друзья! Ну, теперь и в `pyproject.toml` мы убедимся, что у нас здесь, значит, в `dependencies` добавился `requests`, дорогие друзья. При этом, если мы посмотрим `ls`, то мы убедились, что у нас здесь добавилась директория `.venv`. Это то самое виртуальное окружение, к которому мы вроде как привыкли, но которая с которым нам не нужно теперь работать напрямую. То есть нам не нужно создавать виртуальное окружение, активировать его, деактивировать. Всё это происходит внутри, так сказать, нашего замечательного uv. Если мы сейчас запустим `uv run main`, мы убедимся, что всё работает. И в `main.py` мы уже можем вызывать `requests`, да, которые мы установили в этот проект. Давайте посмотрим. Ну, такой простенький код, просто импортируем requests, отсылаем запрос на какую-нибудь свободную API и печатаем её результаты. Давайте попробуем это запустить. `uv run main.py`. Опаньки! И у нас всё сработало, дорогие друзья! Вот, вот прямо всё сработало, да? Это вот ответ от нашей замечательной API, информация по стране Российской Федерации, дорогие друзья. Скажите, классно? Скажите, классно! При этом мы сейчас не создавали какой-то отдельной командой виртуальное окружение, не активировали его каким-то особым образом. Нам не нужно его деактивировать. Просто когда мы `uv run` запускаем, то uv подтягивает нужные зависимости, нужное виртуальное окружение для нашей конкретной команды. Очень удобно, просто песня!

Конечно же, можно посмотреть все зависимости в виде дерева. `uv tree`. Мы видим здесь вот библиотечка `requests`, да, и она зависит от `certifi`, `charset-normalizer`, `idna` и `urllib3`. Здесь дерево может быть большим, да, в зависимости от тех зависимостей, которые у нас есть, и в зависимости от тех зависимостей, которые есть у наших зависимостей. То есть здесь может быть вполне себе большое дерево. Давайте `uv django` установим по классике. Django. Как нам теперь вызвать `django-admin`, дорогие друзья? Ну, просто при помощи `uv run`. `uv run django-admin startproject myproject`. Хоп! Здесь `manage.py`. Как нам при помощи `manage.py` создать проект? Опять же, `uv run manage.py startapp first_app`. Создаём `first_app`. Как нам теперь запустить сервер? Пожалуйста, `uv run manage.py runserver`. Великолепно! Всё работает, дорогие друзья. Очень удобно, очень удобно, дорогие друзья. Мне, мне очень нравится то, что не надо работать напрямую с виртуальным окружением, и что uv работает с ним под капотом. И ещё мне, конечно, очень нравится, что это one tool, это одна утилита, которая умеет управлять версиями Python и управляет всеми зависимостями, умеет разрешать конфликты и так далее. Очень удобненько, дорогие друзья!

Также можно для одного конкретного скрипта указать зависимости, опять же, без создания виртуального окружения. Вот прямо `uv run --with <какая-какая библиотека>`. Мы хотим с какой библиотекой мы хотим запустить наш скрипт. В данном случае мы хотим запустить `httpx`. Можно указать версию `httpx 0.26.0`. Можно убрать версию, да? И запускаем, что мы запускаем? `python` и просто передаём команду, при помощи, при помощи, передаём команду, которую нам необходимо выполнить. И `httpx.get("http://httpbin.org/get")` и берём первое, значит, сколько-то там символов из ответа. Обратите внимание, скачался `httpx`, установился куда-то там внутри uv, совершенно неважно куда, и этот код просто вызвался. Блин, ну скажите классно! Скажите классно! Это очень красиво. Но, дорогие друзья, это, это, конечно, красиво, но это ещё так сказать, полдела. Полдела. Часто используется ведь для написания каких-то скриптов. То есть вот нам надо сделать какую-нибудь задачку, и мы можем написать это на Bash или там на Zsh, или мы можем написать это на Python. Я люблю Python, поэтому я бы в большинстве случаев написал бы это на Python. Но зачастую то, что мы пишем на Python, оно опять же не работает изолировано от всех библиотек, которые, которые есть. То есть нам нужно что-то ещё через там `pip install` добавить, да? И добавлять это в системный Python, конечно, неправильно. То есть мы вынуждены для каких-то вот таких маленьких скриптиков всё-таки создавать виртуальное окружение ручками, там, что как-то его активировать и так далее. Неудобно, неудобно, дорогие друзья. И на самом деле uv позволяет версию Python прописать в файле, прямо в скрипте. `#!/usr/bin/env python`. Да, и указать там те зависимости, которые нужны этому скрипту для запуска этого скрипта. Прикиньте, что? И не нужно писать никакие там, значит, виртуальные окружения и так далее. Очень удобно. Давайте вам покажу, как это дело происходит. Есть у меня вот. Давайте я вам покажу. Ну, собственно, при помощи Bash, да, небольшой новский скрипти, буквально вот на там типа 46 строчек. Что он делает? Он нумерует файлы. То есть я пишу `course` в программе OBS, это просто набор файлов, и все уроки пронумерованы, да? `01. Название урока.md`, `02.`. Ну, я сейчас вам покажу, как это выглядит. Вот, например, вот таким вот образом может выглядеть, да? Вот здесь шесть файлов, это они пронумерованы 1, 2, 4, 5, 6 и так далее. Это номера уроков. Вот что если я вставлю в уроки ещё один урок? Да, если я сюда вставлю ещё один урок, то мне все последующие уроки придётся перенумеровать.

Речь сейчас не об этом, дорогие друзья. Давайте мы добавим в директорию новый файлик, назовём его `02.2.md`. Значит, да, какой-то новый урок, какой-то новый урок. Хоп! Вот так вот, да? Хоп! Соответственно, если мы посмотрим теперь директорию `files`, то вот нам теперь нужно как-то это так сказать, перенумеровать. Если мы посмотрим, что у нас лежит в этой директории, то у нас здесь нет виртуального окружения. И по большому, ну, у нас есть, да? То есть по большому счёту нам теперь нужно создавать здесь виртуальное окружение, вот, устанавливать на, устанавливать `tabulate`, активировать виртуальное окружение, бла-бла-бла. Неудобненько. Давайте просто запустим это при помощи uv. Запускаем `uv run --with net-sort,tabulate` на то есть с библиотекой натуральной сортировки `tabulate`, с библиотекой `tabulate`, запускаем `number_files` и передаём туда флаг, значит, параметр `--simulate` для того, чтобы программа симулировала свою работу, то есть реального переименования файлов пока не делал, просто показал нам, как какие файлы переименуют. Запускаем. Обратите внимание, `resolving dependencies`, то есть uv сейчас потянул `net-sort`, подтянул `tabulate`, да, установил их куда-то себе. Мы это так сказать, не устанавливали, никакое виртуальное окружение не собирали, не активировали, да? Но при этом мы просто запустили скрипт с теми зависимостями, которые нам нужны. Но это же просто песня, дорогие друзья! Это же просто песня! Да, вот у нас было `01`, `02` и `02.2`, `03`, `04`, `05`, `06`. Теперь всё чётенько пронумеровано: `01`, `02`, `03`, `04`, `05`, `06`. Ну, в данном случае у нас не пронумеровано, потому что мы симулировали. Если мы симуляцию уберём, то всё будет хорошо. Можно даже добавить вот ещё параметр `--chapter 12`. У нас типа это в двенадцатой главе. То есть были номера вот такие: `01`, `02`, и `02.2`, `03`, `04`. А теперь будет `12.01`, `12.02`, `12.03` и так далее. Скажите, классно? Скажите, классно! Но это всё-таки какая-то длинная, сложная команда. Какая-то длинная, сложная команда, да? Что если мы в `number_files` пропишем ту версию Python, которая нам нужна, и пропишем те зависимости, которые нам нужны этому Python файлу прямо здесь, чтобы это был прямо один файл, и при помощи uv его можно было, чтобы запустить? uv даёт такие возможности. Давайте посмотрим, как это работает. Просто в начало файла вставляем вот такую вот конструкцию. Да, это просто комментарий с точки зрения синтаксиса Python, но uv найдёт этот комментарий, разберёт его, распарсит и поймёт, что здесь на самом деле требуется для запуска этой штуки: Python больше чем 3.13 и нужны две зависимости: `net-sort` и `tabulate`, дорогие друзья. Давайте перейдём в, значит, мы запускали при помощи вот такой команды. Теперь мы просто уберём, потому что это всё у нас прописано на самом деле в `number_files`, и запустим. И всё тоже по-прежнему замечательным образом работает. Скажите, классно? Скажите, классно! Но при этом, конечно же, мы можем убрать и сам параметр `uv run`, потому что можем просто файл, значит, `number_files` прописать вот такой вот, дорогие друзья, `#!/usr/bin/env python`. И замечательно. И теперь мы можем просто напрямую запускать, запускать эту команду, да? То есть вместо `uv run` просто напрямую запускаем `number_files`. Хоп! Это замечательным образом работает. Почему это работает? Ну, собственно, потому что на `number_files` накинуты права на исполнение. Вот мы видим это право, у нас есть для текущего пользователя, дорогие друзья. Классно? Просто классно! То есть, по сути, к чему мы приходим? Мы приходим к тому, что у нас есть, значит, один Python-ский файл, в котором мы описываем всю необходимую логику. И в нём, в начале, мы описываем, какая версия Python нам нужна. Если эта версия Python не установлена на компьютере, на котором нам надо запустить, но там есть uv, uv просто установит необходимую версию Python. И uv установит все необходимые зависимости и запустит наш код. Блин, ну это просто очень круто! Я считаю, что это очень круто. То есть вот, ну, вот для каких-то таких сценариев, которые я показываю, это прям просто песня, песня.

Так, чудненько, дорогие друзья. Давайте перейдём в наш проект обратно. В его такой инструмент `uvx`. `uvx` позволяет загружать и использовать так называемые Tools. Какие-то штуки, например, линтер R. Линтер R, который разрабатывает, кстати говоря, та же команда, которая сделала и uv. Это замечательный линтер, который тоже написан на Rust. Мы о нём поговорим, наверное, в следующем видео. Ну, так вот, `uvx ruff`. Допустим, вот мы запускаем. У нас `ruff` есть, и мы можем просто его использовать. `ruff check .` И у нас так сказать, проверил текущий, значит, код, который нам сгенерирован, какие-то штуки, которые не используются. Да? `but not`. Ну, мы можем это просто пофиксить, передав в замечательные параметры. Хоп! `ruff check --fix .` То есть нашёл четыре ошибки и их поправил. Когда мы запустим снова, то всё замечательным образом проходит. Великолепно! При этом, если мы посмотрим на `pyproject.toml`, то там мы никакого `ruff` не увидим, потому что мы установили, ну, как бы глобально внутри. Если нам что-то необходимо установить в сам проект для того, чтобы запускалось внутри проекта с какими-то знаниями о проекте, о тех пакетах, просто передаём как dependency. Да? Ну, если это именно dependency, да, какой-нибудь. Ну, собственно, не приходит других мыслей, кроме `pip install`. Инструментик, да? Хоп! У нас замечательным образом установилось. Обратите внимание, да, в директории выше, в `project`, появился dependency `ruff`. И вот у нас есть замечательный `ruff`, который можем здесь запустить. Запустился в этом проекте. Также, дорогие друзья, если мы откроем, например, `main.py`, то мы видим, что здесь `requests`, и он есть в нашем типа виртуальном окружении, которым управляет uv. Но `PyCharm` мой не знает. `PyCharm` у меня здесь настроена, значит, да, `pyright` LSP сервер, который проверяет все зависимости и так сказать, всякие разные умные штуки позволяет здесь делать. Ну, так вот, как же так сказать, `PyCharm` рассказать о том, что на самом деле виртуальное окружение есть и где его необходимо искать? Собственно, для этого нам нужно создать файлик `.vscode/settings.json` и прописать в нём вот такой вот `python.venvPath`. Хоп! Да, и `.uv/venv`. Потому что в данном случае у нас виртуальное окружение лежит в директории `.uv/venv`. Теперь давайте в `main.py` зайдём, и всё. Теперь у нас так сказать, `PyCharm` уже видит виртуальное окружение, видит правильный интерпретатор, правильные версии со всеми библиотечками. Всё по красоте, да? То есть `requests` и вот у нас, пожалуйста, подсказки, подсказки от замечательного `PyCharm`. Красота!

Также, если у нас есть старенький файлик `requirements.txt`, в котором лежат зависимости, которые получились в результате команды `pip freeze`, да, ну, старенький файлик, старенький какой-нибудь проект, то мы можем установить это точно так же, не обязательно через `pip`, но через uv это будет быстрее. То есть в uv есть специальный режим совместимости с `pip`. Да, вот, пожалуйста, `uv pip install -r requirements.txt`. В реальности это будет установлено быстро при помощи uv, дорогие друзья.

Вот такой вот замечательный инструмент uv, дорогие друзья. Если вдруг вы о нём не знали, если вдруг вы его ещё не использовали, всячески рекомендую попрактиковаться, познакомиться и затащить на ваши проекты, потому что штука, штука классная, штука быстрая, штука современная и, ну, фактически, наверное, уже можно сказать, что это стандарт уже в управлении пакетами, в управлении зависимостями на Python. Ruff, в какой-то степени, сейчас тоже уже становится стандартом. О нём мы поговорим в следующем, наверное, видео. Это линтер, который пишет та же самая команда, которая делает и uv. Замечательный, быстрый линтер для Python, написанный на Rust. Вот просто Blazing Fast, то же самое. Вот. Ну и те же самые ребята, на самом деле, пишут ещё сейчас статический анализатор типов, как `mypy` и `pyright`, но, судя по всему, тоже на Rust. И, судя по всему, тоже Blazing Fast и современный, вкусный, замечательный, бодрый статический анализатор типов. Я вот так сказать, жду не дождусь, когда они это выпустят, чтобы это потестить. Дорогие друзья, очень, очень мне интересно, как это всё будет выглядеть и работать. Спасибо, что посмотрели. Надеюсь, что чем-то было вам здесь полезно, интересно. Спасибочки! Остаёмся на связи и до следующего выпуска. Пока-пока, пока-пока!