Как стать автором
Обновить

Лучшие open-source инструменты для Python проектов

Время прочтения 12 мин
Просмотры 18K
Open source *Python *Django *Flask *
Из песочницы
✏️ Технотекст 2022

"Give me six hours to chop down a tree and I will spend the first four sharpening the axe."

Open-source проекты, сторонние инструменты и библиотеки - это то, за что мы действительно любим Python. В этой статье я собрал самые полезные, валидированные сообществом и проверенные временем инструменты, конфигурации которых можно встретить в популярных проектах с открытым исходным кодом.

Инструменты распределены по этапам/сферам разработки. По каждому из них я дам небольшое описание и попытаюсь рассказать о его пользе. Если утилита имеет дополнительные расширения/плагины, то я расскажу про самые полезные (на мой взгляд).

Личный проект

Как пример интеграции инструментов из этой статьи, можно открыть репозиторий с исходным кодом моего проекта. HackerNews Alerts Bot (GitHub) - Telegram-бот для получения различных уведомлений с форума Hacker News. Помимо просмотра конфигураций, чтобы быть в курсе актуальных новостей и статей, можно запустить этот бот и подписаться на уведомления о новых постах по ключевому слову. Например, чтобы подписаться на посты о Python, введите: /add python -stories.

Список инструментов

  1. Конвейер интеграции

    1.1 pre-commit

  2. Управление зависимостями

    2.1 pip-compile

  3. Качество кода

    3.1 flake8

    3.2 Black

    3.3 isort

    3.4 Mypy

    3.5 Ruff: замена flake8 и isort

  4. Тестирование

    4.1 pytest

  5. Дебаггинг

    5.1 PySnooper

  6. Терминал

    6.1 IPython

    6.2 Rich

1. Конвейер интеграции

Чтобы успешно интегрировать инструменты из этой статьи в Python проект нам необходима надежная система, которая возьмет на себя работу по их установке, обновлению и запуске при наступлении определенного события. State of the art инструментом в этой категории безусловно является pre-commit.

1.1 pre-commit

pre-commit — это фреймворк, использующий git pre-commit hook для запуска хуков (инструментов) перед созданием коммита. Помимо запуска инструментов, pre-commit также берет на себя их установку и обновление.

pre-commit пользуется большой популярностью среди open-source Python проектов, например .pre-commit-config.yaml может быть найден в репозиториях наиболее популярных веб-фреймворков: Django, Flask и FastAPI. Это тот самый инструмент, конфиг которого я добавляю первым в новый проект.

Гайд по установке, Quick start и другая полезная информация доступна в документации.

В следующем разделе я расскажу о расширениях, которые обязательно пригодятся в вашей конфигурации. Хуки инструментов из этой статьи указаны в разделе «pre-commit хук» соответствующей утилиты.

Полезные хуки

Стандартная конфигурация уже имеет некоторые расширения из pre-commit-hooks репозитория. Кроме того, репозиторий содержит достаточное количество готовых хуков, которые можно легко добавить в .pre-commit-config.yaml.

pyupgrade

pyupgrade — это хук от создателя pre-commit для автоматического обновления синтаксиса языка. Например, pyupgrade перепишет простые вызовы str.format() в f-strings.

Добавить расширение в конфиг pre-commit:

-   repo: <https://github.com/asottile/pyupgrade>
    rev: v3.3.1
    hooks:
    -   id: pyupgrade

typos

typos — spell-checker, написанный на rust, для проверки исходного кода. Хук отличается высокой скоростью проверки и минимальным количеством ложных срабатываний.

-   repo: <https://github.com/crate-ci/typos>
    rev: v1.13.4
    hooks:
    -   id: typos

Документация

Репозиторий

pre-commit-hooks

pyupgrade

typos

2. Управление зависимостями

С управлением зависимостей в Python не все однозначно. Poetry, pipenv, conda - все эти библиотеки являются популярным выбором среди пользователей языка. Моя причина выбора pip-compile довольно-таки проста: pip-compile позволяет мне пользоваться стандартными инструментами (venv и pip), решая основные проблемы управления зависимостями. Ни больше ни меньше.

2.1 pip-compile

Зачем нужен pip-compile?

Перечислю несколько проблем, возникающих при заморозке зависимостей с помощью pip freeze:

  1. Нельзя определить, откуда взялась какая-либо из зависимостей, так как pip freeze сохраняет все вперемешку (Пакеты, от которых наш проект зависит напрямую, и зависимости этих пакетов).

  2. Добавляя новый пакет в requirements.txt, мы не фиксируем его собственные зависимости. Новые версии этих незакрепленных библиотек могут привести к трате времени на дебаггинг таких обновлений.

  3. Редактирование версии пакета в requirements.txt оставляет без внимания зависимости этой библиотеки. Новые пакеты не добавляются, а старые - не удаляются, что снова приводит к проблемам на этапе сборки.

Для решения этих проблем нам нужно хранить два файла с зависимостями. Первый файл (requirements.in) будет содержать пакеты, которые мы будем добавлять вручную. Во втором файле (requirements.txt) будут храниться закрепленные версии каждой библиотеки нашего проекта, включая пакеты, добавленные вручную (и их зависимости). Список библиотек requirements.in нужен для генерации второго файла, того самого requirements.txt, который мы используем при сборке проекта.

pip-compile - это инструмент, с помощью которого можно осуществить такой подход управления зависимостями.

Управление зависимостями с помощью pip-compile

pip-compile - это одна из утилит пакета pip-tools, поэтому, чтобы начать им пользоваться, установим эту библиотеку (PyPI).

После установки пакета создайте файл 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. Также в pip-tools присутствует команда pip-sync - синхронизация виртуального окружения с requirements.txt. Используйте ее с особой осторожностью, pip-sync удаляет все зависимости неупомянутые в requirements.txt.

pre-commit хук

-   repo: <https://github.com/jazzband/pip-tools>
    rev: 6.12.0
    hooks:
    -   id: pip-compile

Документация

Репозиторий

PyPi

pip-sync

3. Качество кода

Под инструментами качества кода подразумеваются линтеры, средства форматирования и проверки кода. Здесь указан полный набор инструментов, которые дополнят друг друга при минимальной настройке конфигураций. Ну и конечно же, все они поместятся в наш кейс (pre-commit).

3.1 flake8

flake8 — это инструмент, сканирующий код проекта на наличие ошибок и соответствие заданным стандартам. По сути, это полноценный линтер, использующий под капотом три других утилиты (pycodestyle, pyflakes и mccabe), который также может быть расширен с помощью пользовательских плагинов.

flake8 используется в Django, Flask и многих других open-source проектах. За время существования (flake8 появился в 2010) было создано множество различных плагинов. Про некоторые из них я расскажу в разделе «Полезные плагины».

Про настройку конфига и игнорирование ошибок можно почитать в официальной документации.

pre-commit хук

Хук flake8 должен быть указан после средств форматирования кода (Black, isort, и т. д.). В противном случае линтер будет ругаться на ошибки, которые будут автоматически исправлены этими инструментами.

-   repo: <https://github.com/pycqa/flake8>
    rev: 6.0.0
		hooks:
		-   id: flake8

Полезные плагины

flake8 сам по себе неплохой линтер, но его полный потенциал можно раскрыть при использовании сторонних плагинов.

flake8-bugbear

flake8-bugbear — это плагин, содержащий дополнительные проверки на наличие ошибок и возможные проблемы с дизайном кода. Поддерживается разработчиками flake8.

Пример хука с добавленным плагином:

-   repo: <https://github.com/pycqa/flake8>
    rev: 6.0.0
		hooks:
		-   id: flake8
				additional_dependencies:
				-   flake8-bugbear

flake8-print

flake8-print — проверка на наличие вызовов print(). Поможет предотвратить коммиты со строками отладки.

-   repo: <https://github.com/pycqa/flake8>
    rev: 6.0.0
		hooks:
		-   id: flake8
				additional_dependencies:
				-   flake8-bugbear
				-   flake8-print

Полноценный список валидированных расширений можно найти в awesome-flake8-extensions репозитории.


Документация

Репозиторий

flake8-bugbear

flake8-print

awesome-flake8-extensions

3.2 Black

Black — это инструмент форматирующий код на основе стандарта PEP 8.

Несмотря на то, что проект вышел из беты только в этом году, Black уже используется многими известными компаниями и популярными open-source проектами: Django, Facebook, Mozilla, pandas и т. д. Кроме того, проект официально поддерживается Python Software Foundation, организацией, занимающейся разработкой Python.

Контроль над конфигурацией инструмента у вас будет минимальный. Это философия проекта. Но все же некоторые настройки можно подстроить под ваши нужды. Всю необходимую информацию для установки, интеграции и настройки Black можно найти в документации.

pre-commit хук

В документации есть поле language_version, но в нем нет необходимости, если вы указали версию Python через опцию конфига default_language_version.

-   repo: <https://github.com/psf/black>
    rev: 22.12.0
		hooks:
		-   id: black

Документация

Репозиторий

3.3 isort

Black хорош как инструмент приведения кода к общему стилю. Для организации строк импорта нам понадобится другая утилита.

isort — это средство форматирования кода, предназначенное для сортировки и группировки строк импорта на основе различных критериев. Библиотека была выпущена в 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"

Установка и настройка утилиты описана в документации.

pre-commit хук

-   repo: <https://github.com/pycqa/isort>
    rev: 5.11.2
		hooks:
		-   id: isort

Документация

Репозиторий

3.4 Mypy

Тема статической проверки типов продолжает набирать обороты в Python. Самым популярным и развитым инструментом в этой категории является Mypy - open-source проект, разрабатываемый самим сообществом языка.

Основной стимул для использования Mypy - это нахождение багов, которые не подстать обычным линтерам. Инвестируя в аннотации и статическую типизацию, мы не только отлавливаем ошибки до их появления в runtime, но и в итоге получаем более надежный и читабельный код.

Так как наверняка ваш проект включает множество сторонних библиотек, то для эффективного использования Mypy необходимо скачать пакеты заглушек. Например, для проверки типов Django, мы можем установить заглушки django-stubs.

В отличие от большинства других инструментов, описанных в этой статье, Mypy и проверка типов - это обширная тема, требующая хотя бы базового изучения перед тем, как она сможет принести пользу. Документация Mypy включает руководство по началу работы, шпаргалку и справки по различным типам. Другую информацию по этой теме можно найти в awesome-python-typing репозитории.

pre-commit хук

-   repo: <https://github.com/pre-commit/mirrors-mypy>
    rev: v0.991
		hooks:
		-   id: mypy

Более подробно об интеграции Mypy с pre-commit в репозитории расширения.


Документация

Репозиторий

awesome-python-typing

mirrors-mypy

django-stubs

3.5 Ruff: замена flake8 и isort

Ruff — это новый, быстроразвивающийся линтер Python кода, призванный заменить flake8 и isort.

Основным преимуществом Ruff является его скорость. Ruff в 10-100 раз быстрее аналогов (Линтер написан на Rust). В сравнении с flake8, автор заявляет о практически полном совпадении с набором правил инструмента и нативной реализацией популярных плагинов (flake8-bugbear и т.д.). Также Ruff совместим с Black «из коробки».

Ruff может форматировать код. Например, он автоматически удаляет неиспользуемые импорты. Что касается сортировки и группировки строк импорта, то она практически идентична isort.

Несмотря на недавний выпуск инструмента (Август этого года), Ruff используется во многих популярных open-source проектах (FastAPI, Pydantic и т.д.).

Настройка инструмента осуществляется в pyproject.toml файле. Установка и конфигурация описана в README.md проекта.

Не могу не упомянуть, что Ruff - это один из инструментов, о котором я узнал благодаря уведомлению по ключевому слову «Python» в моем Telegram-боте.

pre-commit хук

-   repo: <https://github.com/charliermarsh/ruff-pre-commit>
    rev: v0.0.189
		hooks:
		-   id: ruff

Документация

Репозиторий

Telegram бот

4. Тестирование

Тестирование - это тот этап разработки, который сообщество точно не могло оставить в стороне. В этом разделе будет рассмотрен наиболее популярный инструмент для тестирования кода, возможности которого помогут эффективно писать качественные тесты.

4.1 pytest

pytest — это полноценный фреймворк, заменяющий unittest, стандартный модуль для написания unit-тестов.

Перечислю основные преимущества pytest:

  1. pytest значительно упрощает процесс тестирования кода. Для написания простых тестов нам не нужно ничего импортировать, достаточно использовать обычные функции с приставкой test_. Кроме того, pytest заменяет все self.assert* методы модуля unittest одним утверждением assert.

  2. Более информативный и читабельный вывод информации о ходе и результатах тестирования. Состояние системы, установленные плагины, детальный отчет при фейлах и т. д.

  3. Фикстуры вместо .setUp() и .tearDown(). Фикстуры в pytest - это функции, которые создают данные для набора тестов. Каждый тест может принимать фикстуры в качестве аргументов. Такой подход делает набор тестов более читаемым и структурированным.

  4. Возможность расширения фреймворка с помощью сторонних плагинов. За время существование проекта было создано более 800 плагинов.

По тестированию кода с помощью pytest написаны целые книги. Но для создания базовых тестов достаточно прочитать несколько статей из руководства по началу работы.


Сайт

Effective Python Testing With Pytest

5. Дебаггинг

pdb является отличным инструментом для отладки Python программ. Однако его настройка может занять некоторое время или даже оказаться невозможной (Удаленные контейнеры). PySnooper - это золотая середина между вызовами print() и полноценным, интерактивным отладчиком.

5.1 PySnooper

PySnooper — это декоратор, с помощью которого можно получить полный лог функции, включая изменения локальных переменных, отработавшие строки и время их выполнения.

Установить 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 и ADVANCED_USAGE.md файлах репозитория.


Репозиторий

Документация

Продвинутые возможности

6. Терминал

Оболочка Python в том или ином виде - это незаменимый инструмент для быстрого выполнения небольших фрагментов кода и манипуляций с данными. Апгрейд этой среды непременно повысит нашу производительность. А ещe в терминале мы можем читать логи, просматривать traceback’и ошибок и получать результаты команд. Все это можно вывести в форматированном виде с помощью библиотеки Rich.

6.1 IPython

IPython — это усовершенствованная оболочка Python. Инструмент содержит такие функции как «магические» команды, подсветку синтаксиса и продвинутый автокомплит.

Для использования новой оболочки нам всего лишь нужно установить пакет IPython:

pip install ipython

В следующих разделах я расскажу о некоторых функциях оболочки. За вводным руководством и другой полезной информацией можно обратиться к обширной документации инструмента.

Сохранение истории вывода

Одной из полезных функций 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 официальной документации.

Для замера времени выполнения кода существует команда %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

Репозиторий

PyPi

Документация

Built-in magic commands

6.2 Rich

Rich — это библиотека Python для вывода форматированного текста (цвет, стиль, подсветка синтаксиса, markdown) в терминал.

Rich поддерживает все платформы и терминалы. Это сверх популярная библиотека, которая используется для форматирование вывода в большинстве проектов (В том же pip, например).

Для работы с инструментом советую ознакомиться с документацией.

Полезные возможности

Progress display

Rich может отображать настраиваемый индикатор выполнения задач. По умолчанию будет отображаться описание задачи, процент выполнения, примерное оставшееся время и сам индикатор выполнения.

Rich Inspect

Кроме форматирования текста, библиотека содержит функцию для дебаггинга объектов Python. Пример использования:

from rich import inspect
from rich.color import Color


color = Color.parse("red")
inspect(color, methods=True)

Репозиторий

Документация

Progress display

Rich Inspect

Заключение

Практически каждый инструмент имеет свои «рабочие» альтернативы. Многие утилиты не были включены в этот список, так как я посчитал их слишком специфичными. Расскажите в комментариях, кто чем пользуется, возможно что-то упускаю и я!

На этом все. Надеюсь, статья была полезна, и вы узнали хотя бы об одном инструменте, который может быть задействован в ваших нынешних или будущих проектах.

Теги:
Хабы:
Всего голосов 41: ↑38 и ↓3 +35
Комментарии 9
Комментарии Комментарии 9

Публикации

Истории

Работа

Data Scientist
155 вакансий
Python разработчик
189 вакансий