built-in checkers use [01-50] base message ids (closes #68057)

authorSylvain Thénault <sylvain.thenault@logilab.fr>
changeset51ee3f8f32c7
branchdefault
phasepublic
hiddenno
parent revision#2a5477c2a57f closes #70495: absolute imports fail depending on module path (patch by Jacek Konieczny)
child revision#d706dd303f1b add regular expression support for generated-members (closes #69738)
files modified by this revision
ChangeLog
checkers/__init__.py
checkers/logging.py
checkers/string_format.py
doc/features.txt
test/input/func_e12xx.py
test/input/func_e13xx.py
test/input/func_e65xx.py
test/input/func_e99xx.py
test/input/func_w1201.py
test/input/func_w6501.py
test/messages/func_e12xx.txt
test/messages/func_e13xx.txt
test/messages/func_e65xx.txt
test/messages/func_e99xx.txt
test/messages/func_w1201.txt
test/messages/func_w6501.txt
# HG changeset patch
# User Sylvain Thénault <sylvain.thenault@logilab.fr>
# Date 1310128329 -7200
# Fri Jul 08 14:32:09 2011 +0200
# Node ID 51ee3f8f32c7cc4f120916a98243053246ee7e8a
# Parent 2a5477c2a57f31ede1b54644ad94b87a832b8b14
built-in checkers use [01-50] base message ids (closes #68057)

diff --git a/ChangeLog b/ChangeLog
@@ -1,14 +1,18 @@
1  ChangeLog for PyLint
2  ====================
3 
4  	--
5 -	
6 +    * ids of logging and string_format checkers have been changed:
7 +      logging: 65 -> 12, string_format: 99 -> 13
8 +      Also add documentation to say that ids of range 1-50 shall be reserved
9 +      to pylint internal checkers
10 +
11      * #69993: Additional string format checks for logging module:
12        check for missing arguments, too many arguments, or invalid string
13        formats in the logging checker module. Contributed by Daniel Arena
14 -	
15 +
16      * #69220: add column offset to the reports. If you've a custom reporter,
17        this change may break it has now location gain a new item giving the
18        column offset.
19 
20      * #60828: Fix false positive in reimport check
diff --git a/checkers/__init__.py b/checkers/__init__.py
@@ -25,13 +25,18 @@
21  07: exceptions
22  08: similar
23  09: design_analysis
24  10: newstyle
25  11: typecheck
26 +12: logging
27 +13: string_format
28 +14-50: not yet used: reserved for future internal checkers.
29 +51-99: perhaps used: reserved for external checkers
30 
31  The raw_metrics checker has no number associated since it doesn't emit any
32  messages nor reports. XXX not true, emit a 07 report !
33 +
34  """
35 
36  import tokenize
37  from os import listdir
38  from os.path import dirname, join, isdir, splitext
diff --git a/checkers/logging.py b/checkers/logging.py
@@ -19,29 +19,29 @@
39  from pylint import interfaces
40  from pylint.checkers import utils
41 
42 
43  MSGS = {
44 -    'W6501': ('Specify string format arguments as logging function parameters',
45 +    'W1201': ('Specify string format arguments as logging function parameters',
46               'Used when a logging statement has a call form of '
47               '"logging.<logging method>(format_string % (format_args...))". '
48               'Such calls should leave string interpolation to the logging '
49               'method itself and be written '
50               '"logging.<logging method>(format_string, format_args...)" '
51               'so that the program may avoid incurring the cost of the '
52               'interpolation in those cases in which no message will be '
53               'logged. For more, see '
54               'http://www.python.org/dev/peps/pep-0282/.'),
55 -    'E6500': ('Unsupported logging format character %r (%#02x) at index %d',
56 +    'E1200': ('Unsupported logging format character %r (%#02x) at index %d',
57                'Used when an unsupported format character is used in a logging\
58                statement format string.'),
59 -    'E6501': ('Logging format string ends in middle of conversion specifier',
60 +    'E1201': ('Logging format string ends in middle of conversion specifier',
61                'Used when a logging statement format string terminates before\
62                the end of a conversion specifier.'),
63 -    'E6505': ('Too many arguments for logging format string',
64 +    'E1205': ('Too many arguments for logging format string',
65                'Used when a logging format string is given too few arguments.'),
66 -    'E6506': ('Not enough arguments for logging format string',
67 +    'E1206': ('Not enough arguments for logging format string',
68                'Used when a logging format string is given too many arguments'),
69      }
70 
71 
72  CHECKED_CONVENIENCE_FUNCTIONS = set([
@@ -88,11 +88,11 @@
73          if node.starargs or node.kwargs or not node.args:
74              # Either no args, star args, or double-star args. Beyond the
75              # scope of this checker.
76              return
77          if isinstance(node.args[0], astng.BinOp) and node.args[0].op == '%':
78 -            self.add_message('W6501', node=node)
79 +            self.add_message('W1201', node=node)
80          elif isinstance(node.args[0], astng.Const):
81              self._check_format_string(node, 0)
82 
83      def _check_log_methods(self, node):
84          """Checks calls to logging.log(level, format, *format_args)."""
@@ -101,11 +101,11 @@
85          if node.starargs or node.kwargs or len(node.args) < 2:
86              # Either a malformed call, star args, or double-star args. Beyond
87              # the scope of this checker.
88              return
89          if isinstance(node.args[1], astng.BinOp) and node.args[1].op == '%':
90 -            self.add_message('W6501', node=node)
91 +            self.add_message('W1201', node=node)
92          elif isinstance(node.args[1], astng.Const):
93              self._check_format_string(node, 1)
94 
95      def _check_format_string(self, node, format_arg):
96          """Checks that format string tokens match the supplied arguments.
@@ -132,19 +132,19 @@
97                      # Keyword checking on logging strings is complicated by
98                      # special keywords - out of scope.
99                      return
100              except utils.UnsupportedFormatCharacter, e:
101                  c = format_string[e.index]
102 -                self.add_message('E6500', node=node, args=(c, ord(c), e.index))
103 +                self.add_message('E1200', node=node, args=(c, ord(c), e.index))
104                  return
105              except utils.IncompleteFormatString:
106 -                self.add_message('E6501', node=node)
107 +                self.add_message('E1201', node=node)
108                  return
109          if num_args > required_num_args:
110 -            self.add_message('E6505', node=node)
111 +            self.add_message('E1205', node=node)
112          elif num_args < required_num_args:
113 -            self.add_message('E6506', node=node)
114 +            self.add_message('E1206', node=node)
115 
116      def _count_supplied_tokens(self, args):
117          """Counts the number of tokens in an args list.
118 
119          The Python log functions allow for special keyword arguments: func,
diff --git a/checkers/string_format.py b/checkers/string_format.py
@@ -24,39 +24,39 @@
120  from pylint.checkers import BaseChecker
121  from pylint.checkers import utils
122 
123 
124  MSGS = {
125 -    'E9900': ("Unsupported format character %r (%#02x) at index %d",
126 +    'E1300': ("Unsupported format character %r (%#02x) at index %d",
127                "Used when a unsupported format character is used in a format\
128                string."),
129 -    'E9901': ("Format string ends in middle of conversion specifier",
130 +    'E1301': ("Format string ends in middle of conversion specifier",
131                "Used when a format string terminates before the end of a \
132                conversion specifier."),
133 -    'E9902': ("Mixing named and unnamed conversion specifiers in format string",
134 +    'E1302': ("Mixing named and unnamed conversion specifiers in format string",
135                "Used when a format string contains both named (e.g. '%(foo)d') \
136                and unnamed (e.g. '%d') conversion specifiers.  This is also \
137                used when a named conversion specifier contains * for the \
138                minimum field width and/or precision."),
139 -    'E9903': ("Expected mapping for format string, not %s",
140 +    'E1303': ("Expected mapping for format string, not %s",
141                "Used when a format string that uses named conversion specifiers \
142                is used with an argument that is not a mapping."),
143 -    'W9900': ("Format string dictionary key should be a string, not %s",
144 +    'W1300': ("Format string dictionary key should be a string, not %s",
145                "Used when a format string that uses named conversion specifiers \
146                is used with a dictionary whose keys are not all strings."),
147 -    'W9901': ("Unused key %r in format string dictionary",
148 +    'W1301': ("Unused key %r in format string dictionary",
149                "Used when a format string that uses named conversion specifiers \
150                is used with a dictionary that conWtains keys not required by the \
151                format string."),
152 -    'E9904': ("Missing key %r in format string dictionary",
153 +    'E1304': ("Missing key %r in format string dictionary",
154                "Used when a format string that uses named conversion specifiers \
155                is used with a dictionary that doesn't contain all the keys \
156                required by the format string."),
157 -    'E9905': ("Too many arguments for format string",
158 +    'E1305': ("Too many arguments for format string",
159                "Used when a format string that uses unnamed conversion \
160                specifiers is given too few arguments."),
161 -    'E9906': ("Not enough arguments for format string",
162 +    'E1306': ("Not enough arguments for format string",
163                "Used when a format string that uses unnamed conversion \
164                specifiers is given too many arguments"),
165      }
166 
167  OTHER_NODES = (astng.Const, astng.List, astng.Backquote,
@@ -85,19 +85,19 @@
168          try:
169              required_keys, required_num_args = \
170                  utils.parse_format_string(format_string)
171          except utils.UnsupportedFormatCharacter, e:
172              c = format_string[e.index]
173 -            self.add_message('E9900', node=node, args=(c, ord(c), e.index))
174 +            self.add_message('E1300', node=node, args=(c, ord(c), e.index))
175              return
176          except utils.IncompleteFormatString:
177 -            self.add_message('E9901', node=node)
178 +            self.add_message('E1301', node=node)
179              return
180          if required_keys and required_num_args:
181              # The format string uses both named and unnamed format
182              # specifiers.
183 -            self.add_message('E9902', node=node)
184 +            self.add_message('E1302', node=node)
185          elif required_keys:
186              # The format string uses only named format specifiers.
187              # Check that the RHS of the % operator is a mapping object
188              # that contains precisely the set of keys required by the
189              # format string.
@@ -108,27 +108,27 @@
190                      if isinstance(k, astng.Const):
191                          key = k.value
192                          if isinstance(key, basestring):
193                              keys.add(key)
194                          else:
195 -                            self.add_message('W9900', node=node, args=key)
196 +                            self.add_message('W1300', node=node, args=key)
197                      else:
198                          # One of the keys was something other than a
199                          # constant.  Since we can't tell what it is,
200                          # supress checks for missing keys in the
201                          # dictionary.
202                          unknown_keys = True
203                  if not unknown_keys:
204                      for key in required_keys:
205                          if key not in keys:
206 -                            self.add_message('E9904', node=node, args=key)
207 +                            self.add_message('E1304', node=node, args=key)
208                  for key in keys:
209                      if key not in required_keys:
210 -                        self.add_message('W9901', node=node, args=key)
211 +                        self.add_message('W1301', node=node, args=key)
212              elif isinstance(args, OTHER_NODES + (astng.Tuple,)):
213                  type_name = type(args).__name__
214 -                self.add_message('E9903', node=node, args=type_name)
215 +                self.add_message('E1303', node=node, args=type_name)
216              # else:
217                  # The RHS of the format specifier is a name or
218                  # expression.  It may be a mapping object, so
219                  # there's nothing we can check.
220          else:
@@ -145,13 +145,13 @@
221                  # expression.  It could be a tuple of unknown size, so
222                  # there's nothing we can check.
223                  num_args = None
224              if num_args is not None:
225                  if num_args > required_num_args:
226 -                    self.add_message('E9905', node=node)
227 +                    self.add_message('E1305', node=node)
228                  elif num_args < required_num_args:
229 -                    self.add_message('E9906', node=node)
230 +                    self.add_message('E1306', node=node)
231 
232 
233  def register(linter):
234      """required method to auto register this checker """
235      linter.register_checker(StringFormatChecker(linter))
diff --git a/doc/features.txt b/doc/features.txt
@@ -103,18 +103,31 @@
236  logging checker
237  ---------------
238 
239  Messages
240  ~~~~~~~~
241 -:W6501: *Specify string format arguments as logging function parameters*
242 +:W1201: *Specify string format arguments as logging function parameters*
243    Used when a logging statement has a call form of "logging.<logging
244    method>(format_string % (format_args...))". Such calls should leave string
245    interpolation to the logging method itself and be written "logging.<logging
246    method>(format_string, format_args...)" so that the program may avoid
247    incurring the cost of the interpolation in those cases in which no message
248    will be logged. For more, see http://www.python.org/dev/peps/pep-0282/.
249 
250 +:E1200: *Unsupported logging format character %r (%#02x) at index %d*
251 +  Used when an unsupported format character is used in a logging statement 
252 +  format string.
253 +
254 +:E1201: *'Logging format string ends in middle of conversion specifier*
255 +  Used when a logging statement format string terminates before the end of a
256 +  conversion specifier.
257 +
258 +:E1205: *Too many arguments for logging format string*
259 +  Used when a logging format string is given too few arguments.
260 +
261 +:E1206: *Not enough arguments for logging format string*
262 +  Used when a logging format string is given too many arguments.
263 
264  similarities checker
265  --------------------
266 
267  Options
@@ -147,34 +160,34 @@
268  string_format checker
269  ---------------------
270 
271  Messages
272  ~~~~~~~~
273 -:E9900: *Unsupported format character %r (%#02x) at index %d*
274 +:E1300: *Unsupported format character %r (%#02x) at index %d*
275    Used when a unsupported format character is used in a format string.
276 -:E9901: *Format string ends in middle of conversion specifier*
277 +:E1301: *Format string ends in middle of conversion specifier*
278    Used when a format string terminates before the end of a conversion specifier.
279 -:E9902: *Mixing named and unnamed conversion specifiers in format string*
280 +:E1302: *Mixing named and unnamed conversion specifiers in format string*
281    Used when a format string contains both named (e.g. '%(foo)d') and unnamed
282    (e.g. '%d') conversion specifiers. This is also used when a named conversion
283    specifier contains * for the minimum field width and/or precision.
284 -:E9903: *Expected mapping for format string, not %s*
285 +:E1303: *Expected mapping for format string, not %s*
286    Used when a format string that uses named conversion specifiers is used with
287    an argument that is not a mapping.
288 -:E9904: *Missing key %r in format string dictionary*
289 +:E1304: *Missing key %r in format string dictionary*
290    Used when a format string that uses named conversion specifiers is used with a
291    dictionary that doesn't contain all the keys required by the format string.
292 -:E9905: *Too many arguments for format string*
293 +:E1305: *Too many arguments for format string*
294    Used when a format string that uses unnamed conversion specifiers is given too
295    few arguments.
296 -:E9906: *Not enough arguments for format string*
297 +:E1306: *Not enough arguments for format string*
298    Used when a format string that uses unnamed conversion specifiers is given too
299    many arguments
300 -:W9900: *Format string dictionary key should be a string, not %s*
301 +:W1300: *Format string dictionary key should be a string, not %s*
302    Used when a format string that uses named conversion specifiers is used with a
303    dictionary whose keys are not all strings.
304 -:W9901: *Unused key %r in format string dictionary*
305 +:W1301: *Unused key %r in format string dictionary*
306    Used when a format string that uses named conversion specifiers is used with a
307    dictionary that conWtains keys not required by the format string.
308 
309 
310  format checker
@@ -655,10 +668,13 @@
311  :W0105: *String statement has no effect*
312    Used when a string is used as a statement (which of course has no effect).
313    This is a particular case of W0104 with its own message so you can easily
314    disable it if you're using those strings as documentation, instead of
315    comments.
316 +:W0106: *Expression "%s" is assigned to nothing',*
317 +  Used when an expression that is not a function call is assigned to nothing. 
318 +  Probably something else was intended.
319  :W0107: *Unnecessary pass statement*
320    Used when a "pass" statement that can be avoided is encountered.)
321  :W0108: *Lambda may not be necessary*
322    Used when the body of a lambda expression is a function call on the same
323    argument list as the lambda itself; such lambda expressions are in all but a
diff --git a/test/input/func_e65xx.py b/test/input/func_e12xx.py
@@ -8,16 +8,16 @@
324 
325  def pprint():
326      """Test string format in logging statements.
327      """
328      # These should all emit lint errors:
329 -    logging.info(0, '') # 6505
330 -    logging.info('', '') # 6505
331 -    logging.info('%s%', '') # 6501
332 -    logging.info('%s%s', '') # 6506
333 -    logging.info('%s%a', '', '') # 6500
334 -    logging.info('%s%s', '', '', '') # 6505
335 +    logging.info(0, '') # 1205
336 +    logging.info('', '') # 1205
337 +    logging.info('%s%', '') # 1201
338 +    logging.info('%s%s', '') # 1206
339 +    logging.info('%s%a', '', '') # 1200
340 +    logging.info('%s%s', '', '', '') # 1205
341 
342      # These should be okay:
343      logging.info(1)
344      logging.info(True)
345      logging.info('')
diff --git a/test/input/func_e99xx.py b/test/input/func_e13xx.py
@@ -6,16 +6,16 @@
346  PARG_1 = PARG_2 = PARG_3 = 1
347 
348  def pprint():
349      """Test string format
350      """
351 -    print "%s %s" % {'PARG_1': 1, 'PARG_2': 2} # E9906
352 -    print "%s" % (PARG_1, PARG_2) # E9905
353 -    print "%(PARG_1)d %d" % {'PARG_1': 1, 'PARG_2': 2} # E9902
354 -    print "%(PARG_1)d %(PARG_2)d" % {'PARG_1': 1} # E9904
355 -    print "%(PARG_1)d %(PARG_2)d" % {'PARG_1': 1, 'PARG_2':2, 'PARG_3':3}#W9901
356 -    print "%(PARG_1)d %(PARG_2)d" % {'PARG_1': 1, 2:3} # W9900 E9904
357 -    print "%(PARG_1)d %(PARG_2)d" % (2, 3) # 9903
358 -    print "%(PARG_1)d %(PARG_2)d" % [2, 3] # 9903
359 +    print "%s %s" % {'PARG_1': 1, 'PARG_2': 2} # E1306
360 +    print "%s" % (PARG_1, PARG_2) # E1305
361 +    print "%(PARG_1)d %d" % {'PARG_1': 1, 'PARG_2': 2} # E1302
362 +    print "%(PARG_1)d %(PARG_2)d" % {'PARG_1': 1} # E1304
363 +    print "%(PARG_1)d %(PARG_2)d" % {'PARG_1': 1, 'PARG_2':2, 'PARG_3':3}#W1301
364 +    print "%(PARG_1)d %(PARG_2)d" % {'PARG_1': 1, 2:3} # W1300 E1304
365 +    print "%(PARG_1)d %(PARG_2)d" % (2, 3) # 1303
366 +    print "%(PARG_1)d %(PARG_2)d" % [2, 3] # 1303
367      print "%2z" % PARG_1
368      print "strange format %2" % PARG_2
369 
diff --git a/test/input/func_w6501.py b/test/input/func_w1201.py
diff --git a/test/messages/func_e65xx.txt b/test/messages/func_e12xx.txt
diff --git a/test/messages/func_e99xx.txt b/test/messages/func_e13xx.txt
diff --git a/test/messages/func_w6501.txt b/test/messages/func_w1201.txt