jayvdb / flake8-putty

Flake8 plugin to control reporting per file and line
MIT License
37 stars 6 forks source link

Multiline regex pattern #4

Open JelteF opened 8 years ago

JelteF commented 8 years ago

To disable some pep257 checks for @property methods I would like to match on that and ignore some stuff on the next line. Is this possible in some way? If not were should I look to implement this?

jayvdb commented 8 years ago

If the name of property is only used for properties in files that they appear in (i.e. you dont reuse the name for other functions in the same files), then you can use a filename match and a regex on the name of the property. Basically you might be able to do the same as the example of __init__ at

https://github.com/jayvdb/flake8-putty#examples

e.g.

class Foo(object):

    @property
    def foo(self):
        return 'a'
$ flake8  --putty-ignore="test.py,/def foo/ : +D102" test.py
f.py:1:1: D100 Missing docstring in public module
f.py:1:1: D101 Missing docstring in public class

If you need to be more precise, and explicitly only catch the property, then we need to add some state that flake8 doesnt provide.

Two approaches come to mind:

  1. Add a MultilineRegex to config.py, which finds all matching line numbers for each file it is asked to process, and then have putty_ignore_code passes the line_number it has to Rule.match which would then pass the line number to the MultilineRegex object.
  2. Rather than a multiline regex, a new rule type for object name like ClassName[.method[.inner_function]] as a precise way of selecting a set of lines which should ignored. The implementation would be similar to MultilineRegex, but using inspect to get the line number range instead of a regex. One complication is how to specify property getters vs setters vs deleters. maybe that could be an optional part of the selector syntax, like ClassName[.method[^(getter|setter|deleter)]|[.inner_function]]
JelteF commented 8 years ago

Thanks for the quick response, I already used your above workaround. The two options both seem quite good (especially the second one), but they also also seem quite a bit of work. I'll just stick with the explicit rules for now, but I might add one of these in the future.

jayvdb commented 8 years ago

The multiline regex approach could be achieved quite easily by re-joining the array of lines, which we already have access to as reporter.lines in putty_ignore_code. So there is no need to reload the file each time, which is nice for performance.

A multiline regex could provide a workaround for issues like suppressing E402 (import): https://github.com/PyCQA/pep8/issues/472 . That could not be easily achieved by approach 2 (specifying the object name/scope to disable a code), because the import is at the module level, and the desired effect in that pep8 issue is not to disable the rule for the entire module scope -- only at the beginning. I'm not sure there would be a nice contextual specification syntax to allow selecting a few lines at the top of the module. It feels like a multiline regex is the right syntax for selecting something like that.

Regarding better contextual awareness, the ast for the file is also readily available, but only if the error is in a checker that uses ast checking. flake8-docstring does use the ast checker, so this would be a viable approach for pep257. It wouldnt work for hacking rules, because they use the pep8 logical_line/physical_line checker. It is fairly flakey for this to only work for some checkers. To work for all checkers, flake8-putty would need to register an ast checker which caches the ast so that it is available when the logical_line/physical_line checkers are run after the ast checks are completed.

jayvdb commented 8 years ago

Another feature that requires the rule is run at a per-module level (rather than per-line) is #7 .

As that occurs only once per module source, and the rule applies to all lines in the source module , #7 should be a bit simpler to solve than generic multiline regex support.