root/releases/pkgcore/0.2.2/lintplugin/pkgcore_lint.py @ marienz%2540gentoo.org-20061012220139-62173dc4676746e8

Revision marienz%2540gentoo.org-20061012220139-62173dc4676746e8, 4.6 KB (checked in by Marien Zwart <marienz@…>, 2 years ago)

Tweak the pylint plugin.

Line 
1
2"""Pylint plugin checking for trailing whitespace."""
3
4
5import sys
6
7from pylint import interfaces, checkers
8from logilab.astng import nodes, raw_building, utils
9
10
11class BasicLinesChecker(checkers.BaseChecker):
12
13    __implements__ = (interfaces.IRawChecker, interfaces.IASTNGChecker)
14
15    name = 'pkgcore-lines'
16
17    # XXX move some of those over to RewriteDemandload somehow
18    # (current monkey patch running the rewriter does not support that)
19
20    msgs = {
21        'CPC01': ('line too long',
22                  'More complete version of the standard line too long check'),
23        'CPC02': ('trailing whitespace', 'trailing whitespace sucks.'),
24        'WPC01': ('demandload with arglen != 2 ignored',
25                  'A call which is probably a demandload has the wrong number '
26                  'of arguments. Either fix the checker to not detect it as '
27                  'demandload when it is really not or fix the code to call '
28                  'demandload correctly.'),
29        'WPC02': ('demandload with non-string-constant arg ignored.',
30                  'A call which is probably a demandload has a second arg '
31                  'that is not a string constant. Fix the code to cooperate '
32                  'with the dumb checker.'),
33        }
34
35    def process_module(self, stream):
36        for linenr, line in enumerate(stream):
37            line = line.rstrip('\r\n')
38            if len(line) > 80:
39                self.add_message('CPC01', linenr)
40            if line.endswith(' ') or line.endswith('\t'):
41                self.add_message('CPC02', linenr)
42
43
44class RewriteDemandload(utils.ASTWalker):
45
46    def __init__(self, linter):
47        utils.ASTWalker.__init__(self, self)
48        self.linter = linter
49
50    def visit_callfunc(self, node):
51        """Hack fake imports into the tree after demandload calls."""
52        # XXX inaccurate hack
53        if not node.node.as_string().endswith('demandload'):
54            return
55        # sanity check.
56        if len(node.args) != 2:
57            self.linter.add_message('WPC01', node=node)
58            return
59        if not isinstance(node.args[1], nodes.Const):
60            self.linter.add_message('WPC02', node=node)
61            return
62        modules = node.args[1].value
63        if not isinstance(modules, str):
64            self.linter.add_message('WPC02', node=node)
65            return
66        for mod in modules.split():
67            col = mod.find(':')
68            if col == -1:
69                # Argument to Import probably works like this:
70                # "import foo, foon as spork" is
71                # nodes.Import([('foo', None), ('foon', 'spork')])
72                # (not entirely sure though, have not found documentation.
73                # The asname/importedname might be the other way around fex).
74                newstuff = nodes.Import([(mod, None)])
75                newstuff.fromlineno = 1
76                raw_building._attach_local_node(node.frame(), newstuff, mod)
77            else:
78                for name in mod[col+1:].split(','):
79                    if sys.version_info < (2, 5):
80                        newstuff = nodes.From(mod[:col], ((name, None),))
81                    else:
82                        newstuff = nodes.From(mod[:col], ((name, None),), 0)
83                    newstuff.fromlineno = 1
84                    raw_building._attach_local_node(node.frame(), newstuff,
85                                                    name)
86
87
88def register(linter):
89    """Required method to get our checker registered."""
90
91    rewriter = RewriteDemandload(linter)
92    # XXX HACK: monkeypatch the linter to transform the tree before
93    # the astng checkers get at it.
94    #
95    # Why do we do this? Because a whole bunch of places work with
96    # copies of astng data, not the data itself, by the time a normal
97    # checker runs it is too late to manipulate the data reliably. And
98    # pylint does not provide a hook that gets run at the right point
99    # to do this tree rewriting. So we monkeypatch in the hook.
100    #
101    # Ideally we would do something like
102    #
103    # linter.register_preprocessor(rewriter)
104    #
105    # and the linter would call walk(astng) on everything registered
106    # that way before the IASTNGCheckers run (not sure if it should be
107    # before or after the raw checkers run, probably does not matter).
108    # Perhaps give those preprocessors a priority attribute too.
109    # Definitely give them a msgs attribute.
110
111    original_check_astng_module = linter.check_astng_module
112    def pkgcore_check_astng_module(astng, checkers):
113        rewriter.walk(astng)
114        original_check_astng_module(astng, checkers)
115    linter.check_astng_module = pkgcore_check_astng_module
116
117    linter.register_checker(BasicLinesChecker(linter))
Note: See TracBrowser for help on using the browser.