Pylint: избегайте проверки INSIDE DOCSTRINGS (глобальная директива/rcfile)

Рассмотрим этот фрагмент кода:

def test():
    """This line is longer than 80 chars, but, for me this is ok inside a DOCSTRING,
    this one is shorter.
    """

    if 'This is toooooooooooooooooooooooooooooooooooo longggggggggggggggggggggggg':
        print 'True'

pylint вывод:

C:  5, 0: Line too long (84/80) (line-too-long)
C:  9, 0: Line too long (83/80) (line-too-long)

Есть ли какая-либо директива, доступная (rcfile), чтобы исключить ТОЛЬКО DOCSTRINGS из pylint checker?

Многострочный regex для ignore-long-lines ( Спасибо @fredtantini), кажется, игнорируется.

Окружающие docstrings с # pylint: dis/enable=line-too-long ( Спасибо @Evert) вызовет требуемый эффект, однако я ищу глобальную директиву, чтобы сделать трюк.

Ответ 1

Проблема в том, что вещь, о которой вы просите, не настраивается вообще. Кроме того, согласно PEP8:

Ограничьте все строки максимум 79 символами.

Для потоков длинных блоков текста с меньшими структурными ограничениями (docstrings или comments), длина строки должна быть ограничена 72 символами.

Тем не менее, проанализируйте исходный код и посмотрите, можем ли мы придумать решение. Контроллер, который отвечает за проверку длины строки, называется FormatChecker - он также проверяет наличие отступов и несанкционированных конструкций кода.

Вот два соответствующих метода, которые нас интересуют:

Как вы видите, сообщение об ошибке "Линия слишком длинная" добавляется здесь:

if len(line) > max_chars and not ignore_long_line.search(line):
    self.add_message('line-too-long', line=i, args=(len(line), max_chars))

ignore_long_line здесь ссылается на параметр регулярного выражения ignore-long-lines, который по умолчанию равен ^\s*(# )?<?https?://\S+>?$ - который поможет в случае, если в строке (doc) есть HTTP-ссылки - ошибка не будет выбрана.

Другими словами, существует только параметр ignore-long-lines, который может помешать pylint применять проверку "слишком длинной строки".

Также обратите внимание на интересный факт: утилита проверки качества кода pylint имеет эту вводящую в заблуждение docstring:

def check_lines(self, lines, i):
    """check lines have less than a maximum number of characters
    """

в то время как метод также проверяет на missing-final-newline и trailing-whitespace. Это то, что вы никогда не поймаете статически - человеческую ошибку, которую можно заметить и зафиксировать только человеком.


Мне не нравится следующее предложение, но мы можем обезопасить FormatChecker на лету.

Создайте script под названием "checker.py" и поместите его на PYTHONPATH. Здесь мы переопределяем метод new_line() и добавляем проверку "токена" - не позволяя checker вызывать метод check_lines(), если это комментарий или строка (docstring). Затем в функции register() мы переопределяем встроенный FormatChecker new_line() с помощью наших:

import tokenize
from pylint.checkers.format import FormatChecker, _last_token_on_line_is, _JUNK_TOKENS
import new


class MyFormatChecker(object):
    def new_line(self, tokens, line_end, line_start):
        if _last_token_on_line_is(tokens, line_end, ';'):
            self.add_message('unnecessary-semicolon', line=tokens.start_line(line_end))

        line_num = tokens.start_line(line_start)
        line = tokens.line(line_start)

        token_type = tokens.type(line_start)
        if token_type not in _JUNK_TOKENS:
            self._lines[line_num] = line.split('\n')[0]

        if token_type not in (tokenize.COMMENT, tokenize.STRING):
            self.check_lines(line, line_num)


def register(linter):
    format_checker = linter._checkers['format'][0]
    format_checker.new_line = new.instancemethod(MyFormatChecker.new_line.im_func, format_checker,
                                                 FormatChecker.__class__)

Запустите pylint с аргументом командной строки --load-plugins:

$ pylint --load-plugins checker script.py

Демо:

  • без плагина

    $ pylint script.py 
    C:  2, 0: Line too long (85/79) (line-too-long)
    C:  6, 0: Line too long (83/79) (line-too-long)
    C:  1, 0: Missing module docstring (missing-docstring)
    
  • с плагином (не жалуется на docstring)

    $ pylint --load-plugins=checker script.py 
    C:  6, 0: Line too long (83/79) (line-too-long)
    C:  1, 0: Missing module docstring (missing-docstring)
    

где script.py содержит:

def test():
    """This line is longer than 80 chars, but , for me this is ok inside a DOCSTRING,
    this one is shorter.
    """

    if 'This is toooooooooooooooooooooooooooooooooooo longggggggggggggggggggggggg':
        print 'True'

Следует отметить несколько примечаний:

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