Commits

Anonymous committed b9dab50

Closes #104572: symbolic warning names in output (by Martin Pool)

triggered whatever the format using a command line option

Comments (0)

Files changed (24)

 * Wolfgang Grafen, Axel Muller, Fabio Zadrozny, Pierre Rouleau,
   Maarten ter Huurne, Mirko Friedenhagen (among others):
   bug reports, feedback, feature requests...
-* Martin Pool (Google): warnings for anomalous backslashes
+* Martin Pool (Google): warnings for anomalous backslashes, symbolic names
+  for messages (like 'unused')
 * All the Logilab's team: daily use, bug reports, feature requests
 * Other people have contributed by their feedback, if I've forgotten
   you, send me a note !
 class BasicErrorChecker(_BasicChecker):
     msgs = {
     'E0100': ('__init__ method is a generator',
+              'init-is-generator',
               'Used when the special class method __init__ is turned into a '
               'generator by a yield in its body.'),
     'E0101': ('Explicit return in __init__',
+              'return-in-init',
               'Used when the special class method __init__ has an explicit \
               return value.'),
     'E0102': ('%s already defined line %s',
+              'function-redefined',
               'Used when a function / class / method is redefined.'),
     'E0103': ('%r not properly in loop',
+              'not-in-loop',
               'Used when break or continue keywords are used outside a loop.'),
 
     'E0104': ('Return outside function',
+              'return-outside-function',
               'Used when a "return" statement is found outside a function or '
               'method.'),
     'E0105': ('Yield outside function',
+              'yield-outside-function',
               'Used when a "yield" statement is found outside a function or '
               'method.'),
     'E0106': ('Return with argument inside generator',
+              'return-arg-in-generator',
               'Used when a "return" statement with an argument is found '
               'outside in a generator function or method (e.g. with some '
               '"yield" statements).'),
     'E0107': ("Use of the non-existent %s operator",
+              'nonexistent-operator',
               "Used when you attempt to use the C-style pre-increment or"
               "pre-decrement operator -- and ++, which doesn't exist in Python."),
     }
     name = 'basic'
     msgs = {
     'W0101': ('Unreachable code',
+              'unreachable',
               'Used when there is some code behind a "return" or "raise" \
               statement, which will never be accessed.'),
     'W0102': ('Dangerous default value %s as argument',
+              'dangerous-default-value',
               'Used when a mutable value as list or dictionary is detected in \
               a default value for an argument.'),
     'W0104': ('Statement seems to have no effect',
+              'pointless-statement',
               'Used when a statement doesn\'t have (or at least seems to) \
               any effect.'),
     'W0105': ('String statement has no effect',
+              'pointless-string-statement',
               'Used when a string is used as a statement (which of course \
               has no effect). This is a particular case of W0104 with its \
               own message so you can easily disable it if you\'re using \
               those strings as documentation, instead of comments.'),
     'W0106': ('Expression "%s" is assigned to nothing',
+              'expression-not-assigned',
               'Used when an expression that is not a function call is assigned\
               to nothing. Probably something else was intended.'),
     'W0108': ('Lambda may not be necessary',
+              'unnecessary-lambda',
               'Used when the body of a lambda expression is a function call \
               on the same argument list as the lambda itself; such lambda \
               expressions are in all but a few cases replaceable with the \
               function being called in the body of the lambda.'),
     'W0109': ("Duplicate key %r in dictionary",
+              'duplicate-key',
               "Used when a dictionary expression binds the same key multiple \
               times."),
     'W0122': ('Use of the exec statement',
+              'exec-statement',
               'Used when you use the "exec" statement, to discourage its \
               usage. That doesn\'t mean you can not use it !'),
 
     'W0141': ('Used builtin function %r',
+              'bad-builtin',
               'Used when a black listed builtin function is used (see the '
               'bad-function option). Usual black listed functions are the ones '
               'like map, or filter , where Python offers now some cleaner '
               'alternative like list comprehension.'),
     'W0142': ('Used * or ** magic',
+              'star-args',
               'Used when a function or method is called using `*args` or '
               '`**kwargs` to dispatch arguments. This doesn\'t improve '
               'readability and should be used with care.'),
     'W0150': ("%s statement in finally block may swallow exception",
+              'lost-exception',
               "Used when a break or a return statement is found inside the \
               finally clause of a try...finally block: the exceptions raised \
               in the try clause will be silently swallowed instead of being \
               re-raised."),
     'W0199': ('Assert called on a 2-uple. Did you mean \'assert x,y\'?',
+              'assert-on-tuple',
               'A call of assert on a tuple will always evaluate to true if '
               'the tuple is not empty, and will always evaluate to false if '
               'it is.'),
 
     'C0121': ('Missing required attribute "%s"', # W0103
+              'missing-module-attribute',
               'Used when an attribute required for modules is missing.'),
 
     }
 class NameChecker(_BasicChecker):
     msgs = {
     'C0102': ('Black listed name "%s"',
+              'blacklisted-name',
               'Used when the name is listed in the black list (unauthorized \
               names).'),
     'C0103': ('Invalid name "%s" (should match %s)',
+              'invalid-name',
               'Used when the name doesn\'t match the regular expression \
               associated to its type (constant, variable, class...).'),
 
 class DocStringChecker(_BasicChecker):
     msgs = {
     'C0111': ('Missing docstring', # W0131
+              'missing-docstring',
               'Used when a module, function, class or method has no docstring.\
               Some special methods like __init__ doesn\'t necessary require a \
               docstring.'),
     'C0112': ('Empty docstring', # W0132
+              'empty-docstring',
               'Used when a module, function, class or method has an empty \
               docstring (it would be too easy ;).'),
     }
 class PassChecker(_BasicChecker):
     """check is the pass statement is really necessary"""
     msgs = {'W0107': ('Unnecessary pass statement',
+                      'unnecessary-pass',
                       'Used when a "pass" statement that can be avoided is '
                       'encountered.)'),
             }

checkers/classes.py

 
 MSGS = {
     'F0202': ('Unable to check methods signature (%s / %s)',
+              'method-check-failed',
               'Used when PyLint has been unable to check methods signature \
               compatibility for an unexpected reason. Please report this kind \
               if you don\'t make sense of it.'),
 
     'E0202': ('An attribute affected in %s line %s hide this method',
+              'method-hidden',
               'Used when a class defines a method which is hidden by an '
               'instance attribute from an ancestor class or set by some '
               'client code.'),
     'E0203': ('Access to member %r before its definition line %s',
+              'access-member-before-definition',
               'Used when an instance member is accessed before it\'s actually\
               assigned.'),
     'W0201': ('Attribute %r defined outside __init__',
+              'attribute-defined-outside-init',
               'Used when an instance attribute is defined outside the __init__\
               method.'),
 
     'W0212': ('Access to a protected member %s of a client class', # E0214
+              'protected-access',
               'Used when a protected member (i.e. class member with a name \
               beginning with an underscore) is access outside the class or a \
               descendant of the class where it\'s defined.'),
 
     'E0211': ('Method has no argument',
+              'no-method-argument',
               'Used when a method which should have the bound instance as \
               first argument has no argument defined.'),
     'E0213': ('Method should have "self" as first argument',
+              'no-self-argument',
               'Used when a method has an attribute different the "self" as\
               first argument. This is considered as an error since this is\
               a so common convention that you shouldn\'t break it!'),
     'C0202': ('Class method %s should have %s as first argument', # E0212
+              'bad-classmethod-argument',
               'Used when a class method has a first argument named differently '
               'than the value specified in valid-classmethod-first-arg option '
               '(default to "cls"), recommended to easily differentiate them '
               'from regular instance methods.'),
     'C0203': ('Metaclass method %s should have %s as first argument', # E0214
+              'bad-mcs-method-argument',
               'Used when a metaclass method has a first agument named '
               'differently than the value specified in valid-classmethod-first'
               '-arg option (default to "cls"), recommended to easily '
               'differentiate them from regular instance methods.'),
     'C0204': ('Metaclass class method %s should have %s as first argument',
+              'bad-mcs-classmethod-argument',
               'Used when a metaclass class method has a first argument named '
               'differently than the value specified in valid-metaclass-'
               'classmethod-first-arg option (default to "mcs"), recommended to '
               'easily differentiate them from regular instance methods.'),
 
     'W0211': ('Static method with %r as first argument',
+              'bad-staticmethod-argument',
               'Used when a static method has "self" or a value specified in '
               'valid-classmethod-first-arg option or '
               'valid-metaclass-classmethod-first-arg option as first argument.'
               ),
     'R0201': ('Method could be a function',
+              'no-self-use',
               'Used when a method doesn\'t use its bound instance, and so could\
               be written as a function.'
               ),
 
     'E0221': ('Interface resolved to %s is not a class',
+              'interface-is-not-class',
               'Used when a class claims to implement an interface which is not \
               a class.'),
     'E0222': ('Missing method %r from %s interface',
+              'missing-interface-method',
               'Used when a method declared in an interface is missing from a \
               class implementing this interface'),
     'W0221': ('Arguments number differs from %s method',
+              'arguments-differ',
               'Used when a method has a different number of arguments than in \
               the implemented interface or in an overridden method.'),
     'W0222': ('Signature differs from %s method',
+              'signature-differs',
               'Used when a method signature is different than in the \
               implemented interface or in an overridden method.'),
     'W0223': ('Method %r is abstract in class %r but is not overridden',
+              'abstract-method',
               'Used when an abstract method (i.e. raise NotImplementedError) is \
               not overridden in concrete class.'
               ),
     'F0220': ('failed to resolve interfaces implemented by %s (%s)', # W0224
+              'unresolved-interface',
               'Used when a PyLint as failed to find interfaces implemented by \
                a class'),
 
 
     'W0231': ('__init__ method from base class %r is not called',
+              'super-init-not-called',
               'Used when an ancestor class method has an __init__ method \
               which is not called by a derived class.'),
     'W0232': ('Class has no __init__ method',
+              'no-init',
               'Used when a class has no __init__ method, neither its parent \
               classes.'),
     'W0233': ('__init__ method from a non direct base class %r is called',
+              'non-parent-init-called',
               'Used when an __init__ method is called on a class which is not \
               in the direct ancestors for the analysed class.'),
 

checkers/design_analysis.py

 
 MSGS = {
     'R0901': ('Too many ancestors (%s/%s)',
+              'too-many-ancestors',
               'Used when class has too many parent classes, try to reduce \
               this to get a more simple (and so easier to use) class.'),
     'R0902': ('Too many instance attributes (%s/%s)',
+              'too-many-instance-attributes',
               'Used when class has too many instance attributes, try to reduce \
               this to get a more simple (and so easier to use) class.'),
     'R0903': ('Too few public methods (%s/%s)',
+              'too-few-public-methods',
               'Used when class has too few public methods, so be sure it\'s \
               really worth it.'),
     'R0904': ('Too many public methods (%s/%s)',
+              'too-many-public-methods',
               'Used when class has too many public methods, try to reduce \
               this to get a more simple (and so easier to use) class.'),
 
     'R0911': ('Too many return statements (%s/%s)',
+              'too-many-return-statements',
               'Used when a function or method has too many return statement, \
               making it hard to follow.'),
     'R0912': ('Too many branches (%s/%s)',
+              'too-many-branches',
               'Used when a function or method has too many branches, \
               making it hard to follow.'),
     'R0913': ('Too many arguments (%s/%s)',
+              'too-many-arguments',
               'Used when a function or method takes too many arguments.'),
     'R0914': ('Too many local variables (%s/%s)',
+              'too-many-locals',
               'Used when a function or method has too many local variables.'),
     'R0915': ('Too many statements (%s/%s)',
+              'too-many-statements',
               'Used when a function or method has too many statements. You \
               should then split it in smaller functions / methods.'),
 
     'R0921': ('Abstract class not referenced',
+              'abstract-class-not-used',
               'Used when an abstract class is not used as ancestor anywhere.'),
     'R0922': ('Abstract class is only referenced %s times',
+              'abstract-class-little-used',
               'Used when an abstract class is used less than X times as \
               ancestor.'),
     'R0923': ('Interface not implemented',
+              'interface-not-implemented',
               'Used when an interface class is not implemented anywhere.'),
     }
 

checkers/exceptions.py

 OVERGENERAL_EXCEPTIONS = ('Exception',)
 
 MSGS = {
-    'E0701': (
-    'Bad except clauses order (%s)',
-    'Used when except clauses are not in the correct order (from the \
-    more specific to the more generic). If you don\'t fix the order, \
-    some exceptions may not be catched by the most specific handler.'),
+    'E0701': ('Bad except clauses order (%s)',
+              'bad-except-order',
+              'Used when except clauses are not in the correct order (from the '
+              'more specific to the more generic). If you don\'t fix the order, '
+              'some exceptions may not be catched by the most specific handler.'),
     'E0702': ('Raising %s while only classes, instances or string are allowed',
+              'raising-bad-type',
               'Used when something which is neither a class, an instance or a \
               string is raised (i.e. a `TypeError` will be raised).'),
     'E0710': ('Raising a new style class which doesn\'t inherit from BaseException',
+              'raising-non-exception',
               'Used when a new style class which doesn\'t inherit from \
                BaseException is raised.'),
     'E0711': ('NotImplemented raised - should raise NotImplementedError',
+              'notimplemented-raised',
               'Used when NotImplemented is raised instead of \
               NotImplementedError'),
     
     'W0701': ('Raising a string exception',
+              'raising-string',
               'Used when a string exception is raised.'),
     'W0702': ('No exception type(s) specified',
+              'bare-except',
               'Used when an except clause doesn\'t specify exceptions type to \
               catch.'),
     'W0703': ('Catching too general exception %s',
+              'broad-except',
               'Used when an except catches a too general exception, \
               possibly burying unrelated errors.'),
     'W0704': ('Except doesn\'t do anything',
+              'pointless-except',
               'Used when an except clause does nothing but "pass" and there is\
               no "else" clause.'),
     'W0710': ('Exception doesn\'t inherit from standard "Exception" class',
+              'nonstandard-exception',
               'Used when a custom exception class is raised but doesn\'t \
               inherit from the builtin "Exception" class.'),
     'W0711': ('Exception to catch is the result of a binary "%s" operation',
+              'binary-op-exception',
               'Used when the exception to catch is of the form \
               "except A or B:".  If intending to catch multiple, \
               rewrite as "except (A, B):"'),

checkers/format.py

 
 MSGS = {
     'C0301': ('Line too long (%s/%s)',
+              'line-too-long',
               'Used when a line is longer than a given number of characters.'),
     'C0302': ('Too many lines in module (%s)', # was W0302
+              'too-many-lines',
               'Used when a module has too much lines, reducing its readability.'
               ),
 
     'W0311': ('Bad indentation. Found %s %s, expected %s',
+              'bad-indentation',
               'Used when an unexpected number of indentation\'s tabulations or '
               'spaces has been found.'),
     'W0312': ('Found indentation with %ss instead of %ss',
+              'mixed-indentation',
               'Used when there are some mixed tabs and spaces in a module.'),
     'W0301': ('Unnecessary semicolon', # was W0106
+              'unnecessary-semicolon',
               'Used when a statement is ended by a semi-colon (";"), which \
               isn\'t necessary (that\'s python, not C ;).'),
     'C0321': ('More than one statement on a single line',
+              'multiple-statements',
               'Used when more than on statement are found on the same line.'),
     'C0322': ('Operator not preceded by a space\n%s',
+              'no-space-before-operator',
               'Used when one of the following operator (!= | <= | == | >= | < '
               '| > | = | \\+= | -= | \\*= | /= | %) is not preceded by a space.'),
     'C0323': ('Operator not followed by a space\n%s',
+              'no-space-after-operator',
               'Used when one of the following operator (!= | <= | == | >= | < '
               '| > | = | \\+= | -= | \\*= | /= | %) is not followed by a space.'),
     'C0324': ('Comma not followed by a space\n%s',
+              'no-space-after-comma',
               'Used when a comma (",") is not followed by a space.'),
     }
 
 
     MSGS.update({
     'W0331': ('Use of the <> operator',
+              'old-ne-operator',
               'Used when the deprecated "<>" operator is used instead \
               of "!=".'),
     'W0332': ('Use of "l" as long integer identifier',
+              'lowercase-l-suffix',
               'Used when a lower case "l" is used to mark a long integer. You '
               'should use a upper case "L" since the letter "l" looks too much '
               'like the digit "1"'),
     'W0333': ('Use of the `` operator',
+              'backtick',
               'Used when the deprecated "``" (backtick) operator is used '
               'instead  of the str() function.'),
     })
     msgs = {
         'W1401': ('Anomalous backslash in string: \'%s\'. '
                   'String constant might be missing an r prefix.',
+                  'anomalous-backslash-in-string',
                   'Used when a backslash is in a literal string but not as an '
                   'escape.'),
         'W1402': ('Anomalous Unicode escape in byte string: \'%s\'. '
                   'String constant might be missing an r or u prefix.',
+                  'anomalous-unicode-escape-in-string',
                   'Used when an escape like \\u is encountered in a byte '
                   'string where it has no effect.'),
         }

checkers/imports.py

 
 MSGS = {
     'F0401': ('Unable to import %s',
+              'import-error',
               'Used when pylint has been unable to import a module.'),
     'R0401': ('Cyclic import (%s)',
+              'cyclic-import',
               'Used when a cyclic import between two or more modules is \
               detected.'),
 
     'W0401': ('Wildcard import %s',
+              'wildcard-import',
               'Used when `from module import *` is detected.'),
     'W0402': ('Uses of a deprecated module %r',
+              'deprecated-module',
               'Used a module marked as deprecated is imported.'),
     'W0403': ('Relative import %r, should be %r',
+              'relative-import',
               'Used when an import relative to the package directory is \
               detected.'),
     'W0404': ('Reimport %r (imported line %s)',
+              'reimported',
               'Used when a module is reimported multiple times.'),
     'W0406': ('Module import itself',
+              'import-self',
               'Used when a module is importing itself.'),
 
     'W0410': ('__future__ import is not the first non docstring statement',
+              'misplaced-future',
               'Python 2.5 and greater require __future__ import to be the \
               first non docstring statement in the module.'),
     }

checkers/logging.py

 
 MSGS = {
     'W1201': ('Specify string format arguments as logging function parameters',
+             'logging-not-lazy',
              'Used when a logging statement has a call form of '
              '"logging.<logging method>(format_string % (format_args...))". '
              'Such calls should leave string interpolation to the logging '
              'logged. For more, see '
              'http://www.python.org/dev/peps/pep-0282/.'),
     'E1200': ('Unsupported logging format character %r (%#02x) at index %d',
+              'logging-unsupported-format',
               'Used when an unsupported format character is used in a logging\
               statement format string.'),
     'E1201': ('Logging format string ends in middle of conversion specifier',
+              'logging-format-truncated',
               'Used when a logging statement format string terminates before\
               the end of a conversion specifier.'),
     'E1205': ('Too many arguments for logging format string',
+              'logging-too-many-args',
               'Used when a logging format string is given too few arguments.'),
     'E1206': ('Not enough arguments for logging format string',
+              'logging-too-few-args',
               'Used when a logging format string is given too many arguments'),
     }
 
 
 MSGS = {
     'W0511': ('%s',
+              'fixme',
               'Used when a warning note as FIXME or XXX is detected.'),
     }
 

checkers/newstyle.py

 
 MSGS = {
     'E1001': ('Use of __slots__ on an old style class',
+              'slots-on-old-class',
               'Used when an old style class uses the __slots__ attribute.'),
     'E1002': ('Use of super on an old style class',
+              'super-on-old-class',
               'Used when an old style class uses the super builtin.'),
     'E1003': ('Bad first argument %r given to super class',
+              'bad-super-call',
               'Used when another argument than the current class is given as \
               first argument of the super builtin.'),
     'W1001': ('Use of "property" on an old style class',
+              'property-on-old-class',
               'Used when PyLint detect the use of the builtin "property" \
               on an old style class while this is relying on new style \
               classes features'),

checkers/similar.py

 
 
 MSGS = {'R0801': ('Similar lines in %s files\n%s',
+                  'duplicate-code',
                   'Indicates that a set of similar lines has been detected \
                   among multiple file. This usually means that the code should \
                   be refactored to avoid this duplication.')}

checkers/string_format.py

 
 MSGS = {
     'E1300': ("Unsupported format character %r (%#02x) at index %d",
+              "bad-format-character",
               "Used when a unsupported format character is used in a format\
               string."),
     'E1301': ("Format string ends in middle of conversion specifier",
+              "truncated-format-string",
               "Used when a format string terminates before the end of a \
               conversion specifier."),
     'E1302': ("Mixing named and unnamed conversion specifiers in format string",
+              "mixed-format-string",
               "Used when a format string contains both named (e.g. '%(foo)d') \
               and unnamed (e.g. '%d') conversion specifiers.  This is also \
               used when a named conversion specifier contains * for the \
               minimum field width and/or precision."),
     'E1303': ("Expected mapping for format string, not %s",
+              "format-needs-mapping",
               "Used when a format string that uses named conversion specifiers \
               is used with an argument that is not a mapping."),
     'W1300': ("Format string dictionary key should be a string, not %s",
+              "bad-format-string-key",
               "Used when a format string that uses named conversion specifiers \
               is used with a dictionary whose keys are not all strings."),
     'W1301': ("Unused key %r in format string dictionary",
+              "unused-format-string-key",
               "Used when a format string that uses named conversion specifiers \
               is used with a dictionary that conWtains keys not required by the \
               format string."),
     'E1304': ("Missing key %r in format string dictionary",
+              "missing-format-string-key",
               "Used when a format string that uses named conversion specifiers \
               is used with a dictionary that doesn't contain all the keys \
               required by the format string."),
     'E1305': ("Too many arguments for format string",
+              "too-many-format-args",
               "Used when a format string that uses unnamed conversion \
               specifiers is given too few arguments."),
     'E1306': ("Not enough arguments for format string",
+              "too-few-format-args",
               "Used when a format string that uses unnamed conversion \
               specifiers is given too many arguments"),
     }

checkers/typecheck.py

 
 MSGS = {
     'E1101': ('%s %r has no %r member',
+              'no-member',
               'Used when a variable is accessed for an unexistent member.'),
     'E1102': ('%s is not callable',
+              'not-callable',
               'Used when an object being called has been inferred to a non \
               callable object'),
     'E1103': ('%s %r has no %r member (but some types could not be inferred)',
+              'maybe-no-member',
               'Used when a variable is accessed for an unexistent member, but \
               astng was not able to interpret all possible types of this \
               variable.'),
     'E1111': ('Assigning to function call which doesn\'t return',
+              'assignment-from-no-return',
               'Used when an assignment is done on a function call but the \
               inferred function doesn\'t return anything.'),
     'W1111': ('Assigning to function call which only returns None',
+              'assignment-from-none',
               'Used when an assignment is done on a function call but the \
               inferred function returns nothing but None.'),
 
     'E1120': ('No value passed for parameter %s in function call',
+              'no-value-for-parameter',
               'Used when a function call passes too few arguments.'),
     'E1121': ('Too many positional arguments for function call',
+              'too-many-function-args',
               'Used when a function call passes too many positional \
               arguments.'),
     'E1122': ('Duplicate keyword argument %r in function call',
+              'duplicate-keyword-arg',
               'Used when a function call passes the same keyword argument \
               multiple times.'),
     'E1123': ('Passing unexpected keyword argument %r in function call',
+              'unexpected-keyword-arg',
               'Used when a function call passes a keyword argument that \
               doesn\'t correspond to one of the function\'s parameter names.'),
     'E1124': ('Multiple values passed for parameter %r in function call',
+              'redundant-keyword-arg',
               'Used when a function call would result in assigning multiple \
               values to a function parameter, one value from a positional \
               argument and one from a keyword argument.'),

checkers/variables.py

 
 MSGS = {
     'E0601': ('Using variable %r before assignment',
+              'used-before-assignment',
               'Used when a local variable is accessed before it\'s \
               assignment.'),
     'E0602': ('Undefined variable %r',
+              'undefined-variable',
               'Used when an undefined variable is accessed.'),
     'E0603': ('Undefined variable name %r in __all__',
+              'undefined-all-variable',
               'Used when an undefined variable name is referenced in __all__.'),
     'E0611': ('No name %r in module %r',
+              'no-name-in-module',
               'Used when a name cannot be found in a module.'),
 
     'W0601': ('Global variable %r undefined at the module level',
+              'global-variable-undefined',
               'Used when a variable is defined through the "global" statement \
               but the variable is not defined in the module scope.'),
     'W0602': ('Using global for %r but no assignment is done',
+              'global-variable-not-assigned',
               'Used when a variable is defined through the "global" statement \
               but no assignment to this variable is done.'),
     'W0603': ('Using the global statement', # W0121
+              'global-statement',
               'Used when you use the "global" statement to update a global \
               variable. PyLint just try to discourage this \
               usage. That doesn\'t mean you can not use it !'),
     'W0604': ('Using the global statement at the module level', # W0103
+              'global-at-module-level',
               'Used when you use the "global" statement at the module level \
               since it has no effect'),
     'W0611': ('Unused import %s',
+              'unused-import',
               'Used when an imported module or variable is not used.'),
     'W0612': ('Unused variable %r',
+              'unused-variable',
               'Used when a variable is defined but not used.'),
     'W0613': ('Unused argument %r',
+              'unused-argument',
               'Used when a function or method argument is not used.'),
     'W0614': ('Unused import %s from wildcard import',
+              'unused-wildcard-import',
               'Used when an imported module or variable is not used from a \
               \'from X import *\' style import.'),
 
     'W0621': ('Redefining name %r from outer scope (line %s)',
+              'redefined-outer-name',
               'Used when a variable\'s name hide a name defined in the outer \
               scope.'),
     'W0622': ('Redefining built-in %r',
+              'redefined-builtin',
               'Used when a variable or function override a built-in.'),
     'W0623': ('Redefining name %r from %s in exception handler',
+              'redefine-in-handler',
               'Used when an exception handler assigns the exception \
                to an existing name'),
 
     'W0631': ('Using possibly undefined loop variable %r',
+              'undefined-loop-variable',
               'Used when an loop variable (i.e. defined by a for loop or \
               a list comprehension or a generator expression) is used outside \
               the loop.'),
      E0202, # I have a good reason, trust me
      C0302  # that's it
 
+4.6 Do I have to remember all these numbers?
+--------------------------------------------
+
+No, starting from 0.25.3, you can use symbolic names for messages::
+
+    # pylint: disable=fixme, line-too-long
+
+You can show these symbols in the output with the `-sy` option.
+
 5. Classes and Inheritance
 ==========================
 
 --html=y_or_n           Use HTML as output format instead of text.
 --list-msgs             Generate pylint's messages.
 --full-documentation    Generate pylint's full documentation, in reST format.
+--include_ids=y_or_n    Show numeric ids of messages (like 'C0301')
+--symbols=y_or_n        Show symbolic ids of messsages (like 'line-too-long')
 
 .. _features: features.html
 
 
 MSGS = {
     'F0001': ('%s',
+              'fatal',
               'Used when an error occurred preventing the analysis of a \
               module (unable to find it for instance).'),
     'F0002': ('%s: %s',
+              'astng-error',
               'Used when an unexpected error occurred while building the ASTNG \
               representation. This is usually accompanied by a traceback. \
               Please report such errors !'),
     'F0003': ('ignored builtin module %s',
+              'ignored-builtin-module',
               'Used to indicate that the user asked to analyze a builtin module\
               which has been skipped.'),
     'F0004': ('unexpected inferred value %s',
+              'unexpected-inferred-value',
               'Used to indicate that some value of an unexpected type has been \
               inferred.'),
     'F0010': ('error while code parsing: %s',
+              'parse-error',
               'Used when an exception occured while building the ASTNG \
                representation which could be handled by astng.'),
 
-
     'I0001': ('Unable to run raw checkers on built-in module %s',
+              'raw-checker-failed',
               'Used to inform that a built-in module has not been checked \
               using the raw checkers.'),
 
     'I0010': ('Unable to consider inline option %r',
+              'bad-inline-option',
               'Used when an inline option is either badly formatted or can\'t \
               be used inside modules.'),
 
     'I0011': ('Locally disabling %s',
+              'locally-disabled',
               'Used when an inline option disables a message or a messages \
               category.'),
     'I0012': ('Locally enabling %s',
+              'locally-enabled',
               'Used when an inline option enables a message or a messages \
               category.'),
     'I0013': ('Ignoring entire file',
+              'file-ignored',
               'Used to inform that the file will not be checked'),
 
 
     'E0001': ('%s',
+              'syntax-error',
               'Used when a syntax error is raised for a module.'),
 
     'E0011': ('Unrecognized file option %r',
+              'unrecognized-inline-option',
               'Used when an unknown inline option is encountered.'),
     'E0012': ('Bad option value %r',
+              'bad-option-value',
               'Used when a bad value for an inline option is encountered.'),
     }
 
                   'group': 'Reports',
                   'help' : 'Include message\'s id in output'}),
 
+                ('symbols',
+                 {'type' : 'yn', 'metavar' : '<y_or_n>', 'default' : 0,
+                  'short': 's',
+                  'group': 'Reports',
+                  'help' : 'Include symbolic ids of messages in output'}),
+
                 ('files-output',
                  {'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>',
                   'group': 'Reports', 'level': 1,
         name.
         """
         self.reporter.include_ids = self.config.include_ids
+        self.reporter.symbols = self.config.symbols
         if not isinstance(files_or_modules, (list, tuple)):
             files_or_modules = (files_or_modules,)
         walker = PyLintASTWalker(self)

reporters/__init__.py

     """raised when a report is empty and so should not be displayed"""
 
 class BaseReporter:
-    """base class for reporters"""
+    """base class for reporters
+
+    symbols: show short symbolic names for messages.
+    """
 
     extension = ''
 
     def __init__(self, output=None):
         self.linter = None
         self.include_ids = None
+        self.symbols = None
         self.section = 0
         self.out = None
         self.out_encoding = None
         self.set_output(output)
 
+    def make_sigle(self, msg_id):
+        """generate a short prefix for a message.
+
+        The sigle can include the id, the symbol, or both, or it can just be
+        the message class.
+        """
+        if self.include_ids:
+            sigle = msg_id
+        else:
+            sigle = msg_id[0]
+        if self.symbols:
+            symbol = self.linter.check_message_id(msg_id).symbol
+            if symbol:
+                sigle += '(%s)' % symbol
+        return sigle
+
     def set_output(self, output=None):
         """set output stream"""
         self.out = output or sys.stdout

reporters/guireporter.py

     def add_message(self, msg_id, location, msg):
         """manage message of different type and in the context of path"""
         module, obj, line, col_offset = location[1:]
-        if self.include_ids:
-            sigle = msg_id
-        else:
-            sigle = msg_id[0]
-
+        sigle = self.make_sigle(msg_id)
         full_msg = [sigle, module, obj, str(line), msg]
         self.msgs += [[sigle, module, obj, str(line)]]
         self.gui.msg_queue.put(full_msg)

reporters/html.py

     def add_message(self, msg_id, location, msg):
         """manage message of different type and in the context of path"""
         module, obj, line, col_offset = location[1:]
-        if self.include_ids:
-            sigle = msg_id
-        else:
-            sigle = msg_id[0]
+        sigle = self.make_sigle(msg_id)
         self.msgs += [sigle, module, obj, str(line), str(col_offset), escape(msg)]
 
     def set_output(self, output=None):

reporters/text.py

                 self.writeln('************* %s' % module)
         if obj:
             obj = ':%s' % obj
-        if self.include_ids:
-            sigle = msg_id
-        else:
-            sigle = msg_id[0]
+        sigle = self.make_sigle(msg_id)
         self.writeln('%s:%3s,%s%s: %s' % (sigle, line, col_offset, obj, msg))
 
     def _display(self, layout):
         path, _, obj, line, _ = location
         if obj:
             obj = ', %s' % obj
-        if self.include_ids:
-            sigle = msg_id
-        else:
-            sigle = msg_id[0]
+        sigle = self.make_sigle(msg_id)
         if self._prefix:
             path = path.replace(self._prefix, '')
         self.writeln(self.line_format % locals())
             self._modules[module] = 1
         if obj:
             obj = ':%s' % obj
-        if self.include_ids:
-            sigle = msg_id
-        else:
-            sigle = msg_id[0]
+        sigle = self.make_sigle(msg_id)
         color, style = self._get_decoration(sigle)
         msg = colorize_ansi(msg, color, style)
         sigle = colorize_ansi(sigle, color, style)

test/input/func_docstring.py

 ##     class BBBB:
 ##         # missing docstring
 ##         pass
-    
+
 ##     class CCCC:
 ##         """yeah !"""
 ##         def method1(self):
 ##         def method2(self):
 ##             """ yeah !"""
 ##             pass
-    
+
     def method1(self):
         pass
-    
+
     def method2(self):
         """ yeah !"""
         pass
 
     def __init__(self):
         pass
-    
+
 class DDDD(AAAA):
     """yeah !"""
 
     def __init__(self):
         AAAA.__init__(self)
- 
+
+# pylint: disable=missing-docstring
+def function4():
+    pass

test/unittest_lint.py

         self.assert_(linter.is_message_enabled('E1101', 75))
         self.assert_(linter.is_message_enabled('E1101', 77))
 
+    def test_enable_by_symbol(self):
+        """messages can be controlled by symbolic names.
+
+        The state is consistent across symbols and numbers.
+        """
+        linter = self.linter
+        linter.open()
+        linter.set_current_module('toto')
+        self.assertTrue(linter.is_message_enabled('W0101'))
+        self.assertTrue(linter.is_message_enabled('unreachable'))
+        self.assertTrue(linter.is_message_enabled('W0102'))
+        self.assertTrue(linter.is_message_enabled('dangerous-default-value'))
+        linter.disable('unreachable', scope='package')
+        linter.disable('dangerous-default-value', scope='module', line=1)
+        self.assertFalse(linter.is_message_enabled('W0101'))
+        self.assertFalse(linter.is_message_enabled('unreachable'))
+        self.assertFalse(linter.is_message_enabled('W0102', 1))
+        self.assertFalse(linter.is_message_enabled('dangerous-default-value', 1))
+        linter.set_current_module('tutu')
+        self.assertFalse(linter.is_message_enabled('W0101'))
+        self.assertFalse(linter.is_message_enabled('unreachable'))
+        self.assertTrue(linter.is_message_enabled('W0102'))
+        self.assertTrue(linter.is_message_enabled('dangerous-default-value'))
+        linter.enable('unreachable', scope='package')
+        linter.enable('dangerous-default-value', scope='module', line=1)
+        self.assertTrue(linter.is_message_enabled('W0101'))
+        self.assertTrue(linter.is_message_enabled('unreachable'))
+        self.assertTrue(linter.is_message_enabled('W0102', 1))
+        self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1))
+
     def test_list_messages(self):
         sys.stdout = StringIO()
         try:
 """
 
 import sys
+from warnings import warn
 from os import linesep
 from os.path import dirname, basename, splitext, exists, isdir, join, normpath
 
 
 
 class Message:
-    def __init__(self, checker, msgid, msg, descr):
+    def __init__(self, checker, msgid, msg, descr, symbol):
         assert len(msgid) == 5, 'Invalid message id %s' % msgid
         assert msgid[0] in MSG_TYPES, \
                'Bad message type %s in %r' % (msgid[0], msgid)
         self.msg = msg
         self.descr = descr
         self.checker = checker
+        self.symbol = symbol
 
 class MessagesHandlerMixIn:
     """a mix-in class containing all the messages related methods for the main
     def __init__(self):
         # dictionary of registered messages
         self._messages = {}
+        # dictionary from string symbolic id to Message object.
+        self._messages_by_symbol = {}
         self._msgs_state = {}
         self._module_msgs_state = {} # None
         self._msgs_by_category = {}
         """
         msgs_dict = checker.msgs
         chkid = None
-        for msgid, (msg, msgdescr) in msgs_dict.iteritems():
+        for msgid, msg_tuple in msgs_dict.iteritems():
+            if len(msg_tuple) == 3:
+                (msg, msgsymbol, msgdescr) = msg_tuple
+                assert msgsymbol not in self._messages_by_symbol, \
+                    'Message symbol %r is already defined' % msgsymbol
+            else:
+                # messages should have a symbol, but for backward compatibility
+                # they may not.
+                (msg, msgdescr) = msg_tuple
+                warn("[pylint 0.26] description of message %s doesn't include "
+                     "a symbolic name" % msgid, DeprecationWarning)
+                msgsymbol = None
             # avoid duplicate / malformed ids
             assert msgid not in self._messages, \
                    'Message id %r is already defined' % msgid
             assert chkid is None or chkid == msgid[1:3], \
                    'Inconsistent checker part in message id %r' % msgid
             chkid = msgid[1:3]
-            self._messages[msgid] = Message(checker, msgid, msg, msgdescr)
+            msg = Message(checker, msgid, msg, msgdescr, msgsymbol)
+            self._messages[msgid] = msg
+            self._messages_by_symbol[msgsymbol] = msg
             self._msgs_by_category.setdefault(msgid[0], []).append(msgid)
 
     def get_message_help(self, msgid, checkerref=False):
             desc += ' This message belongs to the %s checker.' % \
                    msg.checker.name
         title = msg.msg
+        if msg.symbol:
+            symbol_part = ' (%s)' % msg.symbol
+        else:
+            symbol_part = ''
         if title != '%s':
             title = title.splitlines()[0]
-            return ':%s: *%s*\n%s' % (msg.msgid, title, desc)
-        return ':%s:\n%s' % (msg.msgid, desc)
+            return ':%s%s: *%s*\n%s' % (msg.msgid, symbol_part, title, desc)
+        return ':%s%s:\n%s' % (msg.msgid, symbol_part, desc)
 
     def disable(self, msgid, scope='package', line=None):
         """don't output message of the given id"""
         if msgid.lower().startswith('rp'):
             self.disable_report(msgid)
             return
-        # msgid is a msgid.
+        # msgid is a symbolic or numeric msgid.
         msg = self.check_message_id(msgid)
         if scope == 'module':
             assert line > 0
         if msgid.lower().startswith('rp'):
             self.enable_report(msgid)
             return
-        # msgid is a msgid.
+        # msgid is a symbolic or numeric msgid.
         msg = self.check_message_id(msgid)
         if scope == 'module':
             assert line > 0
             self.config.enable = [mid for mid, val in msgs.iteritems() if val]
 
     def check_message_id(self, msgid):
-        """raise UnknownMessage if the message id is not defined"""
+        """returns the Message object for this message.
+
+        msgid may be either a numeric or symbolic id.
+
+        Raises UnknownMessage if the message id is not defined.
+        """
+        if msgid in self._messages_by_symbol:
+            return self._messages_by_symbol[msgid]
         msgid = msgid.upper()
         try:
             return self._messages[msgid]
     def is_message_enabled(self, msgid, line=None):
         """return true if the message associated to the given message id is
         enabled
+
+        msgid may be either a numeric or symbolic message id.
         """
+        if msgid in self._messages_by_symbol:
+            msgid = self._messages_by_symbol[msgid].msgid
         if line is None:
             return self._msgs_state.get(msgid, True)
         try:
             self.walk(child)
         for cb in self.leave_events.get(cid, ()):
             cb(astng)
-