Обзор инструментов для автоформатирования кода Python
Благодаря легко читаемому и понятному синтаксису Python вполне обоснованно стал самым востребованным языком программирования на сегодняшний день. Области его применения настолько разнообразны, что программная инженерия, машинное обучение и наука о данных используют его для решения самых разных сложных задач.
Один из немаловажных, но оставленных без должного внимания аспектов в написании чистого кода Python заключается в необходимости его качественного форматирования и проверок.
Достаточно сказать, что автоматизация коснулась всех сторон современной жизни, и нам не составит особого труда привнести ее и в процесс ревью кода.
В нашем распоряжении есть несколько инструментов, позволяющих сэкономить драгоценное время и умственную энергию, чтобы вложить их в более важные дела, чем форматирование кода перед каждым git commit .
Перечислим некоторые из них:
- хуки pre-commit ;
- black ;
- isort .
Рассмотрим поочередно каждый инструмент и научимся настраивать их для проекта Python.
Установка и применение хуков pre-commit
Хуки pre-commit делают ровно то, что указано в названии: запускают определенные скрипты, которые проверяют код на наличие ошибок и конечных пробелов, активируют инструменты форматирования и проводят другие полезные проверки в процессе ревью.
Мы исключим из сферы нашего внимания обычные хуки, а сосредоточимся только на двух важных из них.
Начнем с установки библиотеки (учитывая, что вы уже работаете в виртуальной среде):
pip install pre-commit
После установки проверяем версию с помощью данной команды. Если все работает должным образом, на выводе получаем номер версии.
$ pre-commit --versionpre-commit 2.17.0
Примечание. Для простой настройки инструментов автоформатирования необходимо наличие конфигурационного файла git в корневом каталоге проекта.
Именно этим мы сейчас и займемся.
Настройка конфигурационного файла
Согласно документации в проекте должен быть конфигурационный файл pre-commit с именем .pre-commit-config.yaml .
Теперь воспользуемся фрагментом кода с информацией о хуках, с которыми мы хотим работать. Прямо сейчас мы намерены запустить 2 из них: black и isort в файлах Python перед каждым коммитом.
А вот и их настройки:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 21.12b0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
rev: 5.10.1
hooks:
- id: isort
name: isort (python)
Проведем построчный анализ:
- Строки 5–7: Первая строка id пытается загрузить все файлы yaml для проверки синтаксиса; вторая — следит за тем, чтобы файлы заканчивались переводом строки и только одним; третья — проверяет наличие конечных пробелов.
- Строки 8–10: Настройка хука для black , который автоматически форматирует код Python и широко применяется во всей индустрии.
- Строки 12–16: Настройка для библиотеки isort , которая автоматически сортирует импорты в коде, избавляя программистов от необходимости делать это вручную.
С помощью следующей команды присоединяем их к конфигурации git , чтобы обеспечить их запуск перед каждым коммитом:
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
Без особых усилий мы успешно настроили хуки pre-commit для проекта!
Переходим к настройке black и isort . К счастью, для этого потребуется всего один конфигурационный файл.
Установка и настройка black и isort
Легко и просто устанавливаем эти две библиотеки:
pip install black isort
Из отлично написанной документации мы узнаем о назначении Black :
Black ускоряет процесс ревью кода, производя минимальные возможные различия. Код, отформатированный в Black , выглядит одинаково независимо от проекта, который вы читаете. Со временем принципы форматирования становятся понятными, что позволяет сосредоточиться на содержании.
isort также просто определяет области своего применения:
isort — это утилита/библиотека Python для сортировки импорта по алфавиту с автоматическим разделением на разделы и по типам.
Для настройки потребуется всего один файл pyproject.toml .
Размещаем в нем следующий контент:
[tool.black]
line-length = 109
target-version = ['py37']
[tool.isort]
profile = "black"
Вы можете менять не только длину строки в соответствии с личными или рабочими предпочтениями, но и другие настраиваемые переменные, предлагаемые Black .
Теперь поясним, почему мы непосредственно задействуем этот конкретный файл:
PEP 518 определяет pyproject.toml как конфигурационный файл, содержащий требования к системе сборки для проектов Python.
На практике данный файл в корневом каталоге проекта позволяет использовать “глобальную” конфигурацию проверки/ревизии кода для всего проекта.
Приступаем к их тестированию!
Тестирование хуков pre-commit
Написав или отредактировав код в нескольких файлах, выполняем дальнейшую последовательность простых действий, чтобы протестировать работоспособность прикрепленных хуков.
Сначала добавляем файлы или их комбинацию с помощью команды git add . в терминале.
Я провожу тестирование в одном из моих текущих проектов Django.
Выполняем git commit -m “a message here” и видим следующий результат:
Это значит, что файлы были изменены путем форматирования, выполненного хуком pre-commit .
При выполнении команды git status получаем следующее сообщение:
Файл views.py содержит несколько строк, измененных в результате выполнения хуков. Их следует просмотреть.
Так мы убедимся, что измененные файлы не будут автоматически зафиксированы. Это позволит просмотреть их еще раз и проверить корректность всех изменений.
В качестве преднамеренного шага pre-commit никогда не изменит область staging (подготовки к коммиту) версионного кода. Поскольку любой запускаемый хук может содержать ошибки, исправление которых после совершенного коммита обернется головной болью, нам предоставляется дополнительная возможность еще раз проверить и убедиться, что все в порядке.
Снова добавляем и фиксируем изменения в файлах:
git add .
git commit -m "your message here"
Итак, мы успешно зафиксировали внесенные в код изменения!
Заключение
Надеюсь, это краткое руководство дало вам представление о том, как использовать хуки pre-commit для автоформатирования без усилий и ручного вмешательства.
Полезные ресурсы
- Black docs
- isort docs
- Pre-commit hooks docs
- A GitHub issue that explains why that additional commit step is so necessary.
Благодарю за внимание! 🙂
- Работа с панелью индикаторов. Руководство программиста Python. Часть 3
- Внимание: работает пакет Python Tweepy!
- Осваиваем веб-скрэпинг на Python
7 пакетов Python для анализа и улучшения кода
• isort — это Python-утилита/библиотека для сортировки импорта по алфавиту, а также автоматического разделения его на разделы и по типам.
• black — это бескомпромиссный форматировщик кода на языке Python. Используя его, вы соглашаетесь отказаться от контроля над тонкостями ручного форматирования. Взамен Black дает вам скорость, детерминизм и свободу от придирок pycodestyle к форматированию. Вы сэкономите время и умственную энергию для решения более важных задач.
• flake8 — это инструмент линтинга для Python, который проверяет кодовую базу Python на наличие ошибок, проблем со стилем и сложностью. Библиотека Flake8 построена на базе трех инструментов: PyFlakes — проверяет кодовую базу Python на наличие ошибок. McCabe — проверяет кодовую базу Python на сложность. pycodestyle — проверяет кодовую базу Python на проблемы со стилем в соответствии с PEP8..
• interrogate — interrogate проверяет вашу кодовую базу на наличие отсутствующих документальных строк. Документация должна быть столь же важна, как и сам код. И она должна находиться внутри кода.
• Whispers — это инструмент статического анализа кода, предназначенный для разбора различных распространенных форматов данных в поисках жестко закодированных учетных данных и опасных функций. Whispers может работать в CLI или интегрироваться в конвейер CI/CD.
• hardcodes — это утилита для поиска строк, жестко заданных разработчиками в программах. Она использует модульный токенизатор, способный обрабатывать комментарии, любое количество обратных слэшей и практически любой синтаксис, который вы ему предложите.
• pylint — Pylint анализирует ваш код без его реального выполнения. Он проверяет наличие ошибок, соблюдает стандарты кодирования, ищет «запахи» кода и может дать рекомендации по его рефакторингу.
Стиль кода ¶
При написании кода, предназначенного для использования в составе Django, придерживайтесь этих стандартов кодирования.
Стиль Python ¶
- Пожалуйста, соблюдайте стиль отступа, определенный в файле .editorconfig . Мы рекомендуем использовать текстовый редактор с поддержкой EditorConfig, чтобы избежать проблем с отступами и пространством. Файлы Python используют 4 пробела для отступа, а файлы HTML — 2 пробела.
- За особыми исключениями соблюдайте рекомендации PEP 8 . Используйте flake8 для обнаружения подобных проблем. Обратите внимание, что наш файл setup.cfg содержит исключение определенных файлов (устаревшие модули, которые не нужно было бы исправлять, и некоторый код внешнего происхождения, который включает Django), а также исключение определенных проверок ошибок, которые мы не считаем серьезные нарушения. Помни это PEP 8 — это только руководство, основная цель — соблюдение стиля окружающего кода. Исключение из PEP 8 — это наши правила в отношении длины строк. Не ограничивайте строки кода 79 символами, если это означает, что код выглядит значительно уродливее или его труднее читать. Мы допускаем до 119 символов, так как это ширина обзора кода GitHub; все, что длиннее, требует горизонтальной прокрутки, что затрудняет просмотр. Эта проверка включается при запуске flake8 . Документация, комментарии и строки документации должны быть заключены в 79 символов, даже если PEP 8 предлагает 72.
- Используйте 4 пробела для отступа.
- Используйте четыре отступа для подвешивания вместо вертикального выравнивания:
raise AttributeError( 'Here is a multiline error message ' 'shortened for clarity.' )
Вместо того :
raise AttributeError('Here is a multiline error message ' 'shortened for clarity.')
def test_foo(): """ A test docstring looks like this (#123456). """ .
Импорт ¶
- Используйте isort для автоматизации сортировки импорта, следуя приведенным ниже инструкциям. Чтобы быть быстрым:
$ python -m pip install isort $ isort -rc .
. \> py -m pip install isort . \> isort -rc .
Это выполняется isort рекурсивно из текущего каталога, изменяя любые файлы, которые не соответствуют директивам. Если необходимо иметь несортированный импорт (например, чтобы избежать циклического импорта), используйте такой комментарий
import module # isort:skip
django / contrib / admin / example.py ¶
# future from __future__ import unicode_literals # standard library import json from itertools import chain # third-party import bcrypt # Django from django.http import Http404 from django.http.response import ( Http404, HttpResponse, HttpResponseNotAllowed, StreamingHttpResponse, cookie, ) # local Django from .models import LogEntry # try/except try: import yaml except ImportError: yaml = None CONSTANT = 'foo' class Example: # .
from django.views import View
вместо того
from django.views.generic.base import View
Стиль шаблонов ¶
- В коде шаблонов Django поместите один и только один пробел между фигурными скобками и содержимым тегов. Делать:
Стиль просмотра ¶
- В представлениях Django должен вызываться первый параметр представления функции request . Делать
def my_view(request, foo): # .
def my_view(req, foo): # .
Стиль моделей ¶
- Имена полей должны быть в нижнем регистре с использованием подчеркивания вместо CamelStyle. Делать
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40)
class Person(models.Model): FirstName = models.CharField(max_length=20) Last_Name = models.CharField(max_length=40)
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40) class Meta: verbose_name_plural = 'people'
class Person(models.Model): first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40) class Meta: verbose_name_plural = 'people'
Не делайте этого тоже:
class Person(models.Model): class Meta: verbose_name_plural = 'people' first_name = models.CharField(max_length=20) last_name = models.CharField(max_length=40)
- Все поля в базе
- Настраиваемые атрибуты менеджера
- class Meta
- def __str__()
- def save()
- def get_absolute_url()
- Любой другой индивидуальный метод
class MyModel(models.Model): DIRECTION_UP = 'U' DIRECTION_DOWN = 'D' DIRECTION_CHOICES = [ (DIRECTION_UP, 'Up'), (DIRECTION_DOWN, 'Down'), ]
Используя django.conf.settings ¶
Модули обычно не должны использовать настройки, хранящиеся на django.conf.settings их первом уровне (то есть оцениваемые при импорте модуля). Вот почему:
Ручная настройка параметров (т.е. не полагаясь на DJANGO_SETTINGS_MODULE переменная окружения) допускается и возможно следующим образом:
from django.conf import settings settings.configure(<>, SOME_SETTING='foo')
Однако, если параметр доступен до линии settings.configure , это не будет работать (внутренне, settings это один , LazyObject который настраивается автоматически , когда доступ к настройкам , если это не было сделано ранее).
Итак, если модуль содержит такой код
from django.conf import settings from django.urls import get_callable default_foo_view = get_callable(settings.FOO_VIEW)
… Затем импорт этого модуля приведет к настройке объекта settings . Это означает, что возможность импорта модуля на первом уровне из внешнего кода несовместима с возможностью вручную настраивать объект settings или делает это очень трудным при определенных обстоятельствах.
Вместо приведенного выше кода следует добавить уровень различия или косвенного обращения, например django.utils.functional.LazyObject , django.utils.functional.lazy() или lambda .
Разное ¶
- Отметьте все строки для перевода; см. документацию i18n для более подробной информации.
- Удалите операторы import , которые больше не используются, при редактировании кода. flake8 может идентифицировать этот импорт для вас. Если неиспользуемый импорт необходимо оставить для совместимости, поместите комментарий в конце строки, чтобы вы не промолчали. # NOQA flake8
- Всегда удаляйте все пустые места в конце строки в коде, потому что они добавляют символы без необходимости, создают визуальный беспорядок в исправлениях, а также могут иногда вызывать ненужные конфликты слияния. Некоторые среды разработки могут быть настроены на их автоматическое удаление, а большинство инструментов управления версиями можно настроить так, чтобы они выделялись на дисплеях различий.
- Не пишите свое имя в генерируемом вами коде. Наша политика заключается в том, чтобы помещать имена участников в файл, AUTHORS распространяемый с Django, вместо того, чтобы распространять их по всему коду. Возьмите на себя смелость включить свое имя в этот файл AUTHORS в свой патч, если вы делаете больше, чем просто тривиальное редактирование.
Стиль JavaScript ¶
Дополнительные сведения о стиле кода JavaScript, используемом Django, см . В разделе JavaScript .
Лучшие практики разработки на Python
Цель этой статьи — поделиться лучшими практиками разработки на Python. Вы узнаете, как настроить и использовать репозиторий Github. Я познакомлю вас с полезными инструментами для поддержания чистоты и правильности кода, покажу, как настроить репозиторий и включить в него ранее представленные инструменты для автоматизированной проверки CI (непрерывной интеграции).
В завершение мы соберем все это вместе в образце проекта. Заметьте, я не утверждаю, что список рекомендуемых практик Python-разработки является полным и единственно возможным. Просто хочу поделиться собственным профессиональным опытом работы инженером-программистом. Могу подтвердить, что многие крупные компании, которые разрабатывают ПО, следуют аналогичной схеме.
С учетом сказанного, перейдем непосредственно к содержательной части. Полный код можно найти здесь.
Используемые инструменты
В этом разделе перечислим инструменты, необходимые для разработки Python-репозитория.
poetry
Poetry — это удобный инструмент для управления версиями и зависимостями Python. С его помощью легко контролировать и корректировать версии, а также централизованно управлять зависимостями. Из всех способов сделать это рекомендую poetry. Теперь кратко о том, как использовать этот инструмент.
Основой управления зависимостями в poetry является файл pyproject.toml . В нашем проекте он начинается следующим образом:
[tool.poetry]
name = "Sample Python Project"
version = "0.1.0"
description = "Sample Python repository"
authors = ["hermanmichaels "]
[tool.poetry.dependencies]
python = "3.10"
matplotlib = "3.5.1"
mypy = "0.910"
numpy = "1.22.3"
pytest = "7.1.2"
black = "22.3.0"
flake8 = "4.0.1"
isort = "^5.10.1"
Как видите, заголовок определяет и раскрывает основные свойства проекта. За ним следует абзац, определяющий необходимые зависимости.
Нужно просто выполнить poetry install в терминале, и poetry автоматически создаст среду Python со всеми установленными зависимостями. Затем можно войти в него через poetry shell .
После добавления новой зависимости нужно запустить poetry update . Это создаст или обновит файл poetry.lock , который можно представить как двоичное представление вышеуказанных зависимостей. Его также нужно будет добавить в репозиторий, и описанный выше процесс установки требований использует этот файл.
isort
PEP 8, руководство по стилю для Python, определяет, как упорядочить импорты. Рекомендуется создавать следующие группы.
- Импорт стандартных библиотек (например, os и sys ).
- Импорт сторонних производителей (например, numpy ).
- Локальный, специфический для проекта импорт (например, различные файлы одного проекта).
Внутри этих групп импортированные инструменты должны быть отсортированы в алфавитном порядке.
isort — это инструмент, который позволяет не запоминать и не выполнять все это самостоятельно. Удобно то, что isort и большинство инструментов, представленных в следующих разделах, отлично работают с poetry. Можно даже задать их настройки в файле pyproject.toml . Для нашего случая установим следующее:
[tool.isort]
profile = "black"
py_version = 310
multi_line_output = 3
В дополнение к версии Python сообщаем isort, что будем работать с форматером black (см. следующий раздел), и определяем, как будут переформатироваться импорты, которые слишком длинны для одной строки.
black
black — это форматер Python-кода. Его запуск приводит к форматированию кода в соответствии с действующими соглашениями. Призывая всех разработчиков использовать его, мы обеспечиваем определенный, единый стиль кода. Подумайте об отступах строк, количестве пустых строк после функций и т. д.
Настройками также управляет poetry, а мы просто задаем:
[tool.black]
line-length = 80
target_version = ["py310"]
Т.е. указываем максимальную длину строки (80) и целевую версию Python.
flake8
flake8 — это линтер кода. Линтеры и форматеры кода близки по своему назначению, однако линтеры проверяют соблюдение определенных стилей и рекомендаций, но не форматируют код. flake8 выполняет несколько функций, одна из которых — проверка на соответствие ранее упомянутому стандарту PEP 8.
mypy
mypy — это статическая проверка типов Python. Как вы (наверняка) знаете, Python — динамически типизированный язык, то есть типы переменных определяются во время выполнения (в отличие от, например, C++). Эта гибкость, которую мы все ценим, имеет свои недостатки, такие как большая вероятность совершения ошибок без компилятора или аналогичного средства, выступающего в качестве первой линии обороны.
Поэтому в последние годы многие усилия направлены на то, чтобы сделать проверку типов в Python более строгой. mypy является такой программой проверки типов, следящей за правильным использованием переменных. В основном это происходит автоматически, но вы также можете сделать определенные типы явными, аннотировав их (что для наглядности рекомендуется выполнять в любом случае в отношении параметров функций и возвращаемых типов).
Можно аннотировать аргументы функций и возвращаемые типы следующим образом:
def foo(x: int, y: int) -> int:
return x + y
Тогда mypy будет сигнализировать о нарушении, если вы попытаетесь вызвать функцию с неправильными аргументами, например:
foo("a", "b")
Управлять настройками mypy будем в отдельном файле mypy.ini . Это необходимо главным образом потому, что некоторые внешние зависимости не могут быть проверены на тип, и нужно исключить их из проверки (хотя какие-то из них можно настроить).
pytest
Модульное тестирование необходимо любому профессиональному программному продукту, хотя желательно тестировать каждый проект. Мы будем использовать pytest, который предпочитают многие разработчики Python.
Модульное тестирование помогает отлавливать ошибки и тем самым поддерживать качество кода на высоком уровне.
Github Actions
Github Actions позволяет автоматизировать и запускать определенные шаги в репозитории — в духе непрерывной интеграции. С помощью этого инструмента можно создавать рабочие процессы, которые будут выполняться для определенных событий, таких как запросы на включение изменений (PR).
Рабочий процесс, который будет использован здесь, фактически является совокупной деятельностью вышеупомянутых инструментов: для каждого открытого PR будут выполняться форматирование, линтинг, проверка типов и модульные тесты. И все это должно осуществляться перед слиянием, чтобы защитить основную ветку от коммита любого нечистого и ошибочного кода!
Настройка репозитория
В этой статье не будут рассматриваться с нуля системы контроля версий и настройка репозиториев Github. Предполагается наличие у читателей определенных базовых знаний. При необходимости можно обратиться к туториалам, например к официальному руководству Github. Здесь же поговорим только о настройках в Git, которые есть практически в любом профессиональном репозитории программного обеспечения.
Собственно говоря, нужно установить лишь одну настройку — защиту основной ветки. Чтобы кто-то не попал в нее без проверок, необходимо обеспечить выполнение ваших требований, в частности одобрения другими разработчиками и прохождения установленных вами CI-тестов. Для этого зайдите в репозиторий и выберите “Settings” (“Настройки”), а затем “Branches” (“Ветки”):
Потом добавьте правила защиты основной ветки.
- Требовать запрос на добавление изменений перед слиянием.
- Требовать одобрения (можно выбрать количество необходимых одобрений).
- Требовать прохождения проверки состояния перед слиянием.
Соберем все вместе
Мы подготовили все необходимые инструменты. Теперь соберем их вместе, создадим образец репозитория и запустим рабочий процесс, которому должен следовать каждый разработчик.
Образец проекта
Проект будет иметь папку utils , содержащую файл math_utils.py и связанный с ним файл модульного теста ( math_utils_test.py ). В math_utils повторно реализуем функцию экспоненциализации в демонстрационных целях:
import numpy.typing as npt
def exponentiate(base: int, exponent: npt.NDArray) -> npt.NDArray:
return base**exponent
Таким образом, exponentiate(2, [1, 2, 3]) вернет [2, 4, 8] .
Проверим корректность функции в тестовом файле:
import numpy as np
import numpy.typing as npt
import pytest
from utils.math_utils import exponentiate
@pytest.mark.parametrize(
"base, exponent, expected",
[
(2, np.zeros(3), np.ones(3)),
(2, np.linspace(1, 4, 4), np.asarray([2, 4, 8, 16])),
],
)
def test_exponentiate(base: int, exponent: npt.NDArray, expected: npt.NDArray) -> None:
assert np.allclose(exponentiate(base, exponent), expected)
В основном файле ( main.py ) будем использовать эту функцию для генерации первых 10 значений степени 2 и построения графика с помощью matplotlib :
import matplotlib.pyplot as plt
import numpy as np
from utils.math_utils import exponentiate
def main() -> None:
x = np.linspace(0, 10, 10)
y = exponentiate(2, x)
plt.plot(x, y, "ro")
plt.savefig("plot.png")
if __name__ == "__main__":
main()
Файл pyproject.toml для этого проекта выглядит следующим образом:
[tool.poetry]
name = "Sample Python Project"
version = "0.1.0"
description = "Sample Python repository"
authors = ["hermanmichaels "]
[tool.poetry.dependencies]
python = "3.10"
matplotlib = "3.5.1"
mypy = "0.910"
numpy = "1.22.3"
pytest = "7.1.2"
black = "22.3.0"
flake8 = "4.0.1"
isort = "^5.10.1"
[tool.poetry.dev-dependencies]
[tool.black]
line-length = 80
target_version = ["py310"]
[tool.isort]
profile = "black"
py_version = 310
multi_line_output = 3
Кроме того, исключаем matplotlib из проверки mypy для предотвращения ошибок, создав следующий файл mypy.ini :
[mypy]
python_version = 3.10
[mypy-matplotlib.*]
ignore_missing_imports = True
ignore_errors = True
Рабочий процесс Github
Теперь определим следующий рабочий процесс Github Actions:
name: Sample CI Check
on:
pull_request:
branches: [main]
push:
branches: [main]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10.0
uses: actions/setup-python@v3
with:
python-version: "3.10.0"
- name: Install poetry dependencies
run: |
curl -sSL https://install.python-poetry.org | python3 -
poetry install
- name: Sort imports with isort
run: poetry run python -m isort .
- name: Format with black
run: poetry run python -m black .
- name: Lint with flake8
run: poetry run python -m flake8 .
- name: Check types with mypy
run: poetry run python -m mypy .
- name: Run unit tests
run: poetry run python -m py.test
Таким образом, этот рабочий процесс запускается для каждого нового PR и для каждого PR, объединенного с основным.
Он состоит из следующих шагов.
- Проверка репозитория.
- Установка Python 3.10.
- Установка poetry и зависимостей.
- Запуск всех установленных проверок (обратите внимание, что poetry run X идентичен входу в среду poetry через poetry shell и последующему выполнению X ). В частности, осуществляется запуск сортировки импорта с помощью isort, форматирования кода с помощью black, линтинга с помощью flake8, проверки типов с помощью mypy и модульного тестирования с помощью pytest.
Локальный рабочий процесс разработчика
Теперь опишем рабочий процесс, который каждый разработчик должен выполнять время от времени, особенно перед тем, как генерировать PR. В предыдущем разделе выражение “рабочий процесс” обозначало концепцию Github по группировке шагов в рабочем процессе, а здесь оно просто описывает шаги, которые должен выполнить разработчик.
Не стоит полагаться на CI и нагружать его поиском всех ошибок. Необходимо отправлять PR как можно более “чистыми”. Это означает, что следует проделывать все шаги, выполняемые на CI, самостоятельно локально перед отправкой. Это достигается следующим образом:
- запуск isort для сортировки импорта: isort ;
- запуск black для форматирования кода: black ;
- запуск flake8 для проверки кода: python -m flake8 ;
- запуск mypy для проверки типов: mypy (в первый раз это может занять довольно много времени);
- запуск всех модульных тестов: python -m pytest .
Заключение
В этой статье описаны полезные инструменты, помогающие организовывать и поддерживать код Python в хорошем состоянии в соответствии с профессиональными стандартами. Мы также показали, как создать Git-репозиторий для версионирования и обмена этим кодом и, в частности, как использовать ранее представленные инструменты в CI (выполнение определенных проверок для предотвращения любых нечистых и ошибочных коммитов в основную ветку). Наконец, мы показали, как запустить все эти инструменты локально, чтобы минимизировать риск сбоя CI.
- 5 приемов Python, которые отличают профессионалов от новичков
- Как развернуть пакет Cython в PyPI
- Зачем Python столько знаков подчеркивания?
Читайте нас в Telegram, VK и Дзен