# HG changeset patch
# User Martin Pool <mbp@google.com>
# Date 1348067743 -7200
# Wed Sep 19 17:15:43 2012 +0200
# Node ID b9dab5059b81ed2b5f85e74b8b4b14a7c14143db
# Parent b40e3b4bc00692ccb503520cb689bc8d03d33cbd
Closes #104572: symbolic warning names in output (by Martin Pool)
triggered whatever the format using a command line option
# User Martin Pool <mbp@google.com>
# Date 1348067743 -7200
# Wed Sep 19 17:15:43 2012 +0200
# Node ID b9dab5059b81ed2b5f85e74b8b4b14a7c14143db
# Parent b40e3b4bc00692ccb503520cb689bc8d03d33cbd
Closes #104572: symbolic warning names in output (by Martin Pool)
triggered whatever the format using a command line option
@@ -63,9 +63,10 @@
1 * Benjamin Niemann: patch to allow block level enabling/disabling of messages 2 * Nathaniel Manista: suspicious lambda checking 3 * Wolfgang Grafen, Axel Muller, Fabio Zadrozny, Pierre Rouleau, 4 Maarten ter Huurne, Mirko Friedenhagen (among others): 5 bug reports, feedback, feature requests... 6 -* Martin Pool (Google): warnings for anomalous backslashes 7 +* Martin Pool (Google): warnings for anomalous backslashes, symbolic names 8 + for messages (like 'unused') 9 * All the Logilab's team: daily use, bug reports, feature requests 10 * Other people have contributed by their feedback, if I've forgotten 11 you, send me a note !
@@ -122,31 +122,39 @@
12 name = 'basic' 13 14 class BasicErrorChecker(_BasicChecker): 15 msgs = { 16 'E0100': ('__init__ method is a generator', 17 + 'init-is-generator', 18 'Used when the special class method __init__ is turned into a ' 19 'generator by a yield in its body.'), 20 'E0101': ('Explicit return in __init__', 21 + 'return-in-init', 22 'Used when the special class method __init__ has an explicit \ 23 return value.'), 24 'E0102': ('%s already defined line %s', 25 + 'function-redefined', 26 'Used when a function / class / method is redefined.'), 27 'E0103': ('%r not properly in loop', 28 + 'not-in-loop', 29 'Used when break or continue keywords are used outside a loop.'), 30 31 'E0104': ('Return outside function', 32 + 'return-outside-function', 33 'Used when a "return" statement is found outside a function or ' 34 'method.'), 35 'E0105': ('Yield outside function', 36 + 'yield-outside-function', 37 'Used when a "yield" statement is found outside a function or ' 38 'method.'), 39 'E0106': ('Return with argument inside generator', 40 + 'return-arg-in-generator', 41 'Used when a "return" statement with an argument is found ' 42 'outside in a generator function or method (e.g. with some ' 43 '"yield" statements).'), 44 'E0107': ("Use of the non-existent %s operator", 45 + 'nonexistent-operator', 46 "Used when you attempt to use the C-style pre-increment or" 47 "pre-decrement operator -- and ++, which doesn't exist in Python."), 48 } 49 50 def __init__(self, linter):
@@ -240,58 +248,71 @@
51 __implements__ = IASTNGChecker 52 53 name = 'basic' 54 msgs = { 55 'W0101': ('Unreachable code', 56 + 'unreachable', 57 'Used when there is some code behind a "return" or "raise" \ 58 statement, which will never be accessed.'), 59 'W0102': ('Dangerous default value %s as argument', 60 + 'dangerous-default-value', 61 'Used when a mutable value as list or dictionary is detected in \ 62 a default value for an argument.'), 63 'W0104': ('Statement seems to have no effect', 64 + 'pointless-statement', 65 'Used when a statement doesn\'t have (or at least seems to) \ 66 any effect.'), 67 'W0105': ('String statement has no effect', 68 + 'pointless-string-statement', 69 'Used when a string is used as a statement (which of course \ 70 has no effect). This is a particular case of W0104 with its \ 71 own message so you can easily disable it if you\'re using \ 72 those strings as documentation, instead of comments.'), 73 'W0106': ('Expression "%s" is assigned to nothing', 74 + 'expression-not-assigned', 75 'Used when an expression that is not a function call is assigned\ 76 to nothing. Probably something else was intended.'), 77 'W0108': ('Lambda may not be necessary', 78 + 'unnecessary-lambda', 79 'Used when the body of a lambda expression is a function call \ 80 on the same argument list as the lambda itself; such lambda \ 81 expressions are in all but a few cases replaceable with the \ 82 function being called in the body of the lambda.'), 83 'W0109': ("Duplicate key %r in dictionary", 84 + 'duplicate-key', 85 "Used when a dictionary expression binds the same key multiple \ 86 times."), 87 'W0122': ('Use of the exec statement', 88 + 'exec-statement', 89 'Used when you use the "exec" statement, to discourage its \ 90 usage. That doesn\'t mean you can not use it !'), 91 92 'W0141': ('Used builtin function %r', 93 + 'bad-builtin', 94 'Used when a black listed builtin function is used (see the ' 95 'bad-function option). Usual black listed functions are the ones ' 96 'like map, or filter , where Python offers now some cleaner ' 97 'alternative like list comprehension.'), 98 'W0142': ('Used * or ** magic', 99 + 'star-args', 100 'Used when a function or method is called using `*args` or ' 101 '`**kwargs` to dispatch arguments. This doesn\'t improve ' 102 'readability and should be used with care.'), 103 'W0150': ("%s statement in finally block may swallow exception", 104 + 'lost-exception', 105 "Used when a break or a return statement is found inside the \ 106 finally clause of a try...finally block: the exceptions raised \ 107 in the try clause will be silently swallowed instead of being \ 108 re-raised."), 109 'W0199': ('Assert called on a 2-uple. Did you mean \'assert x,y\'?', 110 + 'assert-on-tuple', 111 'A call of assert on a tuple will always evaluate to true if ' 112 'the tuple is not empty, and will always evaluate to false if ' 113 'it is.'), 114 115 'C0121': ('Missing required attribute "%s"', # W0103 116 + 'missing-module-attribute', 117 'Used when an attribute required for modules is missing.'), 118 119 } 120 121 options = (('required-attributes',
@@ -556,13 +577,15 @@
122 123 124 class NameChecker(_BasicChecker): 125 msgs = { 126 'C0102': ('Black listed name "%s"', 127 + 'blacklisted-name', 128 'Used when the name is listed in the black list (unauthorized \ 129 names).'), 130 'C0103': ('Invalid name "%s" (should match %s)', 131 + 'invalid-name', 132 'Used when the name doesn\'t match the regular expression \ 133 associated to its type (constant, variable, class...).'), 134 135 } 136 options = (('module-rgx',
@@ -707,14 +730,16 @@
137 138 139 class DocStringChecker(_BasicChecker): 140 msgs = { 141 'C0111': ('Missing docstring', # W0131 142 + 'missing-docstring', 143 'Used when a module, function, class or method has no docstring.\ 144 Some special methods like __init__ doesn\'t necessary require a \ 145 docstring.'), 146 'C0112': ('Empty docstring', # W0132 147 + 'empty-docstring', 148 'Used when a module, function, class or method has an empty \ 149 docstring (it would be too easy ;).'), 150 } 151 options = (('no-docstring-rgx', 152 {'default' : NO_REQUIRED_DOC_RGX,
@@ -766,10 +791,11 @@
153 154 155 class PassChecker(_BasicChecker): 156 """check is the pass statement is really necessary""" 157 msgs = {'W0107': ('Unnecessary pass statement', 158 + 'unnecessary-pass', 159 'Used when a "pass" statement that can be avoided is ' 160 'encountered.)'), 161 } 162 163 def visit_pass(self, node):
@@ -36,91 +36,112 @@
164 return False 165 166 167 MSGS = { 168 'F0202': ('Unable to check methods signature (%s / %s)', 169 + 'method-check-failed', 170 'Used when PyLint has been unable to check methods signature \ 171 compatibility for an unexpected reason. Please report this kind \ 172 if you don\'t make sense of it.'), 173 174 'E0202': ('An attribute affected in %s line %s hide this method', 175 + 'method-hidden', 176 'Used when a class defines a method which is hidden by an ' 177 'instance attribute from an ancestor class or set by some ' 178 'client code.'), 179 'E0203': ('Access to member %r before its definition line %s', 180 + 'access-member-before-definition', 181 'Used when an instance member is accessed before it\'s actually\ 182 assigned.'), 183 'W0201': ('Attribute %r defined outside __init__', 184 + 'attribute-defined-outside-init', 185 'Used when an instance attribute is defined outside the __init__\ 186 method.'), 187 188 'W0212': ('Access to a protected member %s of a client class', # E0214 189 + 'protected-access', 190 'Used when a protected member (i.e. class member with a name \ 191 beginning with an underscore) is access outside the class or a \ 192 descendant of the class where it\'s defined.'), 193 194 'E0211': ('Method has no argument', 195 + 'no-method-argument', 196 'Used when a method which should have the bound instance as \ 197 first argument has no argument defined.'), 198 'E0213': ('Method should have "self" as first argument', 199 + 'no-self-argument', 200 'Used when a method has an attribute different the "self" as\ 201 first argument. This is considered as an error since this is\ 202 a so common convention that you shouldn\'t break it!'), 203 'C0202': ('Class method %s should have %s as first argument', # E0212 204 + 'bad-classmethod-argument', 205 'Used when a class method has a first argument named differently ' 206 'than the value specified in valid-classmethod-first-arg option ' 207 '(default to "cls"), recommended to easily differentiate them ' 208 'from regular instance methods.'), 209 'C0203': ('Metaclass method %s should have %s as first argument', # E0214 210 + 'bad-mcs-method-argument', 211 'Used when a metaclass method has a first agument named ' 212 'differently than the value specified in valid-classmethod-first' 213 '-arg option (default to "cls"), recommended to easily ' 214 'differentiate them from regular instance methods.'), 215 'C0204': ('Metaclass class method %s should have %s as first argument', 216 + 'bad-mcs-classmethod-argument', 217 'Used when a metaclass class method has a first argument named ' 218 'differently than the value specified in valid-metaclass-' 219 'classmethod-first-arg option (default to "mcs"), recommended to ' 220 'easily differentiate them from regular instance methods.'), 221 222 'W0211': ('Static method with %r as first argument', 223 + 'bad-staticmethod-argument', 224 'Used when a static method has "self" or a value specified in ' 225 'valid-classmethod-first-arg option or ' 226 'valid-metaclass-classmethod-first-arg option as first argument.' 227 ), 228 'R0201': ('Method could be a function', 229 + 'no-self-use', 230 'Used when a method doesn\'t use its bound instance, and so could\ 231 be written as a function.' 232 ), 233 234 'E0221': ('Interface resolved to %s is not a class', 235 + 'interface-is-not-class', 236 'Used when a class claims to implement an interface which is not \ 237 a class.'), 238 'E0222': ('Missing method %r from %s interface', 239 + 'missing-interface-method', 240 'Used when a method declared in an interface is missing from a \ 241 class implementing this interface'), 242 'W0221': ('Arguments number differs from %s method', 243 + 'arguments-differ', 244 'Used when a method has a different number of arguments than in \ 245 the implemented interface or in an overridden method.'), 246 'W0222': ('Signature differs from %s method', 247 + 'signature-differs', 248 'Used when a method signature is different than in the \ 249 implemented interface or in an overridden method.'), 250 'W0223': ('Method %r is abstract in class %r but is not overridden', 251 + 'abstract-method', 252 'Used when an abstract method (i.e. raise NotImplementedError) is \ 253 not overridden in concrete class.' 254 ), 255 'F0220': ('failed to resolve interfaces implemented by %s (%s)', # W0224 256 + 'unresolved-interface', 257 'Used when a PyLint as failed to find interfaces implemented by \ 258 a class'), 259 260 261 'W0231': ('__init__ method from base class %r is not called', 262 + 'super-init-not-called', 263 'Used when an ancestor class method has an __init__ method \ 264 which is not called by a derived class.'), 265 'W0232': ('Class has no __init__ method', 266 + 'no-init', 267 'Used when a class has no __init__ method, neither its parent \ 268 classes.'), 269 'W0233': ('__init__ method from a non direct base class %r is called', 270 + 'non-parent-init-called', 271 'Used when an __init__ method is called on a class which is not \ 272 in the direct ancestors for the analysed class.'), 273 274 } 275
@@ -41,42 +41,54 @@
276 return False 277 278 279 MSGS = { 280 'R0901': ('Too many ancestors (%s/%s)', 281 + 'too-many-ancestors', 282 'Used when class has too many parent classes, try to reduce \ 283 this to get a more simple (and so easier to use) class.'), 284 'R0902': ('Too many instance attributes (%s/%s)', 285 + 'too-many-instance-attributes', 286 'Used when class has too many instance attributes, try to reduce \ 287 this to get a more simple (and so easier to use) class.'), 288 'R0903': ('Too few public methods (%s/%s)', 289 + 'too-few-public-methods', 290 'Used when class has too few public methods, so be sure it\'s \ 291 really worth it.'), 292 'R0904': ('Too many public methods (%s/%s)', 293 + 'too-many-public-methods', 294 'Used when class has too many public methods, try to reduce \ 295 this to get a more simple (and so easier to use) class.'), 296 297 'R0911': ('Too many return statements (%s/%s)', 298 + 'too-many-return-statements', 299 'Used when a function or method has too many return statement, \ 300 making it hard to follow.'), 301 'R0912': ('Too many branches (%s/%s)', 302 + 'too-many-branches', 303 'Used when a function or method has too many branches, \ 304 making it hard to follow.'), 305 'R0913': ('Too many arguments (%s/%s)', 306 + 'too-many-arguments', 307 'Used when a function or method takes too many arguments.'), 308 'R0914': ('Too many local variables (%s/%s)', 309 + 'too-many-locals', 310 'Used when a function or method has too many local variables.'), 311 'R0915': ('Too many statements (%s/%s)', 312 + 'too-many-statements', 313 'Used when a function or method has too many statements. You \ 314 should then split it in smaller functions / methods.'), 315 316 'R0921': ('Abstract class not referenced', 317 + 'abstract-class-not-used', 318 'Used when an abstract class is not used as ancestor anywhere.'), 319 'R0922': ('Abstract class is only referenced %s times', 320 + 'abstract-class-little-used', 321 'Used when an abstract class is used less than X times as \ 322 ancestor.'), 323 'R0923': ('Interface not implemented', 324 + 'interface-not-implemented', 325 'Used when an interface class is not implemented anywhere.'), 326 } 327 328 329 class MisdesignChecker(BaseChecker):
@@ -27,40 +27,49 @@
330 331 332 OVERGENERAL_EXCEPTIONS = ('Exception',) 333 334 MSGS = { 335 - 'E0701': ( 336 - 'Bad except clauses order (%s)', 337 - 'Used when except clauses are not in the correct order (from the \ 338 - more specific to the more generic). If you don\'t fix the order, \ 339 - some exceptions may not be catched by the most specific handler.'), 340 + 'E0701': ('Bad except clauses order (%s)', 341 + 'bad-except-order', 342 + 'Used when except clauses are not in the correct order (from the ' 343 + 'more specific to the more generic). If you don\'t fix the order, ' 344 + 'some exceptions may not be catched by the most specific handler.'), 345 'E0702': ('Raising %s while only classes, instances or string are allowed', 346 + 'raising-bad-type', 347 'Used when something which is neither a class, an instance or a \ 348 string is raised (i.e. a `TypeError` will be raised).'), 349 'E0710': ('Raising a new style class which doesn\'t inherit from BaseException', 350 + 'raising-non-exception', 351 'Used when a new style class which doesn\'t inherit from \ 352 BaseException is raised.'), 353 'E0711': ('NotImplemented raised - should raise NotImplementedError', 354 + 'notimplemented-raised', 355 'Used when NotImplemented is raised instead of \ 356 NotImplementedError'), 357 358 'W0701': ('Raising a string exception', 359 + 'raising-string', 360 'Used when a string exception is raised.'), 361 'W0702': ('No exception type(s) specified', 362 + 'bare-except', 363 'Used when an except clause doesn\'t specify exceptions type to \ 364 catch.'), 365 'W0703': ('Catching too general exception %s', 366 + 'broad-except', 367 'Used when an except catches a too general exception, \ 368 possibly burying unrelated errors.'), 369 'W0704': ('Except doesn\'t do anything', 370 + 'pointless-except', 371 'Used when an except clause does nothing but "pass" and there is\ 372 no "else" clause.'), 373 'W0710': ('Exception doesn\'t inherit from standard "Exception" class', 374 + 'nonstandard-exception', 375 'Used when a custom exception class is raised but doesn\'t \ 376 inherit from the builtin "Exception" class.'), 377 'W0711': ('Exception to catch is the result of a binary "%s" operation', 378 + 'binary-op-exception', 379 'Used when the exception to catch is of the form \ 380 "except A or B:". If intending to catch multiple, \ 381 rewrite as "except (A, B):"'), 382 } 383
@@ -35,46 +35,58 @@
384 from pylint.checkers import BaseRawChecker 385 from pylint.checkers.utils import check_messages 386 387 MSGS = { 388 'C0301': ('Line too long (%s/%s)', 389 + 'line-too-long', 390 'Used when a line is longer than a given number of characters.'), 391 'C0302': ('Too many lines in module (%s)', # was W0302 392 + 'too-many-lines', 393 'Used when a module has too much lines, reducing its readability.' 394 ), 395 396 'W0311': ('Bad indentation. Found %s %s, expected %s', 397 + 'bad-indentation', 398 'Used when an unexpected number of indentation\'s tabulations or ' 399 'spaces has been found.'), 400 'W0312': ('Found indentation with %ss instead of %ss', 401 + 'mixed-indentation', 402 'Used when there are some mixed tabs and spaces in a module.'), 403 'W0301': ('Unnecessary semicolon', # was W0106 404 + 'unnecessary-semicolon', 405 'Used when a statement is ended by a semi-colon (";"), which \ 406 isn\'t necessary (that\'s python, not C ;).'), 407 'C0321': ('More than one statement on a single line', 408 + 'multiple-statements', 409 'Used when more than on statement are found on the same line.'), 410 'C0322': ('Operator not preceded by a space\n%s', 411 + 'no-space-before-operator', 412 'Used when one of the following operator (!= | <= | == | >= | < ' 413 '| > | = | \\+= | -= | \\*= | /= | %) is not preceded by a space.'), 414 'C0323': ('Operator not followed by a space\n%s', 415 + 'no-space-after-operator', 416 'Used when one of the following operator (!= | <= | == | >= | < ' 417 '| > | = | \\+= | -= | \\*= | /= | %) is not followed by a space.'), 418 'C0324': ('Comma not followed by a space\n%s', 419 + 'no-space-after-comma', 420 'Used when a comma (",") is not followed by a space.'), 421 } 422 423 if sys.version_info < (3, 0): 424 425 MSGS.update({ 426 'W0331': ('Use of the <> operator', 427 + 'old-ne-operator', 428 'Used when the deprecated "<>" operator is used instead \ 429 of "!=".'), 430 'W0332': ('Use of "l" as long integer identifier', 431 + 'lowercase-l-suffix', 432 'Used when a lower case "l" is used to mark a long integer. You ' 433 'should use a upper case "L" since the letter "l" looks too much ' 434 'like the digit "1"'), 435 'W0333': ('Use of the `` operator', 436 + 'backtick', 437 'Used when the deprecated "``" (backtick) operator is used ' 438 'instead of the str() function.'), 439 }) 440 441 # simple quoted string rgx
@@ -363,14 +375,16 @@
442 """Check string literals""" 443 444 msgs = { 445 'W1401': ('Anomalous backslash in string: \'%s\'. ' 446 'String constant might be missing an r prefix.', 447 + 'anomalous-backslash-in-string', 448 'Used when a backslash is in a literal string but not as an ' 449 'escape.'), 450 'W1402': ('Anomalous Unicode escape in byte string: \'%s\'. ' 451 'String constant might be missing an r or u prefix.', 452 + 'anomalous-unicode-escape-in-string', 453 'Used when an escape like \\u is encountered in a byte ' 454 'string where it has no effect.'), 455 } 456 name = 'string_constant' 457 __implements__ = (IRawChecker, IASTNGChecker)
@@ -126,28 +126,36 @@
458 459 # the import checker itself ################################################### 460 461 MSGS = { 462 'F0401': ('Unable to import %s', 463 + 'import-error', 464 'Used when pylint has been unable to import a module.'), 465 'R0401': ('Cyclic import (%s)', 466 + 'cyclic-import', 467 'Used when a cyclic import between two or more modules is \ 468 detected.'), 469 470 'W0401': ('Wildcard import %s', 471 + 'wildcard-import', 472 'Used when `from module import *` is detected.'), 473 'W0402': ('Uses of a deprecated module %r', 474 + 'deprecated-module', 475 'Used a module marked as deprecated is imported.'), 476 'W0403': ('Relative import %r, should be %r', 477 + 'relative-import', 478 'Used when an import relative to the package directory is \ 479 detected.'), 480 'W0404': ('Reimport %r (imported line %s)', 481 + 'reimported', 482 'Used when a module is reimported multiple times.'), 483 'W0406': ('Module import itself', 484 + 'import-self', 485 'Used when a module is importing itself.'), 486 487 'W0410': ('__future__ import is not the first non docstring statement', 488 + 'misplaced-future', 489 'Python 2.5 and greater require __future__ import to be the \ 490 first non docstring statement in the module.'), 491 } 492 493 class ImportsChecker(BaseChecker):
@@ -20,28 +20,33 @@
494 from pylint.checkers import utils 495 496 497 MSGS = { 498 'W1201': ('Specify string format arguments as logging function parameters', 499 + 'logging-not-lazy', 500 'Used when a logging statement has a call form of ' 501 '"logging.<logging method>(format_string % (format_args...))". ' 502 'Such calls should leave string interpolation to the logging ' 503 'method itself and be written ' 504 '"logging.<logging method>(format_string, format_args...)" ' 505 'so that the program may avoid incurring the cost of the ' 506 'interpolation in those cases in which no message will be ' 507 'logged. For more, see ' 508 'http://www.python.org/dev/peps/pep-0282/.'), 509 'E1200': ('Unsupported logging format character %r (%#02x) at index %d', 510 + 'logging-unsupported-format', 511 'Used when an unsupported format character is used in a logging\ 512 statement format string.'), 513 'E1201': ('Logging format string ends in middle of conversion specifier', 514 + 'logging-format-truncated', 515 'Used when a logging statement format string terminates before\ 516 the end of a conversion specifier.'), 517 'E1205': ('Too many arguments for logging format string', 518 + 'logging-too-many-args', 519 'Used when a logging format string is given too few arguments.'), 520 'E1206': ('Not enough arguments for logging format string', 521 + 'logging-too-few-args', 522 'Used when a logging format string is given too many arguments'), 523 } 524 525 526 CHECKED_CONVENIENCE_FUNCTIONS = set([
@@ -23,10 +23,11 @@
527 from pylint.checkers import BaseChecker 528 529 530 MSGS = { 531 'W0511': ('%s', 532 + 'fixme', 533 'Used when a warning note as FIXME or XXX is detected.'), 534 } 535 536 class EncodingChecker(BaseChecker): 537 """checks for:
@@ -22,17 +22,21 @@
538 from pylint.checkers import BaseChecker 539 from pylint.checkers.utils import check_messages 540 541 MSGS = { 542 'E1001': ('Use of __slots__ on an old style class', 543 + 'slots-on-old-class', 544 'Used when an old style class uses the __slots__ attribute.'), 545 'E1002': ('Use of super on an old style class', 546 + 'super-on-old-class', 547 'Used when an old style class uses the super builtin.'), 548 'E1003': ('Bad first argument %r given to super class', 549 + 'bad-super-call', 550 'Used when another argument than the current class is given as \ 551 first argument of the super builtin.'), 552 'W1001': ('Use of "property" on an old style class', 553 + 'property-on-old-class', 554 'Used when PyLint detect the use of the builtin "property" \ 555 on an old style class while this is relying on new style \ 556 classes features'), 557 } 558
@@ -195,10 +195,11 @@
559 index.setdefault(line, []).append( line_no ) 560 return index 561 562 563 MSGS = {'R0801': ('Similar lines in %s files\n%s', 564 + 'duplicate-code', 565 'Indicates that a set of similar lines has been detected \ 566 among multiple file. This usually means that the code should \ 567 be refactored to avoid this duplication.')} 568 569 def report_similarities(sect, stats, old_stats):
@@ -22,38 +22,47 @@
570 from pylint.checkers import utils 571 572 573 MSGS = { 574 'E1300': ("Unsupported format character %r (%#02x) at index %d", 575 + "bad-format-character", 576 "Used when a unsupported format character is used in a format\ 577 string."), 578 'E1301': ("Format string ends in middle of conversion specifier", 579 + "truncated-format-string", 580 "Used when a format string terminates before the end of a \ 581 conversion specifier."), 582 'E1302': ("Mixing named and unnamed conversion specifiers in format string", 583 + "mixed-format-string", 584 "Used when a format string contains both named (e.g. '%(foo)d') \ 585 and unnamed (e.g. '%d') conversion specifiers. This is also \ 586 used when a named conversion specifier contains * for the \ 587 minimum field width and/or precision."), 588 'E1303': ("Expected mapping for format string, not %s", 589 + "format-needs-mapping", 590 "Used when a format string that uses named conversion specifiers \ 591 is used with an argument that is not a mapping."), 592 'W1300': ("Format string dictionary key should be a string, not %s", 593 + "bad-format-string-key", 594 "Used when a format string that uses named conversion specifiers \ 595 is used with a dictionary whose keys are not all strings."), 596 'W1301': ("Unused key %r in format string dictionary", 597 + "unused-format-string-key", 598 "Used when a format string that uses named conversion specifiers \ 599 is used with a dictionary that conWtains keys not required by the \ 600 format string."), 601 'E1304': ("Missing key %r in format string dictionary", 602 + "missing-format-string-key", 603 "Used when a format string that uses named conversion specifiers \ 604 is used with a dictionary that doesn't contain all the keys \ 605 required by the format string."), 606 'E1305': ("Too many arguments for format string", 607 + "too-many-format-args", 608 "Used when a format string that uses unnamed conversion \ 609 specifiers is given too few arguments."), 610 'E1306': ("Not enough arguments for format string", 611 + "too-few-format-args", 612 "Used when a format string that uses unnamed conversion \ 613 specifiers is given too many arguments"), 614 } 615 616 OTHER_NODES = (astng.Const, astng.List, astng.Backquote,
@@ -26,37 +26,47 @@
617 from pylint.checkers import BaseChecker 618 from pylint.checkers.utils import safe_infer, is_super, check_messages 619 620 MSGS = { 621 'E1101': ('%s %r has no %r member', 622 + 'no-member', 623 'Used when a variable is accessed for an unexistent member.'), 624 'E1102': ('%s is not callable', 625 + 'not-callable', 626 'Used when an object being called has been inferred to a non \ 627 callable object'), 628 'E1103': ('%s %r has no %r member (but some types could not be inferred)', 629 + 'maybe-no-member', 630 'Used when a variable is accessed for an unexistent member, but \ 631 astng was not able to interpret all possible types of this \ 632 variable.'), 633 'E1111': ('Assigning to function call which doesn\'t return', 634 + 'assignment-from-no-return', 635 'Used when an assignment is done on a function call but the \ 636 inferred function doesn\'t return anything.'), 637 'W1111': ('Assigning to function call which only returns None', 638 + 'assignment-from-none', 639 'Used when an assignment is done on a function call but the \ 640 inferred function returns nothing but None.'), 641 642 'E1120': ('No value passed for parameter %s in function call', 643 + 'no-value-for-parameter', 644 'Used when a function call passes too few arguments.'), 645 'E1121': ('Too many positional arguments for function call', 646 + 'too-many-function-args', 647 'Used when a function call passes too many positional \ 648 arguments.'), 649 'E1122': ('Duplicate keyword argument %r in function call', 650 + 'duplicate-keyword-arg', 651 'Used when a function call passes the same keyword argument \ 652 multiple times.'), 653 'E1123': ('Passing unexpected keyword argument %r in function call', 654 + 'unexpected-keyword-arg', 655 'Used when a function call passes a keyword argument that \ 656 doesn\'t correspond to one of the function\'s parameter names.'), 657 'E1124': ('Multiple values passed for parameter %r in function call', 658 + 'redundant-keyword-arg', 659 'Used when a function call would result in assigning multiple \ 660 values to a function parameter, one value from a positional \ 661 argument and one from a keyword argument.'), 662 } 663
@@ -52,52 +52,68 @@
664 return None 665 666 667 MSGS = { 668 'E0601': ('Using variable %r before assignment', 669 + 'used-before-assignment', 670 'Used when a local variable is accessed before it\'s \ 671 assignment.'), 672 'E0602': ('Undefined variable %r', 673 + 'undefined-variable', 674 'Used when an undefined variable is accessed.'), 675 'E0603': ('Undefined variable name %r in __all__', 676 + 'undefined-all-variable', 677 'Used when an undefined variable name is referenced in __all__.'), 678 'E0611': ('No name %r in module %r', 679 + 'no-name-in-module', 680 'Used when a name cannot be found in a module.'), 681 682 'W0601': ('Global variable %r undefined at the module level', 683 + 'global-variable-undefined', 684 'Used when a variable is defined through the "global" statement \ 685 but the variable is not defined in the module scope.'), 686 'W0602': ('Using global for %r but no assignment is done', 687 + 'global-variable-not-assigned', 688 'Used when a variable is defined through the "global" statement \ 689 but no assignment to this variable is done.'), 690 'W0603': ('Using the global statement', # W0121 691 + 'global-statement', 692 'Used when you use the "global" statement to update a global \ 693 variable. PyLint just try to discourage this \ 694 usage. That doesn\'t mean you can not use it !'), 695 'W0604': ('Using the global statement at the module level', # W0103 696 + 'global-at-module-level', 697 'Used when you use the "global" statement at the module level \ 698 since it has no effect'), 699 'W0611': ('Unused import %s', 700 + 'unused-import', 701 'Used when an imported module or variable is not used.'), 702 'W0612': ('Unused variable %r', 703 + 'unused-variable', 704 'Used when a variable is defined but not used.'), 705 'W0613': ('Unused argument %r', 706 + 'unused-argument', 707 'Used when a function or method argument is not used.'), 708 'W0614': ('Unused import %s from wildcard import', 709 + 'unused-wildcard-import', 710 'Used when an imported module or variable is not used from a \ 711 \'from X import *\' style import.'), 712 713 'W0621': ('Redefining name %r from outer scope (line %s)', 714 + 'redefined-outer-name', 715 'Used when a variable\'s name hide a name defined in the outer \ 716 scope.'), 717 'W0622': ('Redefining built-in %r', 718 + 'redefined-builtin', 719 'Used when a variable or function override a built-in.'), 720 'W0623': ('Redefining name %r from %s in exception handler', 721 + 'redefine-in-handler', 722 'Used when an exception handler assigns the exception \ 723 to an existing name'), 724 725 'W0631': ('Using possibly undefined loop variable %r', 726 + 'undefined-loop-variable', 727 'Used when an loop variable (i.e. defined by a for loop or \ 728 a list comprehension or a generator expression) is used outside \ 729 the loop.'), 730 } 731
@@ -241,10 +241,19 @@
732 733 disable= W0401, # because I do not want it 734 E0202, # I have a good reason, trust me 735 C0302 # that's it 736 737 +4.6 Do I have to remember all these numbers? 738 +-------------------------------------------- 739 + 740 +No, starting from 0.25.3, you can use symbolic names for messages:: 741 + 742 + # pylint: disable=fixme, line-too-long 743 + 744 +You can show these symbols in the output with the `-sy` option. 745 + 746 5. Classes and Inheritance 747 ========================== 748 749 5.1 When is pylint considering a class as an interface? 750 -------------------------------------------------------
@@ -311,10 +311,12 @@
751 --comment=y_or_n Add a comment according to your evaluation note. 752 --parseable=y_or_n Use a parseable output format. 753 --html=y_or_n Use HTML as output format instead of text. 754 --list-msgs Generate pylint's messages. 755 --full-documentation Generate pylint's full documentation, in reST format. 756 +--include_ids=y_or_n Show numeric ids of messages (like 'C0301') 757 +--symbols=y_or_n Show symbolic ids of messsages (like 'line-too-long') 758 759 .. _features: features.html 760 761 Daily pylint usage 762 ------------------
@@ -82,51 +82,63 @@
763 764 # Python Linter class ######################################################### 765 766 MSGS = { 767 'F0001': ('%s', 768 + 'fatal', 769 'Used when an error occurred preventing the analysis of a \ 770 module (unable to find it for instance).'), 771 'F0002': ('%s: %s', 772 + 'astng-error', 773 'Used when an unexpected error occurred while building the ASTNG \ 774 representation. This is usually accompanied by a traceback. \ 775 Please report such errors !'), 776 'F0003': ('ignored builtin module %s', 777 + 'ignored-builtin-module', 778 'Used to indicate that the user asked to analyze a builtin module\ 779 which has been skipped.'), 780 'F0004': ('unexpected inferred value %s', 781 + 'unexpected-inferred-value', 782 'Used to indicate that some value of an unexpected type has been \ 783 inferred.'), 784 'F0010': ('error while code parsing: %s', 785 + 'parse-error', 786 'Used when an exception occured while building the ASTNG \ 787 representation which could be handled by astng.'), 788 789 - 790 'I0001': ('Unable to run raw checkers on built-in module %s', 791 + 'raw-checker-failed', 792 'Used to inform that a built-in module has not been checked \ 793 using the raw checkers.'), 794 795 'I0010': ('Unable to consider inline option %r', 796 + 'bad-inline-option', 797 'Used when an inline option is either badly formatted or can\'t \ 798 be used inside modules.'), 799 800 'I0011': ('Locally disabling %s', 801 + 'locally-disabled', 802 'Used when an inline option disables a message or a messages \ 803 category.'), 804 'I0012': ('Locally enabling %s', 805 + 'locally-enabled', 806 'Used when an inline option enables a message or a messages \ 807 category.'), 808 'I0013': ('Ignoring entire file', 809 + 'file-ignored', 810 'Used to inform that the file will not be checked'), 811 812 813 'E0001': ('%s', 814 + 'syntax-error', 815 'Used when a syntax error is raised for a module.'), 816 817 'E0011': ('Unrecognized file option %r', 818 + 'unrecognized-inline-option', 819 'Used when an unknown inline option is encountered.'), 820 'E0012': ('Bad option value %r', 821 + 'bad-option-value', 822 'Used when a bad value for an inline option is encountered.'), 823 } 824 825 826 class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
@@ -182,10 +194,16 @@
827 {'type' : 'yn', 'metavar' : '<y_or_n>', 'default' : 0, 828 'short': 'i', 829 'group': 'Reports', 830 'help' : 'Include message\'s id in output'}), 831 832 + ('symbols', 833 + {'type' : 'yn', 'metavar' : '<y_or_n>', 'default' : 0, 834 + 'short': 's', 835 + 'group': 'Reports', 836 + 'help' : 'Include symbolic ids of messages in output'}), 837 + 838 ('files-output', 839 {'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>', 840 'group': 'Reports', 'level': 1, 841 'help' : 'Put messages in a separate file for each module / \ 842 package specified on the command line instead of printing them on stdout. \
@@ -481,10 +499,11 @@
843 def check(self, files_or_modules): 844 """main checking entry: check a list of files or modules from their 845 name. 846 """ 847 self.reporter.include_ids = self.config.include_ids 848 + self.reporter.symbols = self.config.symbols 849 if not isinstance(files_or_modules, (list, tuple)): 850 files_or_modules = (files_or_modules,) 851 walker = PyLintASTWalker(self) 852 checkers = self.prepare_checkers() 853 rawcheckers = [c for c in checkers if implements(c, IRawChecker)
@@ -29,22 +29,42 @@
854 855 class EmptyReport(Exception): 856 """raised when a report is empty and so should not be displayed""" 857 858 class BaseReporter: 859 - """base class for reporters""" 860 + """base class for reporters 861 + 862 + symbols: show short symbolic names for messages. 863 + """ 864 865 extension = '' 866 867 def __init__(self, output=None): 868 self.linter = None 869 self.include_ids = None 870 + self.symbols = None 871 self.section = 0 872 self.out = None 873 self.out_encoding = None 874 self.set_output(output) 875 876 + def make_sigle(self, msg_id): 877 + """generate a short prefix for a message. 878 + 879 + The sigle can include the id, the symbol, or both, or it can just be 880 + the message class. 881 + """ 882 + if self.include_ids: 883 + sigle = msg_id 884 + else: 885 + sigle = msg_id[0] 886 + if self.symbols: 887 + symbol = self.linter.check_message_id(msg_id).symbol 888 + if symbol: 889 + sigle += '(%s)' % symbol 890 + return sigle 891 + 892 def set_output(self, output=None): 893 """set output stream""" 894 self.out = output or sys.stdout 895 # py3k streams handle their encoding : 896 if sys.version_info >= (3, 0):
@@ -20,15 +20,11 @@
897 self.gui = gui 898 899 def add_message(self, msg_id, location, msg): 900 """manage message of different type and in the context of path""" 901 module, obj, line, col_offset = location[1:] 902 - if self.include_ids: 903 - sigle = msg_id 904 - else: 905 - sigle = msg_id[0] 906 - 907 + sigle = self.make_sigle(msg_id) 908 full_msg = [sigle, module, obj, str(line), msg] 909 self.msgs += [[sigle, module, obj, str(line)]] 910 self.gui.msg_queue.put(full_msg) 911 912 def _display(self, layout):
@@ -34,14 +34,11 @@
913 self.msgs = [] 914 915 def add_message(self, msg_id, location, msg): 916 """manage message of different type and in the context of path""" 917 module, obj, line, col_offset = location[1:] 918 - if self.include_ids: 919 - sigle = msg_id 920 - else: 921 - sigle = msg_id[0] 922 + sigle = self.make_sigle(msg_id) 923 self.msgs += [sigle, module, obj, str(line), str(col_offset), escape(msg)] 924 925 def set_output(self, output=None): 926 """set output stream 927
@@ -54,14 +54,11 @@
928 self._modules[module] = 1 929 else: 930 self.writeln('************* %s' % module) 931 if obj: 932 obj = ':%s' % obj 933 - if self.include_ids: 934 - sigle = msg_id 935 - else: 936 - sigle = msg_id[0] 937 + sigle = self.make_sigle(msg_id) 938 self.writeln('%s:%3s,%s%s: %s' % (sigle, line, col_offset, obj, msg)) 939 940 def _display(self, layout): 941 """launch layouts display""" 942 print >> self.out
@@ -86,14 +83,11 @@
943 def add_message(self, msg_id, location, msg): 944 """manage message of different type and in the context of path""" 945 path, _, obj, line, _ = location 946 if obj: 947 obj = ', %s' % obj 948 - if self.include_ids: 949 - sigle = msg_id 950 - else: 951 - sigle = msg_id[0] 952 + sigle = self.make_sigle(msg_id) 953 if self._prefix: 954 path = path.replace(self._prefix, '') 955 self.writeln(self.line_format % locals()) 956 957 class VSTextReporter(ParseableTextReporter):
@@ -143,13 +137,10 @@
958 color, style) 959 self.writeln(modsep) 960 self._modules[module] = 1 961 if obj: 962 obj = ':%s' % obj 963 - if self.include_ids: 964 - sigle = msg_id 965 - else: 966 - sigle = msg_id[0] 967 + sigle = self.make_sigle(msg_id) 968 color, style = self._get_decoration(sigle) 969 msg = colorize_ansi(msg, color, style) 970 sigle = colorize_ansi(sigle, color, style) 971 self.writeln('%s:%3s%s: %s' % (sigle, line, obj, msg))
@@ -18,31 +18,34 @@
972 # missing docstring 973 974 ## class BBBB: 975 ## # missing docstring 976 ## pass 977 - 978 + 979 ## class CCCC: 980 ## """yeah !""" 981 ## def method1(self): 982 ## pass 983 984 ## def method2(self): 985 ## """ yeah !""" 986 ## pass 987 - 988 + 989 def method1(self): 990 pass 991 - 992 + 993 def method2(self): 994 """ yeah !""" 995 pass 996 997 def __init__(self): 998 pass 999 - 1000 + 1001 class DDDD(AAAA): 1002 """yeah !""" 1003 1004 def __init__(self): 1005 AAAA.__init__(self) 1006 - 1007 + 1008 +# pylint: disable=missing-docstring 1009 +def function4(): 1010 + pass
@@ -175,10 +175,40 @@
1011 self.assert_(not linter.is_message_enabled('E1101', 70)) 1012 self.assert_(linter.is_message_enabled('E1101', 72)) 1013 self.assert_(linter.is_message_enabled('E1101', 75)) 1014 self.assert_(linter.is_message_enabled('E1101', 77)) 1015 1016 + def test_enable_by_symbol(self): 1017 + """messages can be controlled by symbolic names. 1018 + 1019 + The state is consistent across symbols and numbers. 1020 + """ 1021 + linter = self.linter 1022 + linter.open() 1023 + linter.set_current_module('toto') 1024 + self.assertTrue(linter.is_message_enabled('W0101')) 1025 + self.assertTrue(linter.is_message_enabled('unreachable')) 1026 + self.assertTrue(linter.is_message_enabled('W0102')) 1027 + self.assertTrue(linter.is_message_enabled('dangerous-default-value')) 1028 + linter.disable('unreachable', scope='package') 1029 + linter.disable('dangerous-default-value', scope='module', line=1) 1030 + self.assertFalse(linter.is_message_enabled('W0101')) 1031 + self.assertFalse(linter.is_message_enabled('unreachable')) 1032 + self.assertFalse(linter.is_message_enabled('W0102', 1)) 1033 + self.assertFalse(linter.is_message_enabled('dangerous-default-value', 1)) 1034 + linter.set_current_module('tutu') 1035 + self.assertFalse(linter.is_message_enabled('W0101')) 1036 + self.assertFalse(linter.is_message_enabled('unreachable')) 1037 + self.assertTrue(linter.is_message_enabled('W0102')) 1038 + self.assertTrue(linter.is_message_enabled('dangerous-default-value')) 1039 + linter.enable('unreachable', scope='package') 1040 + linter.enable('dangerous-default-value', scope='module', line=1) 1041 + self.assertTrue(linter.is_message_enabled('W0101')) 1042 + self.assertTrue(linter.is_message_enabled('unreachable')) 1043 + self.assertTrue(linter.is_message_enabled('W0102', 1)) 1044 + self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) 1045 + 1046 def test_list_messages(self): 1047 sys.stdout = StringIO() 1048 try: 1049 # just invoke it, don't check the output 1050 self.linter.list_messages()
@@ -17,10 +17,11 @@
1051 """some various utilities and helper classes, most of them used in the 1052 main pylint class 1053 """ 1054 1055 import sys 1056 +from warnings import warn 1057 from os import linesep 1058 from os.path import dirname, basename, splitext, exists, isdir, join, normpath 1059 1060 from logilab.common.modutils import modpath_from_file, get_module_files, \ 1061 file_from_modpath
@@ -91,27 +92,30 @@
1062 return id 1063 return MSG_TYPES_LONG.get(id) 1064 1065 1066 class Message: 1067 - def __init__(self, checker, msgid, msg, descr): 1068 + def __init__(self, checker, msgid, msg, descr, symbol): 1069 assert len(msgid) == 5, 'Invalid message id %s' % msgid 1070 assert msgid[0] in MSG_TYPES, \ 1071 'Bad message type %s in %r' % (msgid[0], msgid) 1072 self.msgid = msgid 1073 self.msg = msg 1074 self.descr = descr 1075 self.checker = checker 1076 + self.symbol = symbol 1077 1078 class MessagesHandlerMixIn: 1079 """a mix-in class containing all the messages related methods for the main 1080 lint class 1081 """ 1082 1083 def __init__(self): 1084 # dictionary of registered messages 1085 self._messages = {} 1086 + # dictionary from string symbolic id to Message object. 1087 + self._messages_by_symbol = {} 1088 self._msgs_state = {} 1089 self._module_msgs_state = {} # None 1090 self._msgs_by_category = {} 1091 self.msg_status = 0 1092
@@ -124,32 +128,49 @@
1093 message ids should be a string of len 4, where the two first characters 1094 are the checker id and the two last the message id in this checker 1095 """ 1096 msgs_dict = checker.msgs 1097 chkid = None 1098 - for msgid, (msg, msgdescr) in msgs_dict.iteritems(): 1099 + for msgid, msg_tuple in msgs_dict.iteritems(): 1100 + if len(msg_tuple) == 3: 1101 + (msg, msgsymbol, msgdescr) = msg_tuple 1102 + assert msgsymbol not in self._messages_by_symbol, \ 1103 + 'Message symbol %r is already defined' % msgsymbol 1104 + else: 1105 + # messages should have a symbol, but for backward compatibility 1106 + # they may not. 1107 + (msg, msgdescr) = msg_tuple 1108 + warn("[pylint 0.26] description of message %s doesn't include " 1109 + "a symbolic name" % msgid, DeprecationWarning) 1110 + msgsymbol = None 1111 # avoid duplicate / malformed ids 1112 assert msgid not in self._messages, \ 1113 'Message id %r is already defined' % msgid 1114 assert chkid is None or chkid == msgid[1:3], \ 1115 'Inconsistent checker part in message id %r' % msgid 1116 chkid = msgid[1:3] 1117 - self._messages[msgid] = Message(checker, msgid, msg, msgdescr) 1118 + msg = Message(checker, msgid, msg, msgdescr, msgsymbol) 1119 + self._messages[msgid] = msg 1120 + self._messages_by_symbol[msgsymbol] = msg 1121 self._msgs_by_category.setdefault(msgid[0], []).append(msgid) 1122 1123 def get_message_help(self, msgid, checkerref=False): 1124 """return the help string for the given message id""" 1125 msg = self.check_message_id(msgid) 1126 desc = normalize_text(' '.join(msg.descr.split()), indent=' ') 1127 if checkerref: 1128 desc += ' This message belongs to the %s checker.' % \ 1129 msg.checker.name 1130 title = msg.msg 1131 + if msg.symbol: 1132 + symbol_part = ' (%s)' % msg.symbol 1133 + else: 1134 + symbol_part = '' 1135 if title != '%s': 1136 title = title.splitlines()[0] 1137 - return ':%s: *%s*\n%s' % (msg.msgid, title, desc) 1138 - return ':%s:\n%s' % (msg.msgid, desc) 1139 + return ':%s%s: *%s*\n%s' % (msg.msgid, symbol_part, title, desc) 1140 + return ':%s%s:\n%s' % (msg.msgid, symbol_part, desc) 1141 1142 def disable(self, msgid, scope='package', line=None): 1143 """don't output message of the given id""" 1144 assert scope in ('package', 'module') 1145 # msgid is a category?
@@ -166,11 +187,11 @@
1146 return 1147 # msgid is report id? 1148 if msgid.lower().startswith('rp'): 1149 self.disable_report(msgid) 1150 return 1151 - # msgid is a msgid. 1152 + # msgid is a symbolic or numeric msgid. 1153 msg = self.check_message_id(msgid) 1154 if scope == 'module': 1155 assert line > 0 1156 try: 1157 self._module_msgs_state[msg.msgid][line] = False
@@ -203,11 +224,11 @@
1158 return 1159 # msgid is report id? 1160 if msgid.lower().startswith('rp'): 1161 self.enable_report(msgid) 1162 return 1163 - # msgid is a msgid. 1164 + # msgid is a symbolic or numeric msgid. 1165 msg = self.check_message_id(msgid) 1166 if scope == 'module': 1167 assert line > 0 1168 try: 1169 self._module_msgs_state[msg.msgid][line] = True
@@ -219,21 +240,32 @@
1170 msgs[msg.msgid] = True 1171 # sync configuration object 1172 self.config.enable = [mid for mid, val in msgs.iteritems() if val] 1173 1174 def check_message_id(self, msgid): 1175 - """raise UnknownMessage if the message id is not defined""" 1176 + """returns the Message object for this message. 1177 + 1178 + msgid may be either a numeric or symbolic id. 1179 + 1180 + Raises UnknownMessage if the message id is not defined. 1181 + """ 1182 + if msgid in self._messages_by_symbol: 1183 + return self._messages_by_symbol[msgid] 1184 msgid = msgid.upper() 1185 try: 1186 return self._messages[msgid] 1187 except KeyError: 1188 raise UnknownMessage('No such message id %s' % msgid) 1189 1190 def is_message_enabled(self, msgid, line=None): 1191 """return true if the message associated to the given message id is 1192 enabled 1193 + 1194 + msgid may be either a numeric or symbolic message id. 1195 """ 1196 + if msgid in self._messages_by_symbol: 1197 + msgid = self._messages_by_symbol[msgid].msgid 1198 if line is None: 1199 return self._msgs_state.get(msgid, True) 1200 try: 1201 return self._module_msgs_state[msgid][line] 1202 except (KeyError, TypeError):
@@ -523,6 +555,5 @@
1203 # recurse on children 1204 for child in astng.get_children(): 1205 self.walk(child) 1206 for cb in self.leave_events.get(cid, ()): 1207 cb(astng) 1208 -