Flake8 ignore error

flake8 is a python tool that glues together pycodestyle, pyflakes, mccabe, and third-party plugins to check the style and quality of some python code. - flake8/violations.rst at main · PyCQA/flake8

Selecting and Ignoring Violations

It is possible to select and ignore certain violations reported by |Flake8|
and the plugins we’ve installed. It’s also possible as of |Flake8| 3.0 to
combine usage of :option:`flake8 —select` and :option:`flake8 —ignore`. This
chapter of the User Guide aims to educate about how Flake8 will report errors
based on different inputs.

Ignoring Violations with Flake8

By default, |Flake8| has a list of error codes that it ignores. The list used
by a version of |Flake8| may be different than the list used by a different
version. To see the default list, :option:`flake8 —help` will
show the output with the current default list.

Extending the Default Ignore List

If we want to extend the default list of ignored error codes, we can use
:option:`flake8 —extend-ignore` to specify a comma-separated list of codes
for a specific run on the command line, e.g.,

.. prompt:: bash

    flake8 --extend-ignore=E1,E23 path/to/files/ path/to/more/files

This tells |Flake8| to ignore any error codes starting with E1 and E23,
in addition the default ignore list. To view the default error code ignore
list, run :option:`flake8 —help` and refer to the help text for
:option:`flake8 —ignore`.

Overriding the Default Ignore List

If we want to completely override the default list of ignored error codes, we
can use :option:`flake8 —ignore` to specify a comma-separated list of codes
for a specific run on the command-line, e.g.,

.. prompt:: bash

    flake8 --ignore=E1,E23,W503 path/to/files/ path/to/more/files/

This tells |Flake8| to only ignore error codes starting with E1, E23,
or W503 while it is running.

Note

The documentation for :option:`flake8 —ignore` shows examples for how
to change the ignore list in the configuration file. See also
:ref:`configuration` as well for details about how to use configuration
files.

In-line Ignoring Errors

In some cases, we might not want to ignore an error code (or class of error
codes) for the entirety of our project. Instead, we might want to ignore the
specific error code on a specific line. Let’s take for example a line like

example = lambda: 'example'

Sometimes we genuinely need something this simple. We could instead define
a function like we normally would. Note, in some contexts this distracts from
what is actually happening. In those cases, we can also do:

example = lambda: 'example'  # noqa: E731

This will only ignore the error from pycodestyle that checks for lambda
assignments and generates an E731. If there are other errors on the line
then those will be reported. # noqa is case-insensitive, without the colon
the part after # noqa would be ignored.

Note

If we ever want to disable |Flake8| respecting # noqa comments, we can
refer to :option:`flake8 —disable-noqa`.

If we instead had more than one error that we wished to ignore, we could
list all of the errors with commas separating them:

Finally, if we have a particularly bad line of code, we can ignore every error
using simply # noqa with nothing after it.

Contents before and after the # noqa: ... portion are ignored so multiple
comments may appear on one line. Here are several examples:

# mypy requires `# type: ignore` to appear first
x = 5  # type: ignore  # noqa: ABC123

# can use to add useful user information to a noqa comment
y = 6  # noqa: ABC456  # TODO: will fix this later

Ignoring Entire Files

Imagine a situation where we are adding |Flake8| to a codebase. Let’s further
imagine that with the exception of a few particularly bad files, we can add
|Flake8| easily and move on with our lives. There are two ways to ignore the
file:

  1. By explicitly adding it to our list of excluded paths (see: :option:`flake8
    —exclude`
    )
  2. By adding # flake8: noqa to the file

The former is the recommended way of ignoring entire files. By using our
exclude list, we can include it in our configuration file and have one central
place to find what files aren’t included in |Flake8| checks. The latter has the
benefit that when we run |Flake8| with :option:`flake8 —disable-noqa` all of
the errors in that file will show up without having to modify our
configuration. Both exist so we can choose which is better for us.

Selecting Violations with Flake8

|Flake8| has a default list of violation classes that we use. This list is:

  • C90

    All C90 class violations are reported when the user specifies
    :option:`flake8 —max-complexity`

  • E

    All E class violations are «errors» reported by pycodestyle

  • F

    All F class violations are reported by pyflakes

  • W

    All W class violations are «warnings» reported by pycodestyle

This list can be overridden by specifying :option:`flake8 —select`. Just as
specifying :option:`flake8 —ignore` will change the behaviour of |Flake8|, so
will :option:`flake8 —select`.

Let’s look through some examples using this sample code:

# example.py
def foo():
    print(
                "Hello"
        "World"
        )

By default, if we run flake8 on this file we’ll get:

.. prompt:: bash

    flake8 example.py

example.py:4:9: E131 continuation line unaligned for hanging indent

Now let’s select all E class violations:

.. prompt:: bash

    flake8 --select E example.py

example.py:3:17: E126 continuation line over-indented for hanging indent
example.py:4:9: E131 continuation line unaligned for hanging indent
example.py:5:9: E121 continuation line under-indented for hanging indent

Suddenly we now have far more errors that are reported to us. Using
--select alone will override the default --ignore list. In these cases,
the user is telling us that they want all E violations and so we ignore
our list of violations that we ignore by default.

We can also be highly specific. For example, we can do

.. prompt:: bash

    flake8 --select E121 example.py

example.py:5:9: E121 continuation line under-indented for hanging indent

We can also specify lists of items to select both on the command-line and in
our configuration files.

.. prompt:: bash

    flake8 --select E121,E131 example.py

example.py:4:9: E131 continuation line unaligned for hanging indent
example.py:5:9: E121 continuation line under-indented for hanging indent

Selecting and Ignoring Simultaneously For Fun and Profit

Prior to |Flake8| 3.0, all handling of :option:`flake8 —select` and
:option:`flake8 —ignore` was delegated to pycodestyle. Its handling of the
options significantly differs from how |Flake8| 3.0 has been designed.

pycodestyle has always preferred --ignore over --select and will
ignore --select if the user provides both. |Flake8| 3.0 will now do its
best to intuitively combine both options provided by the user. Let’s look at
some examples using:

# example.py
import os


def foo():
    var = 1
    print(
                "Hello"
        "World"
        )

If we run |Flake8| with its default settings we get:

.. prompt:: bash

    flake8 example.py

example.py:1:1: F401 'os' imported but unused
example.py:5:5: F841 local variable 'var' is assigned to but never used
example.py:8:9: E131 continuation line unaligned for hanging indent

Now let’s select all E and F violations including those in the default
ignore list.

.. prompt:: bash

    flake8 --select E,F example.py

example.py:1:1: F401 'os' imported but unused
example.py:5:5: F841 local variable 'var' is assigned to but never used
example.py:7:17: E126 continuation line over-indented for hanging indent
example.py:8:9: E131 continuation line unaligned for hanging indent
example.py:9:9: E121 continuation line under-indented for hanging indent

Now let’s selectively ignore some of these while selecting the rest:

.. prompt:: bash

    flake8 --select E,F --ignore F401,E121 example.py

example.py:5:5: F841 local variable 'var' is assigned to but never used
example.py:7:17: E126 continuation line over-indented for hanging indent
example.py:8:9: E131 continuation line unaligned for hanging indent

Via this example, we can see that the most specific user-specified rule
will win. So in the above, we had very vague select rules and two very
specific ignore rules. Let’s look at a different example:

.. prompt:: bash

    flake8 --select F401,E131 --ignore E,F example.py

example.py:1:1: F401 'os' imported but unused
example.py:8:9: E131 continuation line unaligned for hanging indent

In this case, we see that since our selected violation codes were more
specific those were reported.

The Ignoring Errors docs currently list a way of ignoring a particular error for a particular line:

example = lambda: 'example'  # noqa: E731

… and a way of ignoring all errors for an entire file:

# flake8: noqa

from foo import unused
function_that_doesnt_exist()
x = 1+       2

… and a couple of ways, either through config or through command-line options, of disabling a particular error globally across an entire project.

But what if I want to ignore a particular error across the entirety of a single file — for instance, to disable warnings about unused imports in an __init__.py barrel file that just imports a bunch of classes so that code from other packages can import them from it in turn? The docs don’t seem to hint at any syntax for this. Is it possible?

asked Jan 8, 2018 at 16:02

Mark Amery's user avatar

Mark AmeryMark Amery

137k78 gold badges401 silver badges450 bronze badges

3

As of Flake8 3.7.0 you can do this using the --per-file-ignores option.

Command line example

flake8 --per-file-ignores="project/__init__.py:F401 setup.py:E121"

Or in your config file

per-file-ignores =
    project/__init__.py:F401
    setup.py:E121
    other_project/*:W9

See the documentation here: http://flake8.pycqa.org/en/latest/user/options.html?highlight=per-file-ignores#cmdoption-flake8-per-file-ignores

It is not possible to place a noqa comment for specific codes at the top of a file like you can for individual lines. # flake8: noqa: F401 may at first appear to work, but it’s actually being detected as only # flake8: noqa, which means «ignore all messages in the file».

answered Jan 31, 2019 at 6:15

Ross MacArthur's user avatar

Ross MacArthurRoss MacArthur

4,2451 gold badge20 silver badges35 bronze badges

1

Before version 3.7.0, ignoring specific errors was only implemented per-line but not per-file.

The feature was discussed in issue #324 and the project chose not to implement. An implementation was proposed in this merge request, which nobody has followed up on.

However, some extensions have emerged to address the problem:

  • [discontinued] flake8-per-file-ignores lets you ignore specific warning/errors for specific files via an entry in the config.

  • flake8-putty claims to do the same, but hasn’t been updated for a while.

bagerard's user avatar

bagerard

4,7672 gold badges25 silver badges44 bronze badges

answered Jan 8, 2018 at 16:41

Arminius's user avatar

ArminiusArminius

2,17818 silver badges21 bronze badges

1

I implemented a flake8 plugin flake8-in-file-ignores to allow adding «ignore» rules in the file itself (as opposed to the built-in config approach), the plugin uses the following syntax

# flake8-in-file-ignores: noqa: E731,E123

answered Jan 27 at 11:02

bagerard's user avatar

bagerardbagerard

4,7672 gold badges25 silver badges44 bronze badges

Update .flake8 file with

ignore = E123,E125,H404,H405,H803 ... any other rools

answered Aug 10, 2022 at 16:55

Jekson's user avatar

JeksonJekson

2,6346 gold badges35 silver badges71 bronze badges

1

Линтеры

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

К таким хорошим практикам можно отнести, например, следующие.

  • Форматировать код по PEP8
    — если этого не делать, то другим людям будет намного сложнее понимать
    ваш код; в плохо оформленном коде сложнее увидеть суть,
    потому что мозг постоянно отвлекается на не несущие смысловой нагрузки
    особенности оформления.
  • Не допускать объявленных, но неиспользуемых переменных/функций/импортов
    — опять же, это усложняет восприятие кода; читателю потребуется потратить
    время на то, чтобы осознать, что вот на эту сущность обращать внимания не
    нужно.
  • Писать короткие функции — слишком сложные функции с большим
    количеством ветвлений и циклов тяжело понимать.
  • Не использовать изменяемый объект в качестве значения аргумента
    функции по умолчанию — иначе в результате можно получить
    очень неожиданные эффекты.

Соблюдать (и даже просто помнить) все хорошие практики — не самая простая
задача. Зачастую люди плохо справляются с тем, чтобы отсчитывать пробелы
и контролировать переменные, и вообще склонны допускать ошибки по
невнимательности. Таковы люди, ничего не поделаешь. Машины, наоборот,
прекрасно справляются с такими хорошо определёнными задачами, поэтому
появились инструменты, которые контролируют следование хорошим практикам.

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

В этом посте я рассмотрю два самых популярных линтера для Python:

  • flake8;
  • pylint.

Термин “lint” впервые начал использоваться в таком значении в 1979 году.
Так называлась программа для статического анализа кода на C,
которая предупреждала об использовании непортабельных на другие архитектуры
языковых конструкций. С тех пор “линтерами” называют любые статические
анализаторы кода, которые помогают находить распространённые ошибки, делать
его однообразным и более читаемым. А названо оно «lint» в честь вот такой
штуки:

lint roller

flake8

flake8 — это утилита-комбайн, которая органично объединяет в себе несколько
других анализаторов кода (pycodestyle, pyflakes и mccabe), а также
имеет огромную экосистему плагинов, которые могут добавить к стандартной
поставке ещё кучу различных проверок. На данный момент, это самый
популярный линтер для Python-кода. Кроме того, он предельно прост в
настройке и использовании.

Установка

flake8 устанавливается, как и любой другой Python-пакет,
через pip. Внутри виртуального окружения проекта выполните:

Если вы пользуетесь pipenv, то flake8 нужно устанавливать
как dev-зависимость (ведь для работы программы линтер не нужен,
он нужен только для разработчика):

$ pipenv install --dev flake8

Аналогично с poetry:

$ poetry add --dev flake8

Проверим установку:

$ flake8 --version
3.8.1 (mccabe: 0.6.1, pycodestyle: 2.6.0, pyflakes: 2.2.0) CPython 3.8.2 on Linux

Использование

Для работы flake8 нужно просто указать файл или директорию, которые
нужно проверять, например:

# проверить один файл
$ flake8 file.py

# проверить директорию рекурсивно 
$ flake8 src/

# проверить текущую директорию рекурсивно
$ flake8 .

Давайте для демонстрации попытаемся написать программу с как можно большим
количеством “плохих практик”:

Возможно, вам не видно всего, но в этом коде точно есть следующие «запахи кода»:

  • import * — импортирование всех имен из модуля, хотя используется
    из них только одно;
  • import itertools — ненужный импорт;
  • во множестве мест стоят лишние или отсутствующие пробелы;
  • название функции написано в стиле PascalCase;
  • в некоторых местах используются табы для отступов;
  • используется список (изменяемый объект) в качестве значения аргумента
    функции по умолчанию;
  • используется слишком “широкое” выражение except: без указания
    конкретного исключения.

Давайте посмотрим, что flake8 скажет по поводу этого файла:

$ flake8 bad_code.py
bad_code.py:1:1: F403 'from math import *' used; unable to detect undefined names
bad_code.py:2:1: F401 'itertools' imported but unused
bad_code.py:4:1: E302 expected 2 blank lines, found 1
bad_code.py:4:4: E271 multiple spaces after keyword
bad_code.py:4:25: E211 whitespace before '('
bad_code.py:4:33: E202 whitespace before ')'
bad_code.py:5:1: W191 indentation contains tabs
bad_code.py:5:8: E271 multiple spaces after keyword
bad_code.py:5:10: F405 'sqrt' may be undefined, or defined from star imports: math
bad_code.py:5:21: E202 whitespace before ')'
bad_code.py:7:1: E302 expected 2 blank lines, found 1
bad_code.py:7:23: E741 ambiguous variable name 'l'
bad_code.py:8:1: E101 indentation contains mixed spaces and tabs
bad_code.py:9:1: E101 indentation contains mixed spaces and tabs
bad_code.py:11:1: E305 expected 2 blank lines after class or function definition, found 1
bad_code.py:12:1: E101 indentation contains mixed spaces and tabs
bad_code.py:13:1: E101 indentation contains mixed spaces and tabs
bad_code.py:13:20: E225 missing whitespace around operator
bad_code.py:14:1: E101 indentation contains mixed spaces and tabs
bad_code.py:14:67: W291 trailing whitespace
bad_code.py:15:1: E101 indentation contains mixed spaces and tabs
bad_code.py:15:14: W291 trailing whitespace
bad_code.py:16:1: E101 indentation contains mixed spaces and tabs
bad_code.py:16:5: E722 do not use bare 'except'
bad_code.py:17:1: E101 indentation contains mixed spaces and tabs

Как видите, flake8 нашёл кучу ошибок. Для каждой ошибки указана строка
и номер символа в строке (не всегда точный), где произошла ошибка.
Также у каждой категории ошибок есть свой код: E101, W291 и т.д.
Эти коды ошибок могут использоваться для включения/отключения правил.
Тем не менее, не все ошибки были найдены. Давайте установим пару плагинов,
чтобы добавить ещё правил!

Плагины

Как я уже говорил, для flake8 написано множество плагинов.
Обычно плагины легко гуглятся или находятся в списках плагинов.
Есть плагины для всех популярных фреймворков и библиотек — пользуйтесь ими!
Давайте для нашего простого примера установим
flake8-bugbear
(находит распространённые логические ошибки) и
pep8-naming
(проверяет имена на соответствие PEP8).

Плагины устанавливаются так же, как и сам flake8 (для краткости я
не буду писать примеры для pipenv и poetry — сами сможете обобщить):

$ pip install flake8-bugbear pep8-naming

Давайте убедимся, что плагины действительно установились
и flake8 может их найти:

$ flake8 --version
3.8.1 (flake8-bugbear: 20.1.4, mccabe: 0.6.1, naming: 0.10.0, pycodestyle: 2.6.0, pyflakes: 2.2.0) CPython 3.8.2 on Linux

Если вы видите в списке в скобках названия ваших плагинов, то всё хорошо.

Теперь снова проверим наш файл:

$ flake8 bad_code.py
bad_code.py:1:1: F403 'from math import *' used; unable to detect undefined names
bad_code.py:2:1: F401 'itertools' imported but unused
bad_code.py:4:1: E302 expected 2 blank lines, found 1
bad_code.py:4:4: E271 multiple spaces after keyword
bad_code.py:4:6: N802 function name 'CalculateSquareRoot' should be lowercase
bad_code.py:4:25: E211 whitespace before '('
bad_code.py:4:28: N803 argument name 'Number' should be lowercase
bad_code.py:4:33: E202 whitespace before ')'
bad_code.py:5:1: W191 indentation contains tabs
bad_code.py:5:8: E271 multiple spaces after keyword
bad_code.py:5:10: F405 'sqrt' may be undefined, or defined from star imports: math
bad_code.py:5:21: E202 whitespace before ')'
bad_code.py:7:1: E302 expected 2 blank lines, found 1
bad_code.py:7:23: E741 ambiguous variable name 'l'
bad_code.py:7:25: B006 Do not use mutable data structures for argument defaults.  They are created during function definition time. All calls to the function reuse this one instance of that data structure, persisting changes between them.
bad_code.py:8:1: E101 indentation contains mixed spaces and tabs
bad_code.py:9:1: E101 indentation contains mixed spaces and tabs
bad_code.py:11:1: E305 expected 2 blank lines after class or function definition, found 1
bad_code.py:12:1: E101 indentation contains mixed spaces and tabs
bad_code.py:13:1: E101 indentation contains mixed spaces and tabs
bad_code.py:13:20: E225 missing whitespace around operator
bad_code.py:14:1: E101 indentation contains mixed spaces and tabs
bad_code.py:14:67: W291 trailing whitespace
bad_code.py:15:1: E101 indentation contains mixed spaces and tabs
bad_code.py:15:14: W291 trailing whitespace
bad_code.py:16:1: E101 indentation contains mixed spaces and tabs
bad_code.py:16:5: E722 do not use bare 'except'
bad_code.py:16:5: B001 Do not use bare `except:`, it also catches unexpected events like memory errors, interrupts, system exit, and so on.  Prefer `except Exception:`.  If you're sure what you're doing, be explicit and write `except BaseException:`.
bad_code.py:17:1: E101 indentation contains mixed spaces and tabs

В выводе появились новые категории ошибок (N802, B006)
— они как раз добавлены плагинами. На этот раз, как мне кажется,
найдены все ошибки. К сожалению, flake8 не умеет сам чинить
найденные ошибки, поэтому давайте сделаем это вручную:

Обратите внимание на строки 8 и 10, там содержится комментарии # noqa.
При помощи этих комментариев можно заставить flake8 игнорировать ошибки.
Это бывает полезно, когда по какой-то причине код должен остаться именно
таким, например:

  • он автоматически сгенерирован и исправление в нём ошибок не имеет смысла;
  • исправление этой ошибки породит куда более уродливый код,
    чем комментарий # noqa;
  • у вас просто сейчас нет времени, чтобы исправлять эту ошибку
    (плохая отмазка, серьёзно).

Если не указать код ошибки, то будут проигнорированы все ошибки в строке
— я не рекомендую так делать, потому что так можно пропустить
и на самом деле плохие ошибки. Если указать номер правила, то
flake8 будет игнорировать только указанную категорию,
а о других ошибках в этой же строке доложит.
Вообще, комментариями # noqa нужно пользоваться с большой осторожностью.
Считайте, что каждый раз, когда вы это делаете, вы берёте на
себя ответственность за эту строку кода. Если программа сломается
в этом месте, то пеняйте на себя — минздрав линтер вас предупреждал.

Конфигурация

flake8 для работы не требует никакой конфигурации.
Он имеет достаточно (но не слишком) строгие настройки по умолчанию,
которые подойдут большинству пользователей, но иногда бывает нужно
отключить (или наоборот включить) определённые правила на уровне всего проекта.
Сделать это можно через файлы .flake8 или setup.cfg в корне проекта.
Если у вас в проекте уже есть файл setup.cfg, то можно добавить конфигурацию
flake8 в него. Если вы предпочитаете для каждой утилиты держать
отдельный файл конфигурации, то используйте .flake8. В любом случае,
формат для обоих этих файлов совпадает:

[flake8]
ignore = D203,E741
exclude =
    # No need to traverse our git directory
    .git,
    # There's no value in checking cache directories
    __pycache__,
    # The conf file is mostly autogenerated, ignore it
    docs/source/conf.py,
    # The old directory contains Flake8 2.0
    old,
    # This contains our built documentation
    build,
    # This contains builds of flake8 that we don't want to check
    dist
max-complexity = 10

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

Если же вам не хватает какого-нибудь правила, и его нет даже в уже
готовых плагинах, то написание собственного плагина
— не такая уж и сложная задача.
Я попробовал,
у меня на это ушло 2-3 часа.

pylint

pylint — это ещё один популярный линтер для Python.
Этот линтер значительно умнее и продвинутее flake8.
В pylint из коробки заложено очень много правил и рекомендаций,
и по умолчанию они все включены, так что он достаточно строгий и придирчивый.
Чтобы интегрировать его в существующий большой проект придётся потратить
некоторое время, чтобы выбрать те правила, которые для вас важны.
Так же как и flake8, pylint поддерживает плагины для расширения
базовой функциональности, но насколько я вижу, экосистема плагинов у pylint
значительно беднее.

Также при каждом запуске pylint выводит оценку качества кода
по десятибалльной шкале, а также следит, как эта оценка меняется
с течением времени. Достичь десятки очень сложно, но это благородная цель,
к которой нужно стремиться.

Установка

Установка pylint принципиально ничем не отличается от установки flake8.
Выполнить внутри виртуального окружения проекта:

Для pipenv:

$ pipenv install --dev pylint

Для poetry:

$ poetry add --dev pylint

Использование

pylint можно натравить на определённый файл:

С директориями у pylint дела обстоят чуть сложнее. Все директории он
обрабатывает как питоновские модули, поэтому если в директории нет хотя бы
пустого файла __init__.py, то работать с ней pylint не сможет. Имейте
это ввиду.

Давайте попросим pylint прокомментировать файл с плохими практиками
из предыдущего примера:

$ pylint bad_code.py
************* Module bad_code
bad_code.py:4:25: C0326: No space allowed before bracket
def  CalculateSquareRoot (Number ):
                         ^ (bad-whitespace)
bad_code.py:4:33: C0326: No space allowed before bracket
def  CalculateSquareRoot (Number ):
                                 ^ (bad-whitespace)
bad_code.py:5:0: W0312: Found indentation with tabs instead of spaces (mixed-indentation)
bad_code.py:5:21: C0326: No space allowed before bracket
    return  sqrt(Number )
                     ^ (bad-whitespace)
bad_code.py:13:19: C0326: Exactly one space required around assignment
        your_number=float(input('Enter your number: '))
                   ^ (bad-whitespace)
bad_code.py:14:66: C0303: Trailing whitespace (trailing-whitespace)
bad_code.py:15:13: C0303: Trailing whitespace (trailing-whitespace)
bad_code.py:1:0: W0622: Redefining built-in 'pow' (redefined-builtin)
bad_code.py:1:0: C0114: Missing module docstring (missing-module-docstring)
bad_code.py:1:0: W0401: Wildcard import math (wildcard-import)
bad_code.py:4:0: C0103: Function name "CalculateSquareRoot" doesn't conform to snake_case naming style (invalid-name)
bad_code.py:4:0: C0103: Argument name "Number" doesn't conform to snake_case naming style (invalid-name)
bad_code.py:4:0: C0116: Missing function or method docstring (missing-function-docstring)
bad_code.py:7:0: W0102: Dangerous default value [] as argument (dangerous-default-value)
bad_code.py:7:0: C0103: Argument name "l" doesn't conform to snake_case naming style (invalid-name)
bad_code.py:7:0: C0116: Missing function or method docstring (missing-function-docstring)
bad_code.py:16:4: W0702: No exception type(s) specified (bare-except)
bad_code.py:1:0: W0614: Unused import acos from wildcard import (unused-wildcard-import)
bad_code.py:1:0: W0614: Unused import acosh from wildcard import (unused-wildcard-import)
bad_code.py:1:0: W0614: Unused import asin from wildcard import (unused-wildcard-import)
bad_code.py:1:0: W0614: Unused import asinh from wildcard import (unused-wildcard-import)
...
bad_code.py:2:0: W0611: Unused import itertools (unused-import)
-------------------------------------
Your code has been rated at -41.43/10

Я немного сократил вывод. Как видите, даже без плагинов pylint нашёл
все ожидаемые ошибки, и даже больше — например, он даже предлагает написать
документацию.

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

$ pylint --help-msg=missing-docstring
$ pylint --help-msg=R0902

Вот какие ошибки pylint находит для файла, который с точки зрения flake8
не содержит никаких ошибок:

$ pylint not_so_bad_code.py 
************* Module not_so_bad_code
not_so_bad_code.py:1:0: C0114: Missing module docstring (missing-module-docstring)
not_so_bad_code.py:4:0: C0116: Missing function or method docstring (missing-function-docstring)
not_so_bad_code.py:8:0: C0103: Argument name "l" doesn't conform to snake_case naming style (invalid-name)
not_so_bad_code.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
not_so_bad_code.py:20:11: W0703: Catching too general exception Exception (broad-except)
-----------------------------------
Your code has been rated at 6.67/10

А вот так в pylint можно игнорировать отдельную ошибку на строке прямо в файлах
с кодом:

def append_item(item, l=None):  # pylint: disable=C0103
   ...

Ещё pylint умеет игнорировать ошибки в блоках кода:

def test():
    # Disable all the no-member violations in this function
    # pylint: disable=no-member
    ...

И для файлов целиком. Вот так можно отключить все ошибки из категорий
Warning, Convention и Refactor:

А можно не проверять файл вообще:

Подробнее о правилах управления сообщениями
смотрите в документации.
Для более сложной настройки правил, придётся по-настоящему сконфигурировать
pylint.

Конфигурация

pylint настраивается через файл .pylintrc в корне проекта. Чтобы создать
дефолтный файл конфигурации, нужно выполнить следующую команду:

$ pylint --generate-rcfile > .pylintrc

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

Плагины

Давайте установим какой-нибудь популярный плагин, например,
pylint-django:

$ pip install pylint-django

Теперь запускать pylint нужно вот так:

$ pylint --load-plugins pylint_django [..other options..] <path_to_your_sources>

либо в .pylintrc нужно исправить директиву load-plugins:

load-plugins=pylint_django

Интеграция линтера в проект

Интегрировать линтер в проект можно на трёх уровнях.
Я рекомендую по возможности использовать все три, но обязательным
является как минимум один (лучше всего, чтобы это была CI система).

Редактор кода или IDE

Популярные IDE для Python умеют легко интегрировать с линтерами и
подсвечивать ошибки линтера прямо в редактируемом файле.
Это удобно, потому что позволяет не выходя из редактора получить
полезную обратную связь.

PyCharm автоматически находить установленные flake8 и pylint внутри
интерпретатора проекта
и подключается к ним.

VS Code требует небольшой настройки, которая
описана здесь.

Git-хуки

Также читайте пост про Git-хуки и pre-commit.

В git есть возможность запрограммировать
определенные скрипты (хуки) в ответ на действия пользователя.
Например, можно запускать
какие-нибудь проверки перед коммитом, заново скачивать зависимости проекта
при переключении веток, высылать сообщение в рабочий чат
после пуша в удалённый репозиторий и вообще что угодно.

я запушель

Нас интересует возможность запускать линтер перед коммитом так,
чтобы если линтер найдёт какие-нибудь проблемы, операция коммита прерывалась.
Git-хуки можно настроить, написав несложный shell-скрипт,
но я рекомендую использовать для этого специальные утилиты,
такие как pre-commit.
Вот здесь
можно найти описание процесса настройки запуска flake8 через pre-commit.

Обратите внимание, что Git-хуки нужно будет настроить на машине каждого
разработчика в проекте.

Continuous Integration (CI)

Последний эшелоном защиты от попадания “сломанного” кода в основную ветку
репозитория является система непрерывной интеграции (CI) — такая, как:

  • GitHub Actions;
  • GitLab CI
    (а ещё читайте пост в блоге моего хорошего товарища про
    основы GitLab CI);
  • Travis CI;
  • или другая.

На каждый пуш в репозиторий система непрерывной интеграции должна
запускать проверки (включая все линтеры и тесты), и если что-то идёт
не так, рядом с коммитом должен появиться красный крестик.
Ветку с таким коммитом на конце нельзя будет слить с основной
веткой проекта через пулл-реквест на GitHub (или мёрдж-реквест на GitLab).
Пример того, как настроить GitHub Actions
для запуска flake8 и других питоновских проверок.

CI — это единственный надёжный способ обеспечить качество кода.
Предыдущие способы нужны скорее для удобства разработчика, чтобы он
как можно скорее получал обратную связь, но разработчик вправе проигнорировать
или отключить эти предупреждения.

Заключение

В подзаголовке этой статьи я написал фразу, что линтер способен
сэкономить разработчику один день жизни в месяц. Фраза может показаться
кликбейтной, но, поверьте мне, это так это и работает.
Возможно, я даже преуменьшил.
Чем раньше найдена ошибка, тем быстрее идёт разработка.
Иногда линтер предотвращает баги, иногда спасает от мучительного
траблшутинга. Линтеры абсолютно точно значительно сокращают время,
потраченное коллегами на код-ревью, потому что все тривиальные
ошибки будут отловлены автоматикой.

Не стоит недооценивать линтеры. Это те инструменты,
которые делают из “кодера” настоящего “software engineer”,
из мальчика — мужчину. Если вы до сих пор не пользуетесь каким-нибудь
линтером, то рекомендую всерьез задуматься над внедрением!

Я предпочитаю использовать flake8, потому что он простой
и понятный, как топор. С ним легко работать, его легко настроить
под свои нужды, а почти любые недостающие правила можно получить
через уже готовые плагины.

У pylint тоже есть свои последователи. Его ценят за подробный вывод
и большое количество правил в стандартной поставке.
Мне же pylint всегда казался слишком сложным в эксплуатации.

А кто-то вообще рекомендует устанавливать flake8 и pylint параллельно.

Если понравилась статья, то
подпишитесь на уведомления
о новых постах в блоге, чтобы ничего не пропустить!

Дополнительное чтение

  • документация flake8;
  • исходный код flake8;
  • список плагинов flake8;
  • сайт, где можно посмотреть правила flake8;
  • документация pylint;
  • исходный код pylint;
  • обсуждение “flake8 vs pylint” на Reddit;
  • пост на RealPython про качество кода;
  • статья на Хабре про линтеры.

Обложка: Sa Mu, Traffic Light

For so long the word “Linting” meant nothing to me. It sounded like some supercoder leet speak that was way out of my league. Then I discovered flake8 and realised I was a fool.

This article is a simple one. It covers what linting is; what Flake8 is and has an embarrassing example of it in use.

Before we get started, I need to get something off my chest. I don’t know why but I really hate the word “linting”. It’s a hatred akin to people and the word “moist”.

Linting. Linting. Linting. shudder. Let’s move on!

What is Linting?

Just so I never have to type it again, let’s quickly cover off what linting is.

It’s actually pretty simple. Linting is the process of running a program that analyses code for programmatic errors such as bugs, actual errors, styling issues etc.

Put it in the same basket as the process running in your favourite text editor that keeps an eye out for typos and grammatical errors.

This brings us to Flake8.

What is Flake8?

It’s one of these linting programs and is pretty damn simple to use. It also happens to analyse your code for PEP8 standard violations!

I love it for a few reasons:

  • I’m constantly learning something new. It picks away at my code, pointing out my failings, much like annoying friends.
  • It keeps my code looking schmick. It’s easy to miss spacing and other tiny things while coding so running Flake8 against my code catches little annoyances before it’s pushed to prod.
  • It’s a much nicer word than “linting”.

Flake8 in Action

To demonstrate my beloved Flake8 I thought I’d grab an old, and I mean old, script that’s likely riddled with issues. Judge me not friends!

In an older (I’m really stressing old here) article I wrote a simple script to send emails. No functions or anything, just line by line code. Ignoring what the code actually does take a look at this snippet below. Full code here.

λ cat generic_emailer.py
#!python3
#emailer.py is a simple script for sending emails using smtplib
#The idea is to assign a web-scraped file to the DATA_FILE constant.
#The data in the file is then read in and sent as the body of the email.



DATA_FILE = 'scraped_data_file'
from_addr = 'your_email@gmail.com'
to_addr = 'your_email@gmail.com'  #Or any generic email you want all recipients to see
bcc = EMAILS


Now that we have my script, let’s run flake8 against it.

  1. pip install the sucker:

    (venv) λ pip install flake8
    
  2. Simply run flake8 and point it at your script. Given generic_emailer.py is in my current directory I’d run the following:

    (venv) λ flake8 generic_emailer.py
    
  3. In traditional CLI fashion, if you don’t receive any output at all, you have no issues. In my case, yeah, nope. The output I receive when running Flake8 against my script is as follows:

    (venv) λ flake8 generic_emailer.py
    generic_emailer.py:2:1: E265 block comment should start with '# '
    generic_emailer.py:3:1: E265 block comment should start with '# '
    generic_emailer.py:4:1: E265 block comment should start with '# '
    generic_emailer.py:14:35: E262 inline comment should start with '# '
    generic_emailer.py:14:80: E501 line too long (86 > 79 characters)
    generic_emailer.py:27:50: E261 at least two spaces before inline comment
    generic_emailer.py:27:51: E262 inline comment should start with '# '
    generic_emailer.py:29:19: E261 at least two spaces before inline comment
    generic_emailer.py:29:20: E262 inline comment should start with '# '
    generic_emailer.py:31:23: E261 at least two spaces before inline comment
    generic_emailer.py:31:24: E262 inline comment should start with '# '
    generic_emailer.py:33:1: E265 block comment should start with '# '
    generic_emailer.py:38:1: E265 block comment should start with '# '
    generic_emailer.py:41:1: E265 block comment should start with '# '
    generic_emailer.py:44:1: E265 block comment should start with '# '
    

Analysing the Output

Before we look into the actual issues, here’s a quick breakdown of what the above means.

  • The first section is the name of the file we’re… flaking… Yes, I’m making the word “flaking” a thing!
  • The next two numbers represent the line number and the character position in that line. ie: line 2, position 1.
  • Finally, we have the actual issue. The “E” number is the error/violation number. The rest is the detail of the problem.

Now what does it all mean?

Well, the majority of my violations here have to do with the spacing in front of my comments.

  • The E265 violations are simply telling me to add a space after my # to satisfy standards.
  • E501 is saying I have too many characters in my line with the limit being 79.

You can read the rest!

Fixing the Violations

Let’s quickly fix two of the violations:

  • generic_emailer.py:14:35: E262 inline comment should start with '# '
  • generic_emailer.py:14:80: E501 line too long (86 > 79 characters)

The code in question on line 14 is this:

to_addr = 'your_email@gmail.com'  #Or any generic email you want all recipients to see

I can actually fix both issues by simply removing the comment. Doing this and running Flake8 again gets me the following output:

(venv) λ flake8 generic_emailer.py
generic_emailer.py:2:1: E265 block comment should start with '# '
generic_emailer.py:3:1: E265 block comment should start with '# '
generic_emailer.py:4:1: E265 block comment should start with '# '
generic_emailer.py:27:50: E261 at least two spaces before inline comment
generic_emailer.py:27:51: E262 inline comment should start with '# '
generic_emailer.py:29:19: E261 at least two spaces before inline comment
generic_emailer.py:29:20: E262 inline comment should start with '# '
generic_emailer.py:31:23: E261 at least two spaces before inline comment
generic_emailer.py:31:24: E262 inline comment should start with '# '
generic_emailer.py:33:1: E265 block comment should start with '# '
generic_emailer.py:38:1: E265 block comment should start with '# '
generic_emailer.py:41:1: E265 block comment should start with '# '
generic_emailer.py:44:1: E265 block comment should start with '# '

Note the two violations are gone.

Ignoring Violations

What if I don’t care about the spacing of my comment #s?

Sometimes you’ll want Flake8 to ignore specific issues. One of the most common use cases is to ignore line length.

You can do this by running flake8 --ignore=E. Just specify which violations you want to ignore and Flake8 will overlook them.

To save yourself time you can also create a Flake8 config file and hardcode the violation codes into that. This method will save you specifying the code every time you run Flake8.

In my case I’m going to ignore those pesky E265 violations because I can.

I need to create a .flake8 file in my parent directory and add the following (with vim of course!):

(venv) λ touch flake8
(venv) λ cat .flake8
[flake8]
ignore = E265

When I re-run Flake8 I now see the following:

(venv) λ flake8 generic_emailer.py
generic_emailer.py:27:50: E261 at least two spaces before inline comment
generic_emailer.py:27:51: E262 inline comment should start with '# '
generic_emailer.py:29:19: E261 at least two spaces before inline comment
generic_emailer.py:29:20: E262 inline comment should start with '# '
generic_emailer.py:31:23: E261 at least two spaces before inline comment
generic_emailer.py:31:24: E262 inline comment should start with '# '

The rest of the errors are an easy clean up so I’ll leave it here.

Another way to ignore errors is to add a # noqa: E..., for example to ignore a very long comment you could add a # noqa E501 to the end::

# In some cases, we might not want to ignore an error code (or class of error codes) for the entirety of our project. Instead, ...  # noqa E501

Of course it’s even better if you split the comment over multiple lines, but just to make a point.

Vim shortcut

As highlighted in 5 Vim Tricks to Speed up Your Python Development, a handy shortcut to invoke flake8 from within Vim, is adding this to your .vimrc:

autocmd FileType python map  ,f :call Flake8()

Flake8 on PyBites CodeChallenges

As luck would have it, we’ve just implemented a new feature on the PyBites CodeChallenges platform that allows you to run flake8 against your browser based code!

Now you can have flake8 lint your code to perfection while you solve our Bites.

Check it out in all its glory:

flake8-codechallenges.png

Conclusion

Whether you like the word Linting or not, there’s no denying the value it can provide – Flake8 case in point.

While it can definitely grow a little tiresome at times if you have a well crafted config file you can customise it to your liking and pain threshold.

It really is a brilliant tool to add to your library so give it a try!

Keep Calm and Code in Python!

— Julian

Scroll to navigation

FLAKE8(1) General Commands Manual FLAKE8(1)

NAME¶

flake8 — code checker using pycodestyle and pyflakes

SYNOPSIS¶

flake8 [options] input

DESCRIPTION¶

flake8 is a command-line utility for enforcing style
consistency across Python projects. By default it includes lint checks
provided by the PyFlakes project, PEP-0008 inspired style checks provided by
the PyCodeStyle project, and McCabe complexity checking provided by the
McCabe project. It will also run third-party extensions if they are found
and installed.

OPTIONS¶

—version
show program’s version number and exit
-h, —help
show this help message and exit
-v, —verbose
print more information about what is happening in flake8. This option is
repeatable and will increase verbosity each time it is repeated.
-q, —quiet
report only file names, or nothing. This option is repeatable.
—count
print total number of errors and warnings to standard error and set the
exit code to 1 if total is not empty.
—diff
report changes only within line number ranges in the unified diff provided
on standard in by the user.
—exclude=patterns
comma-separated list of files or directories to exclude. (Default:
.svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg)
—filename=patterns
only check for filenames matching the patterns in this comma-separated
list. (Default: *.py)
—stdin-display-name=STDIN_DISPLAY_NAME
the name used when reporting errors from code passed via stdin. This is
useful for editors piping the file contents to flake8. (Default:
stdin)
—format=format
format errors according to the chosen formatter.
—hang-closing
hang closing bracket instead of matching indentation of opening bracket’s
line.
—ignore=errors
comma-separated list of errors and warnings to ignore (or skip). For
example, —ignore=E4,E51,W234. (Default:
E121,E123,E126,E226,E24,E704,W503,W504)
—max-line-length=n
maximum allowed line length for the entirety of this run. (Default:
79)
—select=errors
comma-separated list of errors and warnings to enable. For example,
—select=E4,E51,W234. (Default: E,F,W,C90)
—disable-noqa
disable the effect of «# noqa». This will report errors on lines
with «# noqa» at the end.
—show-source
show the source generate each error or warning.
—statistics
count errors and warnings.
—enable-extensions=ENABLE_EXTENSIONS
enable plugins and extensions that are otherwise disabled by default
—exit-zero
exit with status code «0» even if there are errors.
—install-hook=INSTALL_HOOK
install a hook that is run prior to a commit for the supported version
control system.
-j JOBS,
—jobs=JOBS
number of subprocesses to use to run checks in parallel. This is ignored
on Windows. The default, «auto», will auto-detect the number of
processors available to use. (Default: auto)
—output-file=OUTPUT_FILE
redirect report to a file.
—tee
write to stdout and output-file.
—append-config=APPEND_CONFIG
provide extra config files to parse in addition to the files found by
Flake8 by default. These files are the last ones read and so they take the
highest precedence when multiple files provide the same option.
—config=CONFIG
path to the config file that will be the authoritative config source. This
will cause Flake8 to ignore all other configuration files.
—isolated
ignore all found configuration files.
—benchmark
print benchmark information about this run of Flake8
—max-complexity=MAX_COMPLEXITY
McCabe complexity threshold
—bug-report
print information necessary when preparing a bug report
—builtins=BUILTINS
define more built-ins, comma separated
—doctests
check syntax of the doctests
—include-in-doctest=INCLUDE_IN_DOCTEST
run doctests only on these files
—exclude-from-doctest=EXCLUDE_FROM_DOCTEST
skip these files when running doctests

CONFIGURATION¶

The project options are read from the [flake8] section of the
tox.ini file or the setup.cfg file located in any parent folder of the
path(s) being processed. Allowed options are: exclude, filename, select,
ignore, max-line-length, hang-closing, count, format, quiet, showpep8,
show-source, statistics, verbose, max-complexity, builtins.

Понравилась статья? Поделить с друзьями:
  • Flake8 e501 как исправить
  • Flac file decoder seekable stream decoder error
  • Fl studio тормозит как исправить
  • Fl studio как изменить цвет сетки
  • Fl studio как изменить размер плагина