Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(165)

Side by Side Diff: third_party/pylint/checkers/logging.py

Issue 753543006: pylint: upgrade to 1.4.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/pylint/checkers/imports.py ('k') | third_party/pylint/checkers/misc.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2009-2010 Google, Inc. 1 # Copyright (c) 2009-2010 Google, Inc.
2 # This program is free software; you can redistribute it and/or modify it under 2 # This program is free software; you can redistribute it and/or modify it under
3 # the terms of the GNU General Public License as published by the Free Software 3 # the terms of the GNU General Public License as published by the Free Software
4 # Foundation; either version 2 of the License, or (at your option) any later 4 # Foundation; either version 2 of the License, or (at your option) any later
5 # version. 5 # version.
6 # 6 #
7 # This program is distributed in the hope that it will be useful, but WITHOUT 7 # This program is distributed in the hope that it will be useful, but WITHOUT
8 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10 # 10 #
11 # You should have received a copy of the GNU General Public License along with 11 # You should have received a copy of the GNU General Public License along with
12 # this program; if not, write to the Free Software Foundation, Inc., 12 # this program; if not, write to the Free Software Foundation, Inc.,
13 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 13 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14 """checker for use of Python logging 14 """checker for use of Python logging
15 """ 15 """
16 16
17 import astroid 17 import astroid
18 from pylint import checkers 18 from pylint import checkers
19 from pylint import interfaces 19 from pylint import interfaces
20 from pylint.checkers import utils 20 from pylint.checkers import utils
21 from pylint.checkers.utils import check_messages 21 from pylint.checkers.utils import check_messages
22 22
23 import six
24
25
23 MSGS = { 26 MSGS = {
24 'W1201': ('Specify string format arguments as logging function parameters', 27 'W1201': ('Specify string format arguments as logging function parameters',
25 'logging-not-lazy', 28 'logging-not-lazy',
26 'Used when a logging statement has a call form of ' 29 'Used when a logging statement has a call form of '
27 '"logging.<logging method>(format_string % (format_args...))". ' 30 '"logging.<logging method>(format_string % (format_args...))". '
28 'Such calls should leave string interpolation to the logging ' 31 'Such calls should leave string interpolation to the logging '
29 'method itself and be written ' 32 'method itself and be written '
30 '"logging.<logging method>(format_string, format_args...)" ' 33 '"logging.<logging method>(format_string, format_args...)" '
31 'so that the program may avoid incurring the cost of the ' 34 'so that the program may avoid incurring the cost of the '
32 'interpolation in those cases in which no message will be ' 35 'interpolation in those cases in which no message will be '
33 'logged. For more, see ' 36 'logged. For more, see '
34 'http://www.python.org/dev/peps/pep-0282/.'), 37 'http://www.python.org/dev/peps/pep-0282/.'),
38 'W1202': ('Use % formatting in logging functions but pass the % '
39 'parameters as arguments',
40 'logging-format-interpolation',
41 'Used when a logging statement has a call form of '
42 '"logging.<logging method>(format_string.format(format_args...))"'
43 '. Such calls should use % formatting instead, but leave '
44 'interpolation to the logging function by passing the parameters '
45 'as arguments.'),
35 'E1200': ('Unsupported logging format character %r (%#02x) at index %d', 46 'E1200': ('Unsupported logging format character %r (%#02x) at index %d',
36 'logging-unsupported-format', 47 'logging-unsupported-format',
37 'Used when an unsupported format character is used in a logging\ 48 'Used when an unsupported format character is used in a logging\
38 statement format string.'), 49 statement format string.'),
39 'E1201': ('Logging format string ends in middle of conversion specifier', 50 'E1201': ('Logging format string ends in middle of conversion specifier',
40 'logging-format-truncated', 51 'logging-format-truncated',
41 'Used when a logging statement format string terminates before\ 52 'Used when a logging statement format string terminates before\
42 the end of a conversion specifier.'), 53 the end of a conversion specifier.'),
43 'E1205': ('Too many arguments for logging format string', 54 'E1205': ('Too many arguments for logging format string',
44 'logging-too-many-args', 55 'logging-too-many-args',
45 'Used when a logging format string is given too few arguments.'), 56 'Used when a logging format string is given too few arguments.'),
46 'E1206': ('Not enough arguments for logging format string', 57 'E1206': ('Not enough arguments for logging format string',
47 'logging-too-few-args', 58 'logging-too-few-args',
48 'Used when a logging format string is given too many arguments'), 59 'Used when a logging format string is given too many arguments'),
49 } 60 }
50 61
51 62
52 CHECKED_CONVENIENCE_FUNCTIONS = set([ 63 CHECKED_CONVENIENCE_FUNCTIONS = set([
53 'critical', 'debug', 'error', 'exception', 'fatal', 'info', 'warn', 64 'critical', 'debug', 'error', 'exception', 'fatal', 'info', 'warn',
54 'warning']) 65 'warning'])
55 66
67 def is_method_call(callfunc_node, types=(), methods=()):
68 """Determines if a CallFunc node represents a method call.
69
70 Args:
71 callfunc_node: The CallFunc AST node to check.
72 types: Optional sequence of caller type names to restrict check.
73 methods: Optional sequence of method names to restrict check.
74
75 Returns:
76 True, if the node represents a method call for the given type and
77 method names, False otherwise.
78 """
79 if not isinstance(callfunc_node, astroid.CallFunc):
80 return False
81 func = utils.safe_infer(callfunc_node.func)
82 return (isinstance(func, astroid.BoundMethod)
83 and isinstance(func.bound, astroid.Instance)
84 and (func.bound.name in types if types else True)
85 and (func.name in methods if methods else True))
86
87
56 88
57 class LoggingChecker(checkers.BaseChecker): 89 class LoggingChecker(checkers.BaseChecker):
58 """Checks use of the logging module.""" 90 """Checks use of the logging module."""
59 91
60 __implements__ = interfaces.IAstroidChecker 92 __implements__ = interfaces.IAstroidChecker
61 name = 'logging' 93 name = 'logging'
62 msgs = MSGS 94 msgs = MSGS
63 95
64 options = (('logging-modules', 96 options = (('logging-modules',
65 {'default' : ('logging',), 97 {'default': ('logging',),
66 'type' : 'csv', 98 'type': 'csv',
67 'metavar' : '<comma separated list>', 99 'metavar': '<comma separated list>',
68 'help' : 'Logging modules to check that the string format ' 100 'help': 'Logging modules to check that the string format '
69 'arguments are in logging function parameter format'} 101 'arguments are in logging function parameter format'}
70 ), 102 ),
71 ) 103 )
72 104
73 def visit_module(self, unused_node): 105 def visit_module(self, node): # pylint: disable=unused-argument
74 """Clears any state left in this checker from last module checked.""" 106 """Clears any state left in this checker from last module checked."""
75 # The code being checked can just as easily "import logging as foo", 107 # The code being checked can just as easily "import logging as foo",
76 # so it is necessary to process the imports and store in this field 108 # so it is necessary to process the imports and store in this field
77 # what name the logging module is actually given. 109 # what name the logging module is actually given.
78 self._logging_names = set() 110 self._logging_names = set()
79 logging_mods = self.config.logging_modules 111 logging_mods = self.config.logging_modules
80 112
81 self._logging_modules = set(logging_mods) 113 self._logging_modules = set(logging_mods)
82 self._from_imports = {} 114 self._from_imports = {}
83 for logging_mod in logging_mods: 115 for logging_mod in logging_mods:
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 if node.starargs or node.kwargs or not node.args: 175 if node.starargs or node.kwargs or not node.args:
144 # Either no args, star args, or double-star args. Beyond the 176 # Either no args, star args, or double-star args. Beyond the
145 # scope of this checker. 177 # scope of this checker.
146 return 178 return
147 format_pos = 0 179 format_pos = 0
148 else: 180 else:
149 return 181 return
150 182
151 if isinstance(node.args[format_pos], astroid.BinOp) and node.args[format _pos].op == '%': 183 if isinstance(node.args[format_pos], astroid.BinOp) and node.args[format _pos].op == '%':
152 self.add_message('logging-not-lazy', node=node) 184 self.add_message('logging-not-lazy', node=node)
185 elif isinstance(node.args[format_pos], astroid.CallFunc):
186 self._check_call_func(node.args[format_pos])
153 elif isinstance(node.args[format_pos], astroid.Const): 187 elif isinstance(node.args[format_pos], astroid.Const):
154 self._check_format_string(node, format_pos) 188 self._check_format_string(node, format_pos)
155 189
190 def _check_call_func(self, callfunc_node):
191 """Checks that function call is not format_string.format().
192
193 Args:
194 callfunc_node: CallFunc AST node to be checked.
195 """
196 if is_method_call(callfunc_node, ('str', 'unicode'), ('format',)):
197 self.add_message('logging-format-interpolation', node=callfunc_node)
198
156 def _check_format_string(self, node, format_arg): 199 def _check_format_string(self, node, format_arg):
157 """Checks that format string tokens match the supplied arguments. 200 """Checks that format string tokens match the supplied arguments.
158 201
159 Args: 202 Args:
160 node: AST node to be checked. 203 node: AST node to be checked.
161 format_arg: Index of the format string in the node arguments. 204 format_arg: Index of the format string in the node arguments.
162 """ 205 """
163 num_args = _count_supplied_tokens(node.args[format_arg + 1:]) 206 num_args = _count_supplied_tokens(node.args[format_arg + 1:])
164 if not num_args: 207 if not num_args:
165 # If no args were supplied, then all format strings are valid - 208 # If no args were supplied, then all format strings are valid -
166 # don't check any further. 209 # don't check any further.
167 return 210 return
168 format_string = node.args[format_arg].value 211 format_string = node.args[format_arg].value
169 if not isinstance(format_string, basestring): 212 if not isinstance(format_string, six.string_types):
170 # If the log format is constant non-string (e.g. logging.debug(5)), 213 # If the log format is constant non-string (e.g. logging.debug(5)),
171 # ensure there are no arguments. 214 # ensure there are no arguments.
172 required_num_args = 0 215 required_num_args = 0
173 else: 216 else:
174 try: 217 try:
175 keyword_args, required_num_args = \ 218 keyword_args, required_num_args = \
176 utils.parse_format_string(format_string) 219 utils.parse_format_string(format_string)
177 if keyword_args: 220 if keyword_args:
178 # Keyword checking on logging strings is complicated by 221 # Keyword checking on logging strings is complicated by
179 # special keywords - out of scope. 222 # special keywords - out of scope.
180 return 223 return
181 except utils.UnsupportedFormatCharacter, ex: 224 except utils.UnsupportedFormatCharacter as ex:
182 char = format_string[ex.index] 225 char = format_string[ex.index]
183 self.add_message('logging-unsupported-format', node=node, 226 self.add_message('logging-unsupported-format', node=node,
184 args=(char, ord(char), ex.index)) 227 args=(char, ord(char), ex.index))
185 return 228 return
186 except utils.IncompleteFormatString: 229 except utils.IncompleteFormatString:
187 self.add_message('logging-format-truncated', node=node) 230 self.add_message('logging-format-truncated', node=node)
188 return 231 return
189 if num_args > required_num_args: 232 if num_args > required_num_args:
190 self.add_message('logging-too-many-args', node=node) 233 self.add_message('logging-too-many-args', node=node)
191 elif num_args < required_num_args: 234 elif num_args < required_num_args:
(...skipping 12 matching lines...) Expand all
204 247
205 Returns: 248 Returns:
206 Number of AST nodes that aren't keywords. 249 Number of AST nodes that aren't keywords.
207 """ 250 """
208 return sum(1 for arg in args if not isinstance(arg, astroid.Keyword)) 251 return sum(1 for arg in args if not isinstance(arg, astroid.Keyword))
209 252
210 253
211 def register(linter): 254 def register(linter):
212 """Required method to auto-register this checker.""" 255 """Required method to auto-register this checker."""
213 linter.register_checker(LoggingChecker(linter)) 256 linter.register_checker(LoggingChecker(linter))
OLDNEW
« no previous file with comments | « third_party/pylint/checkers/imports.py ('k') | third_party/pylint/checkers/misc.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698