From 2f1b92aff56223e4e3bf11da52d1d74e1e5a7ef3 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 6 Aug 2014 14:42:05 +0200 Subject: [PATCH] Add custom pylint checker for config. --- scripts/pylint_checkers/__init__.py | 1 + scripts/pylint_checkers/config.py | 77 +++++++++++++++++++++++++++++ scripts/run_checks.py | 16 +++++- 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 scripts/pylint_checkers/__init__.py create mode 100644 scripts/pylint_checkers/config.py diff --git a/scripts/pylint_checkers/__init__.py b/scripts/pylint_checkers/__init__.py new file mode 100644 index 000000000..1341a93c7 --- /dev/null +++ b/scripts/pylint_checkers/__init__.py @@ -0,0 +1 @@ +"""Custom pylint checkers.""" diff --git a/scripts/pylint_checkers/config.py b/scripts/pylint_checkers/config.py new file mode 100644 index 000000000..1b0bc3c62 --- /dev/null +++ b/scripts/pylint_checkers/config.py @@ -0,0 +1,77 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2014 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + +"""Custom astroid checker for config calls.""" + +import astroid +from pylint.interfaces import IAstroidChecker +from pylint.checkers import BaseChecker +from pylint.checkers import utils + +import qutebrowser.config.configdata as configdata + + +class ConfigChecker(BaseChecker): + + """Custom astroid checker for config calls.""" + + __implements__ = IAstroidChecker + name = 'config' + msgs = { + 'E0000': ('"%s -> %s" is no valid config option.', 'bad-config-call', + None), + } + priority = -1 + + @utils.check_messages('bad-config-call') + def visit_callfunc(self, node): + """Visit a CallFunc node.""" + if hasattr(node, 'func'): + infer = utils.safe_infer(node.func) + if infer and infer.root().name == 'qutebrowser.config.config': + if getattr(node.func, 'attrname', None) in ('get', 'set'): + self._check_config(node) + + def _check_config(self, node): + """Check that the arguments to config.get(...) are valid. + + FIXME: We should check all ConfigManager calls. + """ + try: + sect_arg = utils.get_argument_from_call(node, position=0, + keyword='sectname') + opt_arg = utils.get_argument_from_call(node, position=1, + keyword='optname') + except utils.NoSuchArgumentError: + return + sect_arg = utils.safe_infer(sect_arg) + opt_arg = utils.safe_infer(opt_arg) + if not (isinstance(sect_arg, astroid.Const) and + isinstance(opt_arg, astroid.Const)): + return + try: + configdata.DATA[sect_arg.value][opt_arg.value] + except KeyError: + self.add_message('bad-config-call', node=node, + args=(sect_arg.value, opt_arg.value)) + + +def register(linter): + """Register this checker.""" + linter.register_checker(ConfigChecker(linter)) diff --git a/scripts/run_checks.py b/scripts/run_checks.py index 6ad368767..bbc53ed61 100755 --- a/scripts/run_checks.py +++ b/scripts/run_checks.py @@ -67,7 +67,8 @@ options = { 'exclude_pep257': ['test_*', 'ez_setup'], 'other': { 'pylint': ['--output-format=colorized', '--reports=no', - '--rcfile=.pylintrc'], + '--rcfile=.pylintrc', + '--load-plugins=pylint_checkers.config'], 'flake8': ['--config=.flake8'], }, } @@ -86,6 +87,14 @@ def run(name, target=None, args=None): target: The package to check args: Option list of arguments to pass """ + if name == 'pylint': + scriptdir = os.path.abspath(os.path.dirname(__file__)) + if 'PYTHONPATH' in os.environ: + old_pythonpath = os.environ['PYTHONPATH'] + os.environ['PYTHONPATH'] += os.pathsep + scriptdir + else: + old_pythonpath = None + os.environ['PYTHONPATH'] = scriptdir sys.argv = [name] if target is None: status_key = name @@ -111,6 +120,11 @@ def run(name, target=None, args=None): except Exception as e: print('{}: {}'.format(e.__class__.__name__, e)) status[status_key] = None + if name == 'pylint': + if old_pythonpath is not None: + os.environ['PYTHONPATH'] = old_pythonpath + else: + del os.environ['PYTHONPATH'] print()