Pylint: Avoid checking INSIDE DOCSTRINGS (global directive / rcfile)
Asked Answered
U

1

16

Consider this piece of code:

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 output:

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

Is there any directive avaliable (rcfile) to exclude ONLY DOCSTRINGS from pylint checker?

A multiline regex for ignore-long-lines (Thanks @fredtantini) seems to be ignored.

Surrounding docstrings with # pylint: dis/enable=line-too-long (Thanks @Evert) will cause the required effect, however, I'm looking for a global directive to make the trick.

Ulberto answered 31/12, 2014 at 11:51 Comment(7)
Did you check if ignore-long-lines takes a multiline regexp?Sunstone
I guess you could surround docstrings with # pylint: dis/enable=line-too-long comment, but that's no fun nor pretty.Bewley
There might not be any more options, see the def check_lines(self, lines, i): source in format.py. It might be possible to write a plugin to override that.Philately
You are free to have as long docstrings as you want. I think docstrings are more readable if you follow the PEP8 recommandation that docstrings/comments should be maximum 72 characters. As far as I know pylint doesn't distingush between code and comments when checking line length. You can set a global max-line-length and that's it. docs.pylint.org/features.html#id3Decarbonate
@Philately followed your initial comment and posted an answer (this is crazy, I know) :) Thank you!Audly
This would be a useful feature for when you are copy/pasting in output from another source and have no choice of line length.Finegrained
Although this does not directly answer the question, if you need a tool that checks line-length while ignoring docstrings, you can use flake8.Gulley
A
10

The problem is that the thing you are asking about is not configurable at all. Moreover, according to the PEP8:

Limit all lines to a maximum of 79 characters.

For flowing long blocks of text with fewer structural restrictions (docstrings or comments), the line length should be limited to 72 characters.

That said, let's analyze the source code and see if we can come up with a solution. The checker which is responsible for checking the line length is called a FormatChecker - it also checks for indentation and unauthorized code constructions.

The are two relevant methods we are interested in:

As you can see the "Line too long" error message is being added here:

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 here refers to the ignore-long-lines regular expression setting, which, by default, equals to ^\s*(# )?<?https?://\S+>?$ - which would help in case there are http links inside the (doc)string - no error would be thrown.

In other words, there is only ignore-long-lines setting that can prevent pylint from applying the "too long line" check.

Also note the interesting fact: the pylint code-quality check utility has this misleading docstring:

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

while the method also checks for missing-final-newline and trailing-whitespace. This is something you would never catch statically - human error which can be noticed and fixed by a human only.


I don't like the following proposal, but we can monkey-patch the FormatChecker on the fly.

Create a script called "checker.py" and put it on PYTHONPATH. Here we are redefining the new_line() method and adding a "token type" check - not letting the checker call the check_lines() method if this is a comment or a string (docstring). Then, in the register() function we are overriding the built-in FormatChecker's new_line() with ours:

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__)

Run pylint with --load-plugins command-line argument:

$ pylint --load-plugins checker script.py

Demo:

  • without the plugin

    $ 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)
    
  • with the plugin (no complains about the 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)
    

where script.py contains:

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'

There are few notes that have to be mentioned:

  • this is too complicated, fragile, unstable and magical to be ever used
  • see the first note
Audly answered 9/1, 2015 at 15:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.