Стильный код на Python, или учимся использовать Flake8

8396349c3e804e45833b14213ed0efd3.png
Автор: Анатолий Соловей, 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 и нажмите на »+», затем заполните поля по этому шаблону:
85084c5536204b83ac61ab31586ab128.png

После этого нажмите на Output Filters, а затем на »+», чтобы добавить новое правило для вывода сообщений от флейка:
8e131d5b5b9c49759ef285cd8cdf5309.png
здесь мы говорим PyCharm, что хотим, чтобы в выводе строки с ошибками были кликабельными и открывали в редакторе файл и место с ошибкой

Все. Интеграция Flake8 с PyCharm закончена. Чтобы вызвать флейк и проверить свой код, кликаем правой кнопкой мыши на файл/директорию, которую мы хотим проверить, и в контекстном меню выбираем External Tools → Flake8.
5848f2d787ff46c19bdcff25f84cd581.png

В выводе PyCharm появится кликабельный список нарушений в выбранном файле/директории:
539150d68b744277b330b0b80abb6fb8.png

Интеграция с Atom
Чтобы установить инструмент Flake8 для Atom, используйте Atom package manager в Settings и найдите там linter-flake8:
a4199710968043b8a3168202fa6cc68e.png

или вызовите


apm install flake8

из командной строки.

Затем перейдите в linter-flake8 settings и укажите путь к директории, где установлен flake8:
39cf8fd4416d4ad9a379ad79d66cc302.png

У 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, что он должен прогонять флейк перед коммитами:
c74845f44b3b4f6d93e6ad004a2cdd7f.png

Затем попробуем провести первый коммит:
f12080ffd3d142768f3021bb353ae3f1.png

Как видите, flake8 был вызван перед коммитом и не позволил нам закоммитить невалидные изменения.

Теперь фиксим ошибки, отмеченные флейком, и пытаемся закоммитить валидный код:
0d2236322b544daf920136b008ec921e.png

Коммит успешно создан. Отлично!

Настройка 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) Теперь у вас есть возможность закоммитить невалидный код из п. 2

  • 29 декабря 2016 в 20:10

    0

    Спасибо.


    Субъективно, насколько Pyflakes8 лучше / удобнее, чем встроенный в Pycharm linter?

© Habrahabr.ru