- PVSM.RU - https://www.pvsm.ru -
"Give me six hours to chop down a tree and I will spend the first four sharpening the axe."
Open-source проекты, сторонние инструменты и библиотеки - это то, за что мы действительно любим Python. В этой статье я собрал самые полезные, валидированные сообществом и проверенные временем инструменты, конфигурации которых можно встретить в популярных проектах с открытым исходным кодом.
Инструменты распределены по этапам/сферам разработки. По каждому из них я дам небольшое описание и попытаюсь рассказать о его пользе. Если утилита имеет дополнительные расширения/плагины, то я расскажу про самые полезные (на мой взгляд).
Как пример интеграции инструментов из этой статьи, можно открыть репозиторий [1] с исходным кодом моего проекта. HackerNews Alerts Bot (GitHub [1]) - Telegram-бот для получения различных уведомлений с форума Hacker News [2]. Помимо просмотра конфигураций, чтобы быть в курсе актуальных новостей и статей, можно запустить этот бот и подписаться на уведомления о новых постах по ключевому слову. Например, чтобы подписаться на посты о Python, введите: /add python -stories
.
Конвейер интеграции
1.1 pre-commit
Управление зависимостями
2.1 pip-compile
Качество кода
3.1 flake8
3.2 Black
3.3 isort
3.4 Mypy
3.5 Ruff: замена flake8 и isort
Тестирование
4.1 pytest
Дебаггинг
5.1 PySnooper
Терминал
6.1 IPython
6.2 Rich
Чтобы успешно интегрировать инструменты из этой статьи в Python проект нам необходима надежная система, которая возьмет на себя работу по их установке, обновлению и запуске при наступлении определенного события. State of the art инструментом в этой категории безусловно является pre-commit.
pre-commit [3] — это фреймворк, использующий git pre-commit hook для запуска хуков (инструментов) перед созданием коммита. Помимо запуска инструментов, pre-commit также берет на себя их установку и обновление.
pre-commit пользуется большой популярностью среди open-source Python проектов, например .pre-commit-config.yaml
может быть найден в репозиториях наиболее популярных веб-фреймворков: Django, Flask и FastAPI. Это тот самый инструмент, конфиг которого я добавляю первым в новый проект.
Гайд по установке, Quick start и другая полезная информация доступна в документации [4].
В следующем разделе я расскажу о расширениях, которые обязательно пригодятся в вашей конфигурации. Хуки инструментов из этой статьи указаны в разделе «pre-commit хук» соответствующей утилиты.
Стандартная конфигурация уже имеет некоторые расширения из pre-commit-hooks репозитория [5]. Кроме того, репозиторий содержит достаточное количество готовых хуков, которые можно легко добавить в .pre-commit-config.yaml
.
pyupgrade
pyupgrade [6] — это хук от создателя pre-commit для автоматического обновления синтаксиса языка. Например, pyupgrade перепишет простые вызовы str.format()
в f-strings.
Добавить расширение в конфиг pre-commit:
- repo: <https://github.com/asottile/pyupgrade>
rev: v3.3.1
hooks:
- id: pyupgrade
typos
typos [7] — spell-checker, написанный на rust, для проверки исходного кода. Хук отличается высокой скоростью проверки и минимальным количеством ложных срабатываний.
- repo: <https://github.com/crate-ci/typos>
rev: v1.13.4
hooks:
- id: typos
Документация [4]
Репозиторий [3]
pre-commit-hooks [5]
pyupgrade [8]
typos [7]
С управлением зависимостей в Python не все однозначно. Poetry, pipenv, conda - все эти библиотеки являются популярным выбором среди пользователей языка. Моя причина выбора pip-compile довольно-таки проста: pip-compile позволяет мне пользоваться стандартными инструментами (venv и pip), решая основные проблемы управления зависимостями. Ни больше ни меньше.
Перечислю несколько проблем, возникающих при заморозке зависимостей с помощью pip freeze
:
Нельзя определить, откуда взялась какая-либо из зависимостей, так как pip freeze
сохраняет все вперемешку (Пакеты, от которых наш проект зависит напрямую, и зависимости этих пакетов).
Добавляя новый пакет в requirements.txt
, мы не фиксируем его собственные зависимости. Новые версии этих незакрепленных библиотек могут привести к трате времени на дебаггинг таких обновлений.
Редактирование версии пакета в requirements.txt
оставляет без внимания зависимости этой библиотеки. Новые пакеты не добавляются, а старые - не удаляются, что снова приводит к проблемам на этапе сборки.
Для решения этих проблем нам нужно хранить два файла с зависимостями. Первый файл (requirements.in
) будет содержать пакеты, которые мы будем добавлять вручную. Во втором файле (requirements.txt
) будут храниться закрепленные версии каждой библиотеки нашего проекта, включая пакеты, добавленные вручную (и их зависимости). Список библиотек requirements.in
нужен для генерации второго файла, того самого requirements.txt
, который мы используем при сборке проекта.
pip-compile - это инструмент, с помощью которого можно осуществить такой подход управления зависимостями.
pip-compile - это одна из утилит пакета pip-tools [9], поэтому, чтобы начать им пользоваться, установим эту библиотеку (PyPI [10]).
После установки пакета создайте файл requirements.in
. Сюда мы будем добавлять зависимости напрямую, например:
Flask
Теперь можно вызвать pip-compile
. Эта команда генерирует итоговый requirements.txt
файл:
$ pip-compile
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile
#
click==8.1.3
# via flask
flask==2.2.2
# via -r requirements.in
itsdangerous==2.1.2
# via flask
jinja2==3.1.2
# via flask
markupsafe==2.1.1
# via
# jinja2
# werkzeug
werkzeug==2.2.2
# via flask
Отклик команды выводит сгенерированное содержимое requirements.txt
. Комментарии в начале файла напоминают нам, как сгенерировать файл. Каждая зависимость зафиксирована. По самой структуре файла мы можем понять, почему был установлен тот или иной пакет.
pip-compile решает множество проблем, не привнося серьёзной абстракции в ваш проект. Все, что нужно для базового использования - это всего лишь запомнить одну команду.
Про конвертирование существующего requirements.txt
, описание процесса добавления/удаления зависимостей и обновление пакетов рассказано в документации pip-tools [11]. Также в pip-tools присутствует команда pip-sync [12] - синхронизация виртуального окружения с requirements.txt
. Используйте ее с особой осторожностью, pip-sync
удаляет все зависимости неупомянутые в requirements.txt
.
- repo: <https://github.com/jazzband/pip-tools>
rev: 6.12.0
hooks:
- id: pip-compile
Документация [11]
Репозиторий [9]
PyPi [10]
pip-sync [12]
Под инструментами качества кода подразумеваются линтеры, средства форматирования и проверки кода. Здесь указан полный набор инструментов, которые дополнят друг друга при минимальной настройке конфигураций. Ну и конечно же, все они поместятся в наш кейс (pre-commit).
flake8 [13] — это инструмент, сканирующий код проекта на наличие ошибок и соответствие заданным стандартам. По сути, это полноценный линтер, использующий под капотом три других утилиты (pycodestyle, pyflakes и mccabe), который также может быть расширен с помощью пользовательских плагинов.
flake8 используется в Django, Flask и многих других open-source проектах. За время существования (flake8 появился в 2010) было создано множество различных плагинов. Про некоторые из них я расскажу в разделе «Полезные плагины».
Про настройку конфига и игнорирование ошибок можно почитать в официальной документации [14].
Хук flake8 должен быть указан после средств форматирования кода (Black, isort, и т. д.). В противном случае линтер будет ругаться на ошибки, которые будут автоматически исправлены этими инструментами.
- repo: <https://github.com/pycqa/flake8>
rev: 6.0.0
hooks:
- id: flake8
flake8 сам по себе неплохой линтер, но его полный потенциал можно раскрыть при использовании сторонних плагинов.
flake8-bugbear
flake8-bugbear [15] — это плагин, содержащий дополнительные проверки на наличие ошибок и возможные проблемы с дизайном кода. Поддерживается разработчиками flake8.
Пример хука с добавленным плагином:
- repo: <https://github.com/pycqa/flake8>
rev: 6.0.0
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
flake8-print
flake8-print [16] — проверка на наличие вызовов print(). Поможет предотвратить коммиты со строками отладки.
- repo: <https://github.com/pycqa/flake8>
rev: 6.0.0
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
- flake8-print
Полноценный список валидированных расширений можно найти в awesome-flake8-extensions [17] репозитории.
Документация [14]
Репозиторий [13]
flake8-bugbear [15]
flake8-print [16]
awesome-flake8-extensions [17]
Black [18] — это инструмент форматирующий код на основе стандарта PEP 8.
Несмотря на то, что проект вышел из беты только в этом году, Black уже используется многими известными компаниями и популярными open-source проектами: Django, Facebook, Mozilla, pandas и т. д. Кроме того, проект официально поддерживается Python Software Foundation, организацией, занимающейся разработкой Python.
Контроль над конфигурацией инструмента у вас будет минимальный. Это философия проекта. Но все же некоторые настройки можно подстроить под ваши нужды. Всю необходимую информацию для установки, интеграции и настройки Black можно найти в документации [19].
В документации есть поле language_version, но в нем нет необходимости, если вы указали версию Python через опцию конфига default_language_version.
- repo: <https://github.com/psf/black>
rev: 22.12.0
hooks:
- id: black
Документация [19]
Репозиторий [18]
Black хорош как инструмент приведения кода к общему стилю. Для организации строк импорта нам понадобится другая утилита.
isort [20] — это средство форматирования кода, предназначенное для сортировки и группировки строк импорта на основе различных критериев. Библиотека была выпущена в 2013 году. С тех пор isort стал основным инструментом сортировки импортов для большинства популярных open-source проектов.
Пример форматирования кода с помощью isort:
from __future__ import absolute_import
import os
import sys
from third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8,
lib9, lib10, lib11, lib12, lib13, lib14, lib15)
from my_lib import Object, Object2, Object3
print("Hey")
print("yo")
Для интеграции инструмента вместе с black в конфигурации файла укажите профиль с одноименным названием:
[tool.isort]
profile = "black"
Установка и настройка утилиты описана в документации [21].
- repo: <https://github.com/pycqa/isort>
rev: 5.11.2
hooks:
- id: isort
Документация [21]
Репозиторий [20]
Тема статической проверки типов продолжает набирать обороты в Python. Самым популярным и развитым инструментом в этой категории является Mypy [22] - open-source проект, разрабатываемый самим сообществом языка.
Основной стимул для использования Mypy - это нахождение багов, которые не подстать обычным линтерам. Инвестируя в аннотации и статическую типизацию, мы не только отлавливаем ошибки до их появления в runtime, но и в итоге получаем более надежный и читабельный код.
Так как наверняка ваш проект включает множество сторонних библиотек, то для эффективного использования Mypy необходимо скачать пакеты заглушек. Например, для проверки типов Django, мы можем установить заглушки django-stubs [23].
В отличие от большинства других инструментов, описанных в этой статье, Mypy и проверка типов - это обширная тема, требующая хотя бы базового изучения перед тем, как она сможет принести пользу. Документация Mypy [24] включает руководство по началу работы, шпаргалку и справки по различным типам. Другую информацию по этой теме можно найти в awesome-python-typing [25] репозитории.
- repo: <https://github.com/pre-commit/mirrors-mypy>
rev: v0.991
hooks:
- id: mypy
Более подробно об интеграции Mypy с pre-commit в репозитории [26] расширения.
Документация [24]
Репозиторий [22]
mirrors-mypy [26]
django-stubs [23]
Ruff [27] — это новый, быстроразвивающийся линтер Python кода, призванный заменить flake8 и isort.
Основным преимуществом Ruff является его скорость. Ruff в 10-100 раз быстрее аналогов (Линтер написан на Rust). В сравнении с flake8, автор заявляет о практически полном совпадении с набором правил инструмента и нативной реализацией популярных плагинов (flake8-bugbear и т.д.). Также Ruff совместим с Black «из коробки».
Ruff может форматировать код. Например, он автоматически удаляет неиспользуемые импорты. Что касается сортировки и группировки строк импорта, то она практически идентична isort.
Несмотря на недавний выпуск инструмента (Август этого года), Ruff используется во многих популярных open-source проектах (FastAPI, Pydantic и т.д.).
Настройка инструмента осуществляется в pyproject.toml
файле. Установка и конфигурация описана в README.md [28] проекта.
Не могу не упомянуть, что Ruff - это один из инструментов, о котором я узнал благодаря уведомлению по ключевому слову «Python» в моем Telegram-боте [1].
- repo: <https://github.com/charliermarsh/ruff-pre-commit>
rev: v0.0.189
hooks:
- id: ruff
Документация [28]
Репозиторий [29]
Telegram бот [1]
Тестирование - это тот этап разработки, который сообщество точно не могло оставить в стороне. В этом разделе будет рассмотрен наиболее популярный инструмент для тестирования кода, возможности которого помогут эффективно писать качественные тесты.
pytest [30] — это полноценный фреймворк, заменяющий unittest, стандартный модуль для написания unit-тестов.
Перечислю основные преимущества pytest:
pytest значительно упрощает процесс тестирования кода. Для написания простых тестов нам не нужно ничего импортировать, достаточно использовать обычные функции с приставкой test_. Кроме того, pytest заменяет все self.assert* методы модуля unittest одним утверждением assert.
Более информативный и читабельный вывод информации о ходе и результатах тестирования. Состояние системы, установленные плагины, детальный отчет при фейлах и т. д.
Фикстуры вместо .setUp()
и .tearDown()
. Фикстуры в pytest - это функции, которые создают данные для набора тестов. Каждый тест может принимать фикстуры в качестве аргументов. Такой подход делает набор тестов более читаемым и структурированным.
Возможность расширения фреймворка с помощью сторонних плагинов. За время существование проекта было создано более 800 плагинов.
По тестированию кода с помощью pytest написаны целые книги. Но для создания базовых тестов достаточно прочитать несколько статей из руководства [31] по началу работы.
Сайт [32]
Effective Python Testing With Pytest [33]
pdb является отличным инструментом для отладки Python программ. Однако его настройка может занять некоторое время или даже оказаться невозможной (Удаленные контейнеры). PySnooper - это золотая середина между вызовами print() и полноценным, интерактивным отладчиком.
PySnooper [34] — это декоратор, с помощью которого можно получить полный лог функции, включая изменения локальных переменных, отработавшие строки и время их выполнения.
Установить PySnooper:
pip install pysnooper
Пример использования декоратора с рекурсивной функцией:
import pysnooper
@pysnooper.snoop()
def fact(x):
return x if x == 1 else x * fact(x - 1)
Вывод:
Source path:... .../example.py
Starting var:.. x = 4
23:55:58.173212 call 49 def fact(x):
23:55:58.173320 line 50 return x if x == 1 else x * fact(x - 1)
Starting var:.. x = 3
23:55:58.173367 call 49 def fact(x):
23:55:58.173420 line 50 return x if x == 1 else x * fact(x - 1)
Starting var:.. x = 2
23:55:58.173463 call 49 def fact(x):
23:55:58.173515 line 50 return x if x == 1 else x * fact(x - 1)
Starting var:.. x = 1
23:55:58.173556 call 49 def fact(x):
23:55:58.173610 line 50 return x if x == 1 else x * fact(x - 1)
23:55:58.173643 return 50 return x if x == 1 else x * fact(x - 1)
Return value:.. 1
Elapsed time: 00:00:00.000146
23:55:58.173727 return 50 return x if x == 1 else x * fact(x - 1)
Return value:.. 2
Elapsed time: 00:00:00.000324
23:55:58.173807 return 50 return x if x == 1 else x * fact(x - 1)
Return value:.. 6
Elapsed time: 00:00:00.000499
23:55:58.173886 return 50 return x if x == 1 else x * fact(x - 1)
Return value:.. 24
Elapsed time: 00:00:00.000740
Логирование части кода можно осуществить с помощью with
блока:
import pysnooper
import random
def foo():
lst = []
for i in range(10):
lst.append(random.randrange(1, 1000))
with pysnooper.snoop():
lower = min(lst)
upper = max(lst)
mid = (lower + upper) / 2
print(lower, mid, upper)
Сохранение логов в файл, логирование глобальных переменных и другую информацию по особенностям PySnooper можно найти в README.md [35] и ADVANCED_USAGE.md [36] файлах репозитория.
Репозиторий [34]
Документация [35]
Оболочка Python в том или ином виде - это незаменимый инструмент для быстрого выполнения небольших фрагментов кода и манипуляций с данными. Апгрейд этой среды непременно повысит нашу производительность. А ещe в терминале мы можем читать логи, просматривать traceback’и ошибок и получать результаты команд. Все это можно вывести в форматированном виде с помощью библиотеки Rich.
IPython [37] — это усовершенствованная оболочка Python. Инструмент содержит такие функции как «магические» команды, подсветку синтаксиса и продвинутый автокомплит.
Для использования новой оболочки нам всего лишь нужно установить пакет IPython [38]:
pip install ipython
В следующих разделах я расскажу о некоторых функциях оболочки. За вводным руководством и другой полезной информацией можно обратиться к обширной документации [39] инструмента.
Одной из полезных функций IPython является кеширование результатов вывода. Через нумерацию Out мы можем повторно использовать любой из предыдущих результатов:
In [3]: "пример"
Out[3]: 'пример'
In [4]: print(f" {_3} кеширования результатов вывода")
пример кеширования результатов вывода
In [5]: 10
Out[5]: 10
In [6]: _5 + 10
Out[6]: 20
В этом разделе я указал пару команд, которые я использую постоянно. Список полезных команд не ограничивается этими двумя. Все доступные «магические» команды можно найти в разделе Built-in magic commands [40] официальной документации.
Для замера времени выполнения кода существует команда %timeit
:
In [8]: %timeit [i for i in range(10000)]
144 µs ± 1.8 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
Для вывода введенной информации мы можем вызвать команду %hist
:
In [9]: %hist
"пример"
print(f" {_3} кеширования результатов вывода")
5
_5 + 10
%timeit [i for i in range(10000)]
%hist
Репозиторий [37]
PyPi [38]
Документация [39]
Rich [41] — это библиотека Python для вывода форматированного текста (цвет, стиль, подсветка синтаксиса, markdown) в терминал.
Rich поддерживает все платформы и терминалы. Это сверх популярная библиотека, которая используется для форматирование вывода в большинстве проектов (В том же pip, например).
Для работы с инструментом советую ознакомиться с документацией [42].
Progress display
Rich может отображать настраиваемый индикатор выполнения задач [43]. По умолчанию будет отображаться описание задачи, процент выполнения, примерное оставшееся время и сам индикатор выполнения.
Rich Inspect
Кроме форматирования текста, библиотека содержит функцию [44] для дебаггинга объектов Python. Пример использования:
from rich import inspect
from rich.color import Color
color = Color.parse("red")
inspect(color, methods=True)
Репозиторий [41]
Документация [42]
Progress display [43]
Rich Inspect [44]
Практически каждый инструмент имеет свои «рабочие» альтернативы. Многие утилиты не были включены в этот список, так как я посчитал их слишком специфичными. Расскажите в комментариях, кто чем пользуется, возможно что-то упускаю и я!
На этом все. Надеюсь, статья была полезна, и вы узнали хотя бы об одном инструменте, который может быть задействован в ваших нынешних или будущих проектах.
Автор:
lawxls
Источник [45]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/381754
Ссылки в тексте:
[1] репозиторий: https://github.com/lawxls/HackerNews-Alerts-Bot
[2] Hacker News: https://news.ycombinator.com/
[3] pre-commit: https://github.com/pre-commit/pre-commit
[4] документации: https://pre-commit.com/#installation
[5] pre-commit-hooks репозитория: https://github.com/pre-commit/pre-commit-hooks
[6] pyupgrade: https://github.com/asottile/pyupgrade
[7] typos: https://github.com/crate-ci/typos
[8] pyupgrade: https://github.com/asottile/pyupgradehttps://github.com/asottile/pyupgrade
[9] pip-tools: https://github.com/jazzband/pip-tools
[10] PyPI: https://pypi.org/project/pip-tools/
[11] документации pip-tools: https://pip-tools.readthedocs.io/en/latest/
[12] команда pip-sync: https://github.com/jazzband/pip-tools/#example-usage-for-pip-sync
[13] flake8: https://github.com/PyCQA/flake8
[14] официальной документации: https://flake8.pycqa.org/en/latest/index.html#
[15] flake8-bugbear: https://github.com/PyCQA/flake8-bugbear
[16] flake8-print: https://github.com/JBKahn/flake8-print
[17] awesome-flake8-extensions: https://github.com/DmytroLitvinov/awesome-flake8-extensions
[18] Black: https://github.com/psf/black
[19] документации: https://black.readthedocs.io/en/stable/the_black_code_style/index.html
[20] isort: https://github.com/PyCQA/isort
[21] документации: https://pycqa.github.io/isort/index.html
[22] Mypy: https://github.com/python/mypy
[23] django-stubs: https://pypi.org/project/django-stubs/
[24] Документация Mypy: https://mypy.readthedocs.io/en/stable/
[25] awesome-python-typing: https://github.com/typeddjango/awesome-python-typing
[26] репозитории: https://github.com/pre-commit/mirrors-mypy
[27] Ruff: https://github.com/charliermarsh/ruff
[28] README.md: https://github.com/charliermarsh/ruff/blob/main/README.md
[29] Репозиторий: https://github.com/charliermarsh/ruffhttps://github.com/charliermarsh/ruff
[30] pytest: https://docs.pytest.org/en/7.2.x/
[31] руководства: https://docs.pytest.org/en/7.2.x/getting-started.html
[32] Сайт: https://docs.pytest.org/en/7.2.x/index.html
[33] Effective Python Testing With Pytest: https://realpython.com/pytest-python-testing/
[34] PySnooper: https://github.com/cool-RR/PySnooper
[35] README.md: https://github.com/cool-RR/PySnooper/blob/master/README.md
[36] ADVANCED_USAGE.md: https://github.com/cool-RR/PySnooper/blob/master/ADVANCED_USAGE.md
[37] IPython: https://github.com/ipython/ipython
[38] пакет IPython: https://pypi.org/project/ipython/
[39] документации: https://ipython.readthedocs.io/en/stable/index.html
[40] Built-in magic commands: https://ipython.readthedocs.io/en/stable/interactive/magics.html
[41] Rich: https://github.com/Textualize/rich
[42] документацией: https://rich.readthedocs.io/en/stable/introduction.html
[43] индикатор выполнения задач: https://rich.readthedocs.io/en/stable/progress.html
[44] функцию: https://rich.readthedocs.io/en/stable/reference/init.html?highlight=Rich%20Inspect#rich.inspect
[45] Источник: https://habr.com/ru/post/708916/?utm_source=habrahabr&utm_medium=rss&utm_campaign=708916
Нажмите здесь для печати.