diff options
| -rw-r--r-- | ChangeLog | 4 | ||||
| -rw-r--r-- | checkers/logging.py | 38 | ||||
| -rw-r--r-- | test/test_logging.py | 50 |
3 files changed, 85 insertions, 7 deletions
@@ -5,6 +5,10 @@ ChangeLog for Pylint * Add new warning 'eval-used', checking that the builtin function `eval` was used. + * Added a new configuration option logging-modules to make the list + of module names that can be checked for 'logging-not-lazy' et. al. + configurable; contributed by morbo@google.com. + * ensure init-hooks is evaluated before other options, notably load-plugins (#166) diff --git a/checkers/logging.py b/checkers/logging.py index a6b0145d8..cc8967d1a 100644 --- a/checkers/logging.py +++ b/checkers/logging.py @@ -61,21 +61,45 @@ class LoggingChecker(checkers.BaseChecker): name = 'logging' msgs = MSGS + options = (('logging-modules', + {'default' : ('logging',), + 'type' : 'csv', + 'metavar' : '<comma separated list>', + 'help' : ('Logging modules to check that the string format ' + 'arguments are in logging function parameter format')} + ), + ) + def visit_module(self, unused_node): """Clears any state left in this checker from last module checked.""" # The code being checked can just as easily "import logging as foo", # so it is necessary to process the imports and store in this field # what name the logging module is actually given. - self._logging_name = None + self._logging_names = set() + logging_mods = self.config.logging_modules + + self._logging_modules = set(logging_mods) + self._from_imports = {} + for logging_mod in logging_mods: + parts = logging_mod.rsplit('.', 1) + if len(parts) > 1: + self._from_imports[parts[0]] = parts[1] + + def visit_from(self, node): + """Checks to see if a module uses a non-Python logging module.""" + try: + logging_name = self._from_imports[node.modname] + for module, as_name in node.names: + if module == logging_name: + self._logging_names.add(as_name or module) + except KeyError: + pass def visit_import(self, node): """Checks to see if this module uses Python's built-in logging.""" for module, as_name in node.names: - if module == 'logging': - if as_name: - self._logging_name = as_name - else: - self._logging_name = 'logging' + if module in self._logging_modules: + self._logging_names.add(as_name or module) @check_messages(*(MSGS.keys())) def visit_callfunc(self, node): @@ -91,7 +115,7 @@ class LoggingChecker(checkers.BaseChecker): and ancestor.parent.name == 'logging')))] except astroid.exceptions.InferenceError: return - if node.func.expr.name != self._logging_name and not logger_class: + if node.func.expr.name not in self._logging_names and not logger_class: return self._check_convenience_methods(node) self._check_log_methods(node) diff --git a/test/test_logging.py b/test/test_logging.py new file mode 100644 index 000000000..85d3c8209 --- /dev/null +++ b/test/test_logging.py @@ -0,0 +1,50 @@ +# Copyright 2014 Google Inc. All Rights Reserved. +""" +Unittest for the logging checker. +""" +from logilab.common.testlib import unittest_main +from astroid import test_utils + +from pylint.checkers import logging + +from pylint.testutils import CheckerTestCase, Message + + +class LoggingModuleDetectionTest(CheckerTestCase): + CHECKER_CLASS = logging.LoggingChecker + + def test_detects_standard_logging_module(self): + stmts = test_utils.extract_node(""" + import logging #@ + logging.warn('%s' % '%s') #@ + """) + self.checker.visit_module(None) + self.checker.visit_import(stmts[0]) + with self.assertAddsMessages(Message('W1201', node=stmts[1])): + self.checker.visit_callfunc(stmts[1]) + + def test_detects_renamed_standard_logging_module(self): + stmts = test_utils.extract_node(""" + import logging as blogging #@ + blogging.warn('%s' % '%s') #@ + """) + self.checker.visit_module(None) + self.checker.visit_import(stmts[0]) + with self.assertAddsMessages(Message('W1201', node=stmts[1])): + self.checker.visit_callfunc(stmts[1]) + + def test_nonstandard_logging_module(self): + self.checker.config.logging_modules = ( + 'logging', 'my.logging') + stmts = test_utils.extract_node(""" + from my import logging as blogging #@ + blogging.warn('%s' % '%s') #@ + """) + self.checker.visit_module(None) + self.checker.visit_import(stmts[0]) + with self.assertAddsMessages(Message('W1201', node=stmts[1])): + self.checker.visit_callfunc(stmts[1]) + + +if __name__ == '__main__': + unittest_main() |
