summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--checkers/logging.py38
-rw-r--r--test/test_logging.py50
3 files changed, 85 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 32a74d3f1..3f62f1470 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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()