Стильный код на Python, или учимся использовать Flake8
Автор: Анатолий Соловей, developer
Язык программирования Python очень востребован на современном рынке, он развивается изо дня в день, и вокруг него сложилось активное сообщество. Во избежание конфликтов между разработчиками-питонистами, создатели языка написали соглашение PEP 8, описывающее правила оформления кода, однако даже там отмечено, что:
Many projects have their own coding style guidelines. In the event of any conflicts, such project-specific guides take precedence for that project.
В результате добавления новых правил количество требований к оформлению кода увеличилось настолько, что удержать их в голове стало очень трудно. При этом обращение к гайдам может занимать много времени и отвлекать от процесса разработки.
За долгое время работы у программистов вырабатывается собственный стиль написания кода, предпочтения в стайлгайдах и прочие мелочи, которые оставляют авторскую печать на программах девелопера. Убедить разработчиков отказаться от привычных им кодстайлов очень сложно, но, даже если это удастся, велик шанс, что в их коде будут проскакивать старые фишки, добавленные в силу привычки.
Когда каждый апдейт проходит строгий код ревью, включающий в себя проверку стилей, подобные ошибки могут очень сильно замедлять процесс разработки. А если ошибки в итоге не заметят даже в процессе ревью, в системе контроля версий проекта очень скоро появится куча нечитаемого и непонятного кода.
На помощь в этом случае приходят линтеры — инструменты, контролирующие оформление кода в проекте. Именно они помогают поддерживать его чистоту и, в нашем случае, предотвращать создание коммитов, которые могут содержать ошибки. Я для контроля качества использую Flake8 и сейчас постараюсь объяснить, почему выбрал именно его, и расскажу, как его настроить, чтобы получить максимальный результат. Заинтересовались? Добро пожаловать под кат.
Flake8: Your Tool For Style Guide Enforcement
Сам Flake8 — инструмент, позволяющий просканировать код проекта и обнаружить в нем стилистические ошибки и нарушения различных конвенций кода на Python.
Flake8 умеет работать не только с PEP 8, но и с другими правилами, к тому же поддерживает кастомные плагины, поэтому в дальнейшем в этой статье я буду отталкиваться от правил из Google Python Style Guide.
Почему Flake8?
Flake8: pep8 + pyflakes + more
Создатель Flake8 Тарек Зиаде ставил перед собой цель объединить главные популярные инструменты контроля кодстайла в одной библиотеке, с чем в итоге успешно справился — Flake8 получился действительно универсальным.
Легкость установки и конфигурации
Чтобы проверить, отвечает ли код в вашем проекте основным требованиям PEP 8, достаточно установить Flake:
$ pip install flake8
и запустить его — просто ввести в командной строке:
$ flake8 my_project
после чего вы получите список с именами файлов и номерами строк, где были допущены ошибки, и подробное описание самих ошибок:
$ flake8 my_project
myfile.py:1: 'sys' imported but unused
myfile.py:4:1: E302 expected 2 blank lines, found 1
Великолепно, не правда ли? Но и это не всё. Если вы не любитель работать с консолью, то вы можете настроить интеграцию Flake8 с IDE или редактором, который вы предпочитаете использовать.
Интеграция Flake8 с редакторами и IDE
Интеграция с PyCharm
Так же актуально и для любой другой IDE от JetBrains.
Интеграция проводится всего за пару несложных шагов.
Откройте настройки External Tools в File→Settings→Tools и нажмите на »+», затем заполните поля по этому шаблону:
После этого нажмите на Output Filters, а затем на »+», чтобы добавить новое правило для вывода сообщений от флейка:
здесь мы говорим PyCharm, что хотим, чтобы в выводе строки с ошибками были кликабельными и открывали в редакторе файл и место с ошибкой
Все. Интеграция Flake8 с PyCharm закончена. Чтобы вызвать флейк и проверить свой код, кликаем правой кнопкой мыши на файл/директорию, которую мы хотим проверить, и в контекстном меню выбираем External Tools → Flake8.
В выводе PyCharm появится кликабельный список нарушений в выбранном файле/директории:
Интеграция с Atom
Чтобы установить инструмент Flake8 для Atom, используйте Atom package manager в Settings и найдите там linter-flake8:
или вызовите
apm install flake8
из командной строки.
Затем перейдите в linter-flake8 settings и укажите путь к директории, где установлен flake8:
У linter-flake8 есть собственный ReadMe по настройке, с которым при желании вы можете ознакомиться на странице самого linter-flake8 в Atom.
Наличие Version Control Hooks
Именно это я считаю главным достоинством Flake8, которое выделяет его среди других линтеров. В отличии от большинства подобных инструментов, где для настройки VCS-хуков используются целые отдельные библиотеки и модули (как, например, в Pylint), настройка хуков в флейке проводится буквально в две строчки.
На момент написания этой статьи, Flake8 умеет использовать pre-commit-хуки для Git и Mercurial. Эти хуки позволяют, например, не допускать создания коммита при нарушении каких-либо правил оформления.
Установить хук для Git:
$ flake8 --install-hook git
И настроить сам гит, чтобы учитывать правила Flake8:
$ git config --bool flake8.strict true
Я продемонстрирую, как Git hook работает на проекте, который я использовал для примера интеграции Flake8 с PyCharm. В модуле flake8tutorial.py мы видим очевидные ошибки: импортированные и неиспользованные модули, остсутствие докстринга и пустой строки в конце файла.
Первым делом проинициализируем в этом проекте git-0репозиторий, установим flake8 хук и скажем нашему git, что он должен прогонять флейк перед коммитами:
Затем попробуем провести первый коммит:
Как видите, flake8 был вызван перед коммитом и не позволил нам закоммитить невалидные изменения.
Теперь фиксим ошибки, отмеченные флейком, и пытаемся закоммитить валидный код:
Коммит успешно создан. Отлично!
Настройка Flake8 для Mercurial практически идентична. Для начала нужно установить Flake8 Mercurial Hook:
$ flake8 --install-hook mercurial
И настроить сам Mercurial:
$ hg config flake8.strict true
Вот и все, хук для Меrcurial установлен, настроен и готов к использованию!
Подробнее о конфигурации Flake8
Базовая конфигурация
Список дополнительных опций и правил можно передать прямо при вызове из командной строки таким образом:
flake8 --select E123
(в этом примере опцией select мы говорим, чтобы Flake сообщал о нарушениях только правила E123 (это код правила «closing bracket does not match indentation of opening bracket’s line»)).
Кстати, полный список опций с описанием вы можете найти в документации к самой библиотеке.
На мой взгляд, куда предпочтительнее настраивать Flake с помощью конфигурационных файлов, вы можете хранить настройки в одном из файлов setup.cfg, tox.ini или.flake8. Для ясности я предпочитаю использовать последний вариант.
Файл с настройками позволяет контролировать использование библиотекой тех же опций, что настраиваются для командной строки, базовый конфигурационный файл выглядит так:
[flake8]
ignore = D203
exclude = .git,__pycache__,docs/source/conf.py,old,build,dist
В этом файле мы сообщаем Flake, что он не должен оповещать нас о нарушениях правила D203 (»1 blank line required before class docstring»), а также не должен проверять файлы .git,__pycache__, docs/source/conf.py и директории old, build, dist.
В конфигурационных файлах можно оставлять комментарии, это полезно делать, если вы предоставляете большой список правил, которые Flake должен игнорировать:
[flake8]
# it's not a bug that we aren't using all of hacking
ignore =
# F812: list comprehension redefines ...
F812,
# H101: Use TODO(NAME)
H101,
# H202: assertRaises Exception too broad
H202,
# H233: Python 3.x incompatible use of print operator
H233,
# H301: one import per line
H301,
# H306: imports not in alphabetical order (time, os)
H306,
# H401: docstring should not start with a space
H401,
# H403: multi line docstrings should end on a new line
H403,
# H404: multi line docstring should start without a leading new line
H404,
# H405: multi line docstring summary not separated with an empty line
H405,
# H501: Do not use self.__dict__ for string formatting
H501
Также можно добавить в исключения отдельную строку в вашем модуле, просто оставив на этой строке комментарий noqa. Тогда при проверке модуля Flake8 будет игнорировать ошибки, найденные в строках, помеченных этим комментарием:
import sys # noqa
Модули, расширяющие функциональность
Так как Flake позволяет создавать и использовать кастомные плагины, для него можно найти большое количество open-source плагинов. Я опишу только те, которые использую сам и считаю особенно полезными:
flake8-import-order
Плагин, проверяющий порядок импортов в проекте: в стандартной конфигурации первыми должны идти импорты стандартных библиотек (stdlib), затем импорты сторонних библиотек, а потом локальные пакеты, причем каждая группа отделена пустой строкой и отсортирована в алфавитном порядке.
Этот плагин расширяет список предупреждений Flake, добавляя туда три новых:
- I100: Your import statements are in the wrong order.
- I101: The names in your from import are in the wrong order.
- I201: Missing newline between sections or imports.
Установка:
pip install flake8-import-order
Конфигурация:
[flake8]
application-import-names = my_project, tests # Указываем флейку директории, в которых хранятся локальные пакеты.
import-order-style = google # Указываем флейку на то, в каком порядке должны идти импорты. Как я уже говорил выше, я предпочитаю использовать Google Style Guide.
Более подробно о настройке flake8-import-order можно прочитать на странице библиотеки на Github.
flake8-docstrings
Плагин, добавляющий поддержку функционала из pydocstyle — проверку докстрингов на соответствие конвенциям Питона.
Установка:
pip install flake8_docstrings
Список добавляемых этой библиотекой правил можно найти в документации pydocstyle.
Конфигурация:
Сама по себе эта библиотека никак не настраивается, однако добавленные правила можно внести в исключения, если какое-то из них неактуально для вашего проекта:
[flake8]
ignore = D101 # Игнорировать docstrings предупреждение "Missing docstring in public class”
Страница библиотеки на Github тут.
flake8-builtins
Плагин, проверяющий код на использование встроенных имен в качестве переменных или параметров.
Установка:
pip install flake8-builtins
Конфигурация:
Как и в случае с flake8-docstrings, у плагина нет дополнительных настроек, но добавленные им правила можно, например, внести в исключения флейка:
[flake8]
ignore = B001 # Игнорировать builtins предупреждение " is a python builtin and is being shadowed, consider renaming the variable”
Более подробную информацию об этом плагине можно найти на странице этого плагина на Github.
flake8-quotes
Плагин, позволяющий контролировать тип кавычек, которые будут использоваться в проекте.
Установка:
pip install flake8-quotes
Конфигурация:
[flake8]
inline-quotes = " # Указываем, какой тип кавычек должен использоваться в вашем проекте
Более подробную информацию об этом плагине можно найти на странице этого плагина на Github.
Послесловие
Хотя настройки, описанные выше, в 97,5% случаев смогут предотвратить появление некачественного кода в репозитории, он так или иначе может оказаться запушенным (например, если деву было лень вводить две строчки для настройки pre-commit hook). Поэтому я настоятельно рекомендую добавить вызов Flake8 на этапе билда пул-реквестов в используемой вами системе continuous integration, чтобы предотвратить мердж невалидных пул-реквестов и попадание ошибок в мастер.
Надеюсь, эта статья была вам полезна и позволит в дальнейшем максимально гибко и качественно настраивать рабочий процесс и стайлгайды в ваших Python-проектах. Всех благ.
Список источников:
- Документация Flake8
- Useful Python Modules: Flake8
- Google Python Style Guide
Комментарии (2)
29 декабря 2016 в 20:02
0↑
↓
Теперь фиксим ошибки, отмеченные флейком, и пытаемся закоммитить валидный код:
Есть (была?) одна проблема: валидатор проверяет состояние рабочего дерева, а не индекса. Проще говоря, существует возможность нечаянно запихнуть в репозиторий каку:1) Пишите невалидный код
2) Добавляете файл в индекс
3) Пытаетесь сделать коммит
4) Валидатор ругается
5) Доводите файл до валидного состояния, но НЕ добавляете его повторно в индекс
6) Теперь у вас есть возможность закоммитить невалидный код из п. 229 декабря 2016 в 20:10
0↑
↓
Спасибо.
Субъективно, насколько Pyflakes8 лучше / удобнее, чем встроенный в Pycharm linter?