George Sakkis avatar George Sakkis committed 79f6283

Move all source under a 'pylint' directory so that setuptools.develop works

Comments (0)

Files changed (71)

__init__.py

-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-""" Copyright (c) 2002-2008 LOGILAB S.A. (Paris, FRANCE).
-http://www.logilab.fr/ -- mailto:contact@logilab.fr  
-"""
-

__pkginfo__.py

-# pylint: disable=W0622,C0103
-# Copyright (c) 2003-2012 LOGILAB S.A. (Paris, FRANCE).
-# http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-"""pylint packaging information"""
-
-modname = distname = 'pylint'
-
-numversion = (0, 25, 2)
-version = '.'.join([str(num) for num in numversion])
-
-install_requires = ['logilab-common >= 0.53.0', 'logilab-astng >= 0.21.1']
-
-license = 'GPL'
-copyright = 'Logilab S.A.'
-description = "python code static checker"
-web = "http://www.logilab.org/project/%s" % distname
-ftp = "ftp://ftp.logilab.org/pub/%s" % modname
-mailinglist = "mailto://python-projects@lists.logilab.org"
-author = 'Logilab'
-author_email = 'python-projects@lists.logilab.org'
-
-classifiers =  ['Development Status :: 4 - Beta',
-                'Environment :: Console',
-                'Intended Audience :: Developers',
-                'License :: OSI Approved :: GNU General Public License (GPL)',
-                'Operating System :: OS Independent',
-                'Programming Language :: Python',
-                'Topic :: Software Development :: Debuggers',
-                'Topic :: Software Development :: Quality Assurance',
-                'Topic :: Software Development :: Testing',
-                ]
-
-
-long_desc = """\
- Pylint is a Python source code analyzer which looks for programming
- errors, helps enforcing a coding standard and sniffs for some code
- smells (as defined in Martin Fowler's Refactoring book)
- .
- Pylint can be seen as another PyChecker since nearly all tests you
- can do with PyChecker can also be done with Pylint. However, Pylint
- offers some more features, like checking length of lines of code,
- checking if variable names are well-formed according to your coding
- standard, or checking if declared interfaces are truly implemented,
- and much more.
- .
- Additionally, it is possible to write plugins to add your own checks.
- .
- Pylint is shipped with "pylint-gui", "pyreverse" (UML diagram generator)
- and "symilar" (an independent similarities checker)."""
-
-from os.path import join
-scripts = [join('bin', filename)
-           for filename in ('pylint', 'pylint-gui', "symilar", "epylint",
-                            "pyreverse")]
-

checkers/__init__.py

-# Copyright (c) 2003-2010 LOGILAB S.A. (Paris, FRANCE).
-# http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-"""utilities methods and classes for checkers
-
-Base id of standard checkers (used in msg and report ids):
-01: base
-02: classes
-03: format
-04: import
-05: misc
-06: variables
-07: exceptions
-08: similar
-09: design_analysis
-10: newstyle
-11: typecheck
-12: logging
-13: string_format
-14-50: not yet used: reserved for future internal checkers.
-51-99: perhaps used: reserved for external checkers
-
-The raw_metrics checker has no number associated since it doesn't emit any
-messages nor reports. XXX not true, emit a 07 report !
-
-"""
-
-import tokenize
-from os import listdir
-from os.path import dirname, join, isdir, splitext
-
-from logilab.astng.utils import ASTWalker
-from logilab.common.configuration import OptionsProviderMixIn
-
-from pylint.reporters import diff_string, EmptyReport
-
-def table_lines_from_stats(stats, old_stats, columns):
-    """get values listed in <columns> from <stats> and <old_stats>,
-    and return a formated list of values, designed to be given to a
-    ureport.Table object
-    """
-    lines = []
-    for m_type in columns:
-        new = stats[m_type]
-        format = str
-        if isinstance(new, float):
-            format = lambda num: '%.3f' % num
-        old = old_stats.get(m_type)
-        if old is not None:
-            diff_str = diff_string(old, new)
-            old = format(old)
-        else:
-            old, diff_str = 'NC', 'NC'
-        lines += (m_type.replace('_', ' '), format(new), old, diff_str)
-    return lines
-
-
-class BaseChecker(OptionsProviderMixIn, ASTWalker):
-    """base class for checkers"""
-    # checker name (you may reuse an existing one)
-    name = None
-    # options level (0 will be displaying in --help, 1 in --long-help)
-    level = 1
-    # ordered list of options to control the ckecker behaviour
-    options = ()
-    # messages issued by this checker
-    msgs = {}
-    # reports issued by this checker
-    reports = ()
-
-    def __init__(self, linter=None):
-        """checker instances should have the linter as argument
-
-        linter is an object implementing ILinter
-        """
-        ASTWalker.__init__(self, self)
-        self.name = self.name.lower()
-        OptionsProviderMixIn.__init__(self)
-        self.linter = linter
-        # messages that are active for the current check
-        self.active_msgs = set()
-
-    def add_message(self, msg_id, line=None, node=None, args=None):
-        """add a message of a given type"""
-        self.linter.add_message(msg_id, line, node, args)
-
-    def package_dir(self):
-        """return the base directory for the analysed package"""
-        return dirname(self.linter.base_file)
-
-
-    # dummy methods implementing the IChecker interface
-
-    def open(self):
-        """called before visiting project (i.e set of modules)"""
-
-    def close(self):
-        """called after visiting project (i.e set of modules)"""
-
-class BaseRawChecker(BaseChecker):
-    """base class for raw checkers"""
-
-    def process_module(self, node):
-        """process a module
-
-        the module's content is accessible via the stream object
-
-        stream must implement the readline method
-        """
-        stream = node.file_stream
-        stream.seek(0) # XXX may be removed with astng > 0.23
-        self.process_tokens(tokenize.generate_tokens(stream.readline))
-
-    def process_tokens(self, tokens):
-        """should be overridden by subclasses"""
-        raise NotImplementedError()
-
-
-PY_EXTS = ('.py', '.pyc', '.pyo', '.pyw', '.so', '.dll')
-
-def initialize(linter):
-    """initialize linter with checkers in this package """
-    package_load(linter, __path__[0])
-
-def package_load(linter, directory):
-    """load all module and package in the given directory, looking for a
-    'register' function in each one, used to register pylint checkers
-    """
-    globs = globals()
-    imported = {}
-    for filename in listdir(directory):
-        basename, extension = splitext(filename)
-        if basename in imported or basename == '__pycache__':
-            continue
-        if extension in PY_EXTS and basename != '__init__' or (
-             not extension and basename != 'CVS' and
-             isdir(join(directory, basename))):
-            try:
-                module = __import__(basename, globs, globs, None)
-            except ValueError:
-                # empty module name (usually emacs auto-save files)
-                continue
-            except ImportError, exc:
-                import sys
-                print >> sys.stderr, "Problem importing module %s: %s" % (filename, exc)
-            else:
-                if hasattr(module, 'register'):
-                    module.register(linter)
-                    imported[basename] = 1
-
-__all__ = ('BaseChecker', 'initialize', 'package_load')

checkers/base.py

-# Copyright (c) 2003-2010 LOGILAB S.A. (Paris, FRANCE).
-# Copyright (c) 2009-2010 Arista Networks, Inc.
-# http://www.logilab.fr/ -- mailto:contact@logilab.fr
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-"""basic checker for Python code"""
-
-
-from logilab import astng
-from logilab.common.ureports import Table
-from logilab.astng import are_exclusive
-
-from pylint.interfaces import IASTNGChecker
-from pylint.reporters import diff_string
-from pylint.checkers import BaseChecker, EmptyReport
-from pylint.checkers.utils import check_messages, clobber_in_except, is_inside_except
-
-
-import re
-
-# regex for class/function/variable/constant name
-CLASS_NAME_RGX = re.compile('[A-Z_][a-zA-Z0-9]+$')
-MOD_NAME_RGX = re.compile('(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$')
-CONST_NAME_RGX = re.compile('(([A-Z_][A-Z0-9_]*)|(__.*__))$')
-COMP_VAR_RGX = re.compile('[A-Za-z_][A-Za-z0-9_]*$')
-DEFAULT_NAME_RGX = re.compile('[a-z_][a-z0-9_]{2,30}$')
-# do not require a doc string on system methods
-NO_REQUIRED_DOC_RGX = re.compile('__.*__')
-
-del re
-
-def in_loop(node):
-    """return True if the node is inside a kind of for loop"""
-    parent = node.parent
-    while parent is not None:
-        if isinstance(parent, (astng.For, astng.ListComp, astng.SetComp,
-                               astng.DictComp, astng.GenExpr)):
-            return True
-        parent = parent.parent
-    return False
-
-def in_nested_list(nested_list, obj):
-    """return true if the object is an element of <nested_list> or of a nested
-    list
-    """
-    for elmt in nested_list:
-        if isinstance(elmt, (list, tuple)):
-            if in_nested_list(elmt, obj):
-                return True
-        elif elmt == obj:
-            return True
-    return False
-
-def report_by_type_stats(sect, stats, old_stats):
-    """make a report of
-
-    * percentage of different types documented
-    * percentage of different types with a bad name
-    """
-    # percentage of different types documented and/or with a bad name
-    nice_stats = {}
-    for node_type in ('module', 'class', 'method', 'function'):
-        try:
-            total = stats[node_type]
-        except KeyError:
-            raise EmptyReport()
-        nice_stats[node_type] = {}
-        if total != 0:
-            try:
-                documented = total - stats['undocumented_'+node_type]
-                percent = (documented * 100.) / total
-                nice_stats[node_type]['percent_documented'] = '%.2f' % percent
-            except KeyError:
-                nice_stats[node_type]['percent_documented'] = 'NC'
-            try:
-                percent = (stats['badname_'+node_type] * 100.) / total
-                nice_stats[node_type]['percent_badname'] = '%.2f' % percent
-            except KeyError:
-                nice_stats[node_type]['percent_badname'] = 'NC'
-    lines = ('type', 'number', 'old number', 'difference',
-             '%documented', '%badname')
-    for node_type in ('module', 'class', 'method', 'function'):
-        new = stats[node_type]
-        old = old_stats.get(node_type, None)
-        if old is not None:
-            diff_str = diff_string(old, new)
-        else:
-            old, diff_str = 'NC', 'NC'
-        lines += (node_type, str(new), str(old), diff_str,
-                  nice_stats[node_type].get('percent_documented', '0'),
-                  nice_stats[node_type].get('percent_badname', '0'))
-    sect.append(Table(children=lines, cols=6, rheaders=1))
-
-def redefined_by_decorator(node):
-    """return True if the object is a method redefined via decorator.
-
-    For example:
-        @property
-        def x(self): return self._x
-        @x.setter
-        def x(self, value): self._x = value
-    """
-    if node.decorators:
-        for decorator in node.decorators.nodes:
-            if (isinstance(decorator, astng.Getattr) and
-                getattr(decorator.expr, 'name', None) == node.name):
-                return True
-    return False
-
-class _BasicChecker(BaseChecker):
-    __implements__ = IASTNGChecker
-    name = 'basic'
-
-class BasicErrorChecker(_BasicChecker):
-    msgs = {
-    'E0100': ('__init__ method is a generator',
-              'Used when the special class method __init__ is turned into a '
-              'generator by a yield in its body.'),
-    'E0101': ('Explicit return in __init__',
-              'Used when the special class method __init__ has an explicit \
-              return value.'),
-    'E0102': ('%s already defined line %s',
-              'Used when a function / class / method is redefined.'),
-    'E0103': ('%r not properly in loop',
-              'Used when break or continue keywords are used outside a loop.'),
-
-    'E0104': ('Return outside function',
-              'Used when a "return" statement is found outside a function or '
-              'method.'),
-    'E0105': ('Yield outside function',
-              'Used when a "yield" statement is found outside a function or '
-              'method.'),
-    'E0106': ('Return with argument inside 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",
-              "Used when you attempt to use the C-style pre-increment or"
-              "pre-decrement operator -- and ++, which doesn't exist in Python."),
-    }
-
-    def __init__(self, linter):
-        _BasicChecker.__init__(self, linter)
-
-    @check_messages('E0102')
-    def visit_class(self, node):
-        self._check_redefinition('class', node)
-
-    @check_messages('E0100', 'E0101', 'E0102', 'E0106')
-    def visit_function(self, node):
-        if not redefined_by_decorator(node):
-            self._check_redefinition(node.is_method() and 'method' or 'function', node)
-        # checks for max returns, branch, return in __init__
-        returns = node.nodes_of_class(astng.Return,
-                                      skip_klass=(astng.Function, astng.Class))
-        if node.is_method() and node.name == '__init__':
-            if node.is_generator():
-                self.add_message('E0100', node=node)
-            else:
-                values = [r.value for r in returns]
-                if  [v for v in values if not (v is None or
-                    (isinstance(v, astng.Const) and v.value is None)
-                    or  (isinstance(v, astng.Name) and v.name == 'None'))]:
-                    self.add_message('E0101', node=node)
-        elif node.is_generator():
-            # make sure we don't mix non-None returns and yields
-            for retnode in returns:
-                if isinstance(retnode.value, astng.Const) and \
-                       retnode.value.value is not None:
-                    self.add_message('E0106', node=node,
-                                     line=retnode.fromlineno)
-
-    @check_messages('E0104')
-    def visit_return(self, node):
-        if not isinstance(node.frame(), astng.Function):
-            self.add_message('E0104', node=node)
-
-    @check_messages('E0105')
-    def visit_yield(self, node):
-        if not isinstance(node.frame(), astng.Function):
-            self.add_message('E0105', node=node)
-
-    @check_messages('E0103')
-    def visit_continue(self, node):
-        self._check_in_loop(node, 'continue')
-
-    @check_messages('E0103')
-    def visit_break(self, node):
-        self._check_in_loop(node, 'break')
-
-    @check_messages('E0107')
-    def visit_unaryop(self, node):
-        """check use of the non-existent ++ adn -- operator operator"""
-        if ((node.op in '+-') and
-            isinstance(node.operand, astng.UnaryOp) and
-            (node.operand.op == node.op)):
-            self.add_message('E0107', node=node, args=node.op*2)
-
-    def _check_in_loop(self, node, node_name):
-        """check that a node is inside a for or while loop"""
-        _node = node.parent
-        while _node:
-            if isinstance(_node, (astng.For, astng.While)):
-                break
-            _node = _node.parent
-        else:
-            self.add_message('E0103', node=node, args=node_name)
-
-    def _check_redefinition(self, redeftype, node):
-        """check for redefinition of a function / method / class name"""
-        defined_self = node.parent.frame()[node.name]
-        if defined_self is not node and not are_exclusive(node, defined_self):
-            self.add_message('E0102', node=node,
-                             args=(redeftype, defined_self.fromlineno))
-
-
-
-class BasicChecker(_BasicChecker):
-    """checks for :
-    * doc strings
-    * modules / classes / functions / methods / arguments / variables name
-    * number of arguments, local variables, branches, returns and statements in
-functions, methods
-    * required module attributes
-    * dangerous default values as arguments
-    * redefinition of function / method / class
-    * uses of the global statement
-    """
-
-    __implements__ = IASTNGChecker
-
-    name = 'basic'
-    msgs = {
-    'W0101': ('Unreachable code',
-              'Used when there is some code behind a "return" or "raise" \
-              statement, which will never be accessed.'),
-    'W0102': ('Dangerous default value %s as argument',
-              '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',
-              'Used when a statement doesn\'t have (or at least seems to) \
-              any effect.'),
-    'W0105': ('String statement has no effect',
-              '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',
-              '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',
-              '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",
-              "Used when a dictionary expression binds the same key multiple \
-              times."),
-    'W0122': ('Use of the 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',
-              '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',
-              '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",
-              "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\'?',
-              '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
-              'Used when an attribute required for modules is missing.'),
-
-    }
-
-    options = (('required-attributes',
-                {'default' : (), 'type' : 'csv',
-                 'metavar' : '<attributes>',
-                 'help' : 'Required attributes for module, separated by a '
-                          'comma'}
-                ),
-               ('bad-functions',
-                {'default' : ('map', 'filter', 'apply', 'input'),
-                 'type' :'csv', 'metavar' : '<builtin function names>',
-                 'help' : 'List of builtins function names that should not be '
-                          'used, separated by a comma'}
-                ),
-               )
-    reports = ( ('RP0101', 'Statistics by type', report_by_type_stats), )
-
-    def __init__(self, linter):
-        _BasicChecker.__init__(self, linter)
-        self.stats = None
-        self._tryfinallys = None
-
-    def open(self):
-        """initialize visit variables and statistics
-        """
-        self._tryfinallys = []
-        self.stats = self.linter.add_stats(module=0, function=0,
-                                           method=0, class_=0)
-
-    def visit_module(self, node):
-        """check module name, docstring and required arguments
-        """
-        self.stats['module'] += 1
-        for attr in self.config.required_attributes:
-            if attr not in node:
-                self.add_message('C0121', node=node, args=attr)
-
-    def visit_class(self, node):
-        """check module name, docstring and redefinition
-        increment branch counter
-        """
-        self.stats['class'] += 1
-
-    @check_messages('W0104', 'W0105')
-    def visit_discard(self, node):
-        """check for various kind of statements without effect"""
-        expr = node.value
-        if isinstance(expr, astng.Const) and isinstance(expr.value,
-                                                        basestring):
-            # treat string statement in a separated message
-            self.add_message('W0105', node=node)
-            return
-        # ignore if this is :
-        # * a direct function call
-        # * the unique child of a try/except body
-        # * a yield (which are wrapped by a discard node in _ast XXX)
-        # warn W0106 if we have any underlying function call (we can't predict
-        # side effects), else W0104
-        if (isinstance(expr, (astng.Yield, astng.CallFunc)) or
-            (isinstance(node.parent, astng.TryExcept) and
-             node.parent.body == [node])):
-            return
-        if any(expr.nodes_of_class(astng.CallFunc)):
-            self.add_message('W0106', node=node, args=expr.as_string())
-        else:
-            self.add_message('W0104', node=node)
-
-    @check_messages('W0108')
-    def visit_lambda(self, node):
-        """check whether or not the lambda is suspicious
-        """
-        # if the body of the lambda is a call expression with the same
-        # argument list as the lambda itself, then the lambda is
-        # possibly unnecessary and at least suspicious.
-        if node.args.defaults:
-            # If the arguments of the lambda include defaults, then a
-            # judgment cannot be made because there is no way to check
-            # that the defaults defined by the lambda are the same as
-            # the defaults defined by the function called in the body
-            # of the lambda.
-            return
-        call = node.body
-        if not isinstance(call, astng.CallFunc):
-            # The body of the lambda must be a function call expression
-            # for the lambda to be unnecessary.
-            return
-        # XXX are lambda still different with astng >= 0.18 ?
-        # *args and **kwargs need to be treated specially, since they
-        # are structured differently between the lambda and the function
-        # call (in the lambda they appear in the args.args list and are
-        # indicated as * and ** by two bits in the lambda's flags, but
-        # in the function call they are omitted from the args list and
-        # are indicated by separate attributes on the function call node).
-        ordinary_args = list(node.args.args)
-        if node.args.kwarg:
-            if (not call.kwargs
-                or not isinstance(call.kwargs, astng.Name)
-                or node.args.kwarg != call.kwargs.name):
-                return
-        elif call.kwargs:
-            return
-        if node.args.vararg:
-            if (not call.starargs
-                or not isinstance(call.starargs, astng.Name)
-                or node.args.vararg != call.starargs.name):
-                return
-        elif call.starargs:
-            return
-        # The "ordinary" arguments must be in a correspondence such that:
-        # ordinary_args[i].name == call.args[i].name.
-        if len(ordinary_args) != len(call.args):
-            return
-        for i in xrange(len(ordinary_args)):
-            if not isinstance(call.args[i], astng.Name):
-                return
-            if node.args.args[i].name != call.args[i].name:
-                return
-        self.add_message('W0108', line=node.fromlineno, node=node)
-
-    def visit_function(self, node):
-        """check function name, docstring, arguments, redefinition,
-        variable names, max locals
-        """
-        self.stats[node.is_method() and 'method' or 'function'] += 1
-        # check for dangerous default values as arguments
-        for default in node.args.defaults:
-            try:
-                value = default.infer().next()
-            except astng.InferenceError:
-                continue
-            if isinstance(value, (astng.Dict, astng.List)):
-                if value is default:
-                    msg = default.as_string()
-                else:
-                    msg = '%s (%s)' % (default.as_string(), value.as_string())
-                self.add_message('W0102', node=node, args=(msg,))
-            if value.qname() == '__builtin__.set':
-                if isinstance(default, astng.CallFunc):
-                    msg = default.as_string()
-                else:
-                    msg = '%s (%s)' % (default.as_string(), value.qname())
-                self.add_message('W0102', node=node, args=(msg,))
-
-    @check_messages('W0101', 'W0150')
-    def visit_return(self, node):
-        """1 - check is the node has a right sibling (if so, that's some
-        unreachable code)
-        2 - check is the node is inside the finally clause of a try...finally
-        block
-        """
-        self._check_unreachable(node)
-        # Is it inside final body of a try...finally bloc ?
-        self._check_not_in_finally(node, 'return', (astng.Function,))
-
-    @check_messages('W0101')
-    def visit_continue(self, node):
-        """check is the node has a right sibling (if so, that's some unreachable
-        code)
-        """
-        self._check_unreachable(node)
-
-    @check_messages('W0101', 'W0150')
-    def visit_break(self, node):
-        """1 - check is the node has a right sibling (if so, that's some
-        unreachable code)
-        2 - check is the node is inside the finally clause of a try...finally
-        block
-        """
-        # 1 - Is it right sibling ?
-        self._check_unreachable(node)
-        # 2 - Is it inside final body of a try...finally bloc ?
-        self._check_not_in_finally(node, 'break', (astng.For, astng.While,))
-
-    @check_messages('W0101')
-    def visit_raise(self, node):
-        """check is the node has a right sibling (if so, that's some unreachable
-        code)
-        """
-        self._check_unreachable(node)
-
-    @check_messages('W0122')
-    def visit_exec(self, node):
-        """just print a warning on exec statements"""
-        self.add_message('W0122', node=node)
-
-    @check_messages('W0141', 'W0142')
-    def visit_callfunc(self, node):
-        """visit a CallFunc node -> check if this is not a blacklisted builtin
-        call and check for * or ** use
-        """
-        if isinstance(node.func, astng.Name):
-            name = node.func.name
-            # ignore the name if it's not a builtin (i.e. not defined in the
-            # locals nor globals scope)
-            if not (name in node.frame() or
-                    name in node.root()):
-                if name in self.config.bad_functions:
-                    self.add_message('W0141', node=node, args=name)
-        if node.starargs or node.kwargs:
-            scope = node.scope()
-            if isinstance(scope, astng.Function):
-                toprocess = [(n, vn) for (n, vn) in ((node.starargs, scope.args.vararg),
-                                                     (node.kwargs, scope.args.kwarg)) if n]
-                if toprocess:
-                    for cfnode, fargname in toprocess[:]:
-                        if getattr(cfnode, 'name', None) == fargname:
-                            toprocess.remove((cfnode, fargname))
-                    if not toprocess:
-                        return # W0142 can be skipped
-            self.add_message('W0142', node=node.func)
-
-    @check_messages('W0199')
-    def visit_assert(self, node):
-        """check the use of an assert statement on a tuple."""
-        if node.fail is None and isinstance(node.test, astng.Tuple) and \
-           len(node.test.elts) == 2:
-             self.add_message('W0199', line=node.fromlineno, node=node)
-
-    @check_messages('W0109')
-    def visit_dict(self, node):
-        """check duplicate key in dictionary"""
-        keys = set()
-        for k, v in node.items:
-            if isinstance(k, astng.Const):
-                key = k.value
-                if key in keys:
-                    self.add_message('W0109', node=node, args=key)
-                keys.add(key)
-
-    def visit_tryfinally(self, node):
-        """update try...finally flag"""
-        self._tryfinallys.append(node)
-
-    def leave_tryfinally(self, node):
-        """update try...finally flag"""
-        self._tryfinallys.pop()
-
-    def _check_unreachable(self, node):
-        """check unreachable code"""
-        unreach_stmt = node.next_sibling()
-        if unreach_stmt is not None:
-            self.add_message('W0101', node=unreach_stmt)
-
-    def _check_not_in_finally(self, node, node_name, breaker_classes=()):
-        """check that a node is not inside a finally clause of a
-        try...finally statement.
-        If we found before a try...finally bloc a parent which its type is
-        in breaker_classes, we skip the whole check."""
-        # if self._tryfinallys is empty, we're not a in try...finally bloc
-        if not self._tryfinallys:
-            return
-        # the node could be a grand-grand...-children of the try...finally
-        _parent = node.parent
-        _node = node
-        while _parent and not isinstance(_parent, breaker_classes):
-            if hasattr(_parent, 'finalbody') and _node in _parent.finalbody:
-                self.add_message('W0150', node=node, args=node_name)
-                return
-            _node = _parent
-            _parent = _node.parent
-
-
-
-class NameChecker(_BasicChecker):
-    msgs = {
-    'C0102': ('Black listed name "%s"',
-              'Used when the name is listed in the black list (unauthorized \
-              names).'),
-    'C0103': ('Invalid name "%s" (should match %s)',
-              'Used when the name doesn\'t match the regular expression \
-              associated to its type (constant, variable, class...).'),
-
-    }
-    options = (('module-rgx',
-                {'default' : MOD_NAME_RGX,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match correct '
-                          'module names'}
-                ),
-               ('const-rgx',
-                {'default' : CONST_NAME_RGX,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match correct '
-                          'module level names'}
-                ),
-               ('class-rgx',
-                {'default' : CLASS_NAME_RGX,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match correct '
-                          'class names'}
-                ),
-               ('function-rgx',
-                {'default' : DEFAULT_NAME_RGX,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match correct '
-                          'function names'}
-                ),
-               ('method-rgx',
-                {'default' : DEFAULT_NAME_RGX,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match correct '
-                          'method names'}
-                ),
-               ('attr-rgx',
-                {'default' : DEFAULT_NAME_RGX,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match correct '
-                          'instance attribute names'}
-                ),
-               ('argument-rgx',
-                {'default' : DEFAULT_NAME_RGX,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match correct '
-                          'argument names'}),
-               ('variable-rgx',
-                {'default' : DEFAULT_NAME_RGX,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match correct '
-                          'variable names'}
-                ),
-               ('inlinevar-rgx',
-                {'default' : COMP_VAR_RGX,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match correct '
-                          'list comprehension / generator expression variable \
-                          names'}
-                ),
-               # XXX use set
-               ('good-names',
-                {'default' : ('i', 'j', 'k', 'ex', 'Run', '_'),
-                 'type' :'csv', 'metavar' : '<names>',
-                 'help' : 'Good variable names which should always be accepted,'
-                          ' separated by a comma'}
-                ),
-               ('bad-names',
-                {'default' : ('foo', 'bar', 'baz', 'toto', 'tutu', 'tata'),
-                 'type' :'csv', 'metavar' : '<names>',
-                 'help' : 'Bad variable names which should always be refused, '
-                          'separated by a comma'}
-                ),
-               )
-
-    def open(self):
-        self.stats = self.linter.add_stats(badname_module=0,
-                                           badname_class=0, badname_function=0,
-                                           badname_method=0, badname_attr=0,
-                                           badname_const=0,
-                                           badname_variable=0,
-                                           badname_inlinevar=0,
-                                           badname_argument=0)
-
-    @check_messages('C0102', 'C0103')
-    def visit_module(self, node):
-        self._check_name('module', node.name.split('.')[-1], node)
-
-    @check_messages('C0102', 'C0103')
-    def visit_class(self, node):
-        self._check_name('class', node.name, node)
-        for attr, anodes in node.instance_attrs.items():
-            self._check_name('attr', attr, anodes[0])
-
-    @check_messages('C0102', 'C0103')
-    def visit_function(self, node):
-        self._check_name(node.is_method() and 'method' or 'function',
-                         node.name, node)
-        # check arguments name
-        args = node.args.args
-        if args is not None:
-            self._recursive_check_names(args, node)
-
-    @check_messages('C0102', 'C0103')
-    def visit_assname(self, node):
-        """check module level assigned names"""
-        frame = node.frame()
-        ass_type = node.ass_type()
-        if isinstance(ass_type, (astng.Comprehension, astng.Comprehension)):
-            self._check_name('inlinevar', node.name, node)
-        elif isinstance(frame, astng.Module):
-            if isinstance(ass_type, astng.Assign) and not in_loop(ass_type):
-                self._check_name('const', node.name, node)
-            elif isinstance(ass_type, astng.ExceptHandler):
-                self._check_name('variable', node.name, node)
-        elif isinstance(frame, astng.Function):
-            # global introduced variable aren't in the function locals
-            if node.name in frame:
-                self._check_name('variable', node.name, node)
-
-    def _recursive_check_names(self, args, node):
-        """check names in a possibly recursive list <arg>"""
-        for arg in args:
-            if isinstance(arg, astng.AssName):
-                self._check_name('argument', arg.name, node)
-            else:
-                self._recursive_check_names(arg.elts, node)
-
-    def _check_name(self, node_type, name, node):
-        """check for a name using the type's regexp"""
-        if is_inside_except(node):
-            clobbering, _ = clobber_in_except(node)
-            if clobbering:
-                return
-
-        if name in self.config.good_names:
-            return
-        if name in self.config.bad_names:
-            self.stats['badname_' + node_type] += 1
-            self.add_message('C0102', node=node, args=name)
-            return
-        regexp = getattr(self.config, node_type + '_rgx')
-        if regexp.match(name) is None:
-            self.add_message('C0103', node=node, args=(name, regexp.pattern))
-            self.stats['badname_' + node_type] += 1
-
-
-class DocStringChecker(_BasicChecker):
-    msgs = {
-    'C0111': ('Missing docstring', # W0131
-              '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
-              'Used when a module, function, class or method has an empty \
-              docstring (it would be too easy ;).'),
-    }
-    options = (('no-docstring-rgx',
-                {'default' : NO_REQUIRED_DOC_RGX,
-                 'type' : 'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Regular expression which should only match '
-                          'functions or classes name which do not require a '
-                          'docstring'}
-                ),
-               )
-
-    def open(self):
-        self.stats = self.linter.add_stats(undocumented_module=0,
-                                           undocumented_function=0,
-                                           undocumented_method=0,
-                                           undocumented_class=0)
-
-    def visit_module(self, node):
-        self._check_docstring('module', node)
-
-    def visit_class(self, node):
-        if self.config.no_docstring_rgx.match(node.name) is None:
-            self._check_docstring('class', node)
-
-    def visit_function(self, node):
-        if self.config.no_docstring_rgx.match(node.name) is None:
-            ftype = node.is_method() and 'method' or 'function'
-            if isinstance(node.parent.frame(), astng.Class):
-                overridden = False
-                # check if node is from a method overridden by its ancestor
-                for ancestor in node.parent.frame().ancestors():
-                    if node.name in ancestor and \
-                       isinstance(ancestor[node.name], astng.Function):
-                        overridden = True
-                        break
-                if not overridden:
-                    self._check_docstring(ftype, node)
-            else:
-                self._check_docstring(ftype, node)
-
-    def _check_docstring(self, node_type, node):
-        """check the node has a non empty docstring"""
-        docstring = node.doc
-        if docstring is None:
-            self.stats['undocumented_'+node_type] += 1
-            self.add_message('C0111', node=node)
-        elif not docstring.strip():
-            self.stats['undocumented_'+node_type] += 1
-            self.add_message('C0112', node=node)
-
-
-class PassChecker(_BasicChecker):
-    """check is the pass statement is really necessary"""
-    msgs = {'W0107': ('Unnecessary pass statement',
-                      'Used when a "pass" statement that can be avoided is '
-                      'encountered.)'),
-            }
-
-    def visit_pass(self, node):
-        if len(node.parent.child_sequence(node)) > 1:
-            self.add_message('W0107', node=node)
-
-
-def register(linter):
-    """required method to auto register this checker"""
-    linter.register_checker(BasicErrorChecker(linter))
-    linter.register_checker(BasicChecker(linter))
-    linter.register_checker(NameChecker(linter))
-    linter.register_checker(DocStringChecker(linter))
-    linter.register_checker(PassChecker(linter))

checkers/classes.py

-# Copyright (c) 2003-2011 LOGILAB S.A. (Paris, FRANCE).
-# http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-"""classes checker for Python code
-"""
-from __future__ import generators
-
-from logilab import astng
-from logilab.astng import YES, Instance, are_exclusive, AssAttr
-
-from pylint.interfaces import IASTNGChecker
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import (PYMETHODS, overrides_a_method,
-    check_messages, is_attr_private, is_attr_protected, node_frame_class)
-
-def class_is_abstract(node):
-    """return true if the given class node should be considered as an abstract
-    class
-    """
-    for method in node.methods():
-        if method.parent.frame() is node:
-            if method.is_abstract(pass_is_abstract=False):
-                return True
-    return False
-
-
-MSGS = {
-    'F0202': ('Unable to check methods signature (%s / %s)',
-              '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',
-              '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',
-              'Used when an instance member is accessed before it\'s actually\
-              assigned.'),
-    'W0201': ('Attribute %r 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
-              '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',
-              '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',
-              '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 should have %s as first argument', # E0212
-              'Used when a class method has an attribute different than "cls"\
-              as first argument, to easily differentiate them from regular \
-              instance methods.'),
-    'C0203': ('Metaclass method should have "mcs" as first argument', # E0214
-              'Used when a metaclass method has an attribute different the \
-              "mcs" as first argument.'),
-
-    'W0211': ('Static method with %r as first argument',
-              'Used when a static method has "self" or "cls" as first argument.'
-              ),
-    'R0201': ('Method could be a function',
-              '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',
-              'Used when a class claims to implement an interface which is not \
-              a class.'),
-    'E0222': ('Missing method %r from %s interface',
-              'Used when a method declared in an interface is missing from a \
-              class implementing this interface'),
-    'W0221': ('Arguments number differs from %s method',
-              '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',
-              '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',
-              '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
-              'Used when a PyLint as failed to find interfaces implemented by \
-               a class'),
-
-
-    'W0231': ('__init__ method from base class %r is 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',
-              'Used when a class has no __init__ method, neither its parent \
-              classes.'),
-    'W0233': ('__init__ method from a non direct base class %r is called',
-              'Used when an __init__ method is called on a class which is not \
-              in the direct ancestors for the analysed class.'),
-
-    }
-
-
-class ClassChecker(BaseChecker):
-    """checks for :
-    * methods without self as first argument
-    * overridden methods signature
-    * access only to existent members via self
-    * attributes not defined in the __init__ method
-    * supported interfaces implementation
-    * unreachable code
-    """
-
-    __implements__ = (IASTNGChecker,)
-
-    # configuration section name
-    name = 'classes'
-    # messages
-    msgs = MSGS
-    priority = -2
-    # configuration options
-    options = (('ignore-iface-methods',
-                {'default' : (#zope interface
-        'isImplementedBy', 'deferred', 'extends', 'names',
-        'namesAndDescriptions', 'queryDescriptionFor',  'getBases',
-        'getDescriptionFor', 'getDoc', 'getName', 'getTaggedValue',
-        'getTaggedValueTags', 'isEqualOrExtendedBy', 'setTaggedValue',
-        'isImplementedByInstancesOf',
-        # twisted
-        'adaptWith',
-        # logilab.common interface
-        'is_implemented_by'),
-                 'type' : 'csv',
-                 'metavar' : '<method names>',
-                 'help' : 'List of interface methods to ignore, \
-separated by a comma. This is used for instance to not check methods defines \
-in Zope\'s Interface base class.'}
-                ),
-
-               ('defining-attr-methods',
-                {'default' : ('__init__', '__new__', 'setUp'),
-                 'type' : 'csv',
-                 'metavar' : '<method names>',
-                 'help' : 'List of method names used to declare (i.e. assign) \
-instance attributes.'}
-                ),
-               ('valid-classmethod-first-arg',
-                {'default' : ('cls',),
-                 'type' : 'csv',
-                 'metavar' : '<argument names>',
-                 'help' : 'List of valid names for the first argument in \
-a class method.'}
-                ),
-
-               )
-
-    def __init__(self, linter=None):
-        BaseChecker.__init__(self, linter)
-        self._accessed = []
-        self._first_attrs = []
-        self._meth_could_be_func = None
-
-    def visit_class(self, node):
-        """init visit variable _accessed and check interfaces
-        """
-        self._accessed.append({})
-        self._check_bases_classes(node)
-        self._check_interfaces(node)
-        # if not an interface, exception, metaclass
-        if node.type == 'class':
-            try:
-                node.local_attr('__init__')
-            except astng.NotFoundError:
-                self.add_message('W0232', args=node, node=node)
-
-    @check_messages('E0203', 'W0201')
-    def leave_class(self, cnode):
-        """close a class node:
-        check that instance attributes are defined in __init__ and check
-        access to existent members
-        """
-        # check access to existent members on non metaclass classes
-        accessed = self._accessed.pop()
-        if cnode.type != 'metaclass':
-            self._check_accessed_members(cnode, accessed)
-        # checks attributes are defined in an allowed method such as __init__
-        if 'W0201' not in self.active_msgs:
-            return
-        defining_methods = self.config.defining_attr_methods
-        for attr, nodes in cnode.instance_attrs.items():
-            nodes = [n for n in nodes if not
-                    isinstance(n.statement(), (astng.Delete, astng.AugAssign))]
-            if not nodes:
-                continue # error detected by typechecking
-            attr_defined = False
-            # check if any method attr is defined in is a defining method
-            for node in nodes:
-                if node.frame().name in defining_methods:
-                    attr_defined = True
-            if not attr_defined:
-                # check attribute is defined in a parent's __init__
-                for parent in cnode.instance_attr_ancestors(attr):
-                    attr_defined = False
-                    # check if any parent method attr is defined in is a defining method
-                    for node in parent.instance_attrs[attr]:
-                        if node.frame().name in defining_methods:
-                            attr_defined = True
-                    if attr_defined:
-                        # we're done :)
-                        break
-                else:
-                    # check attribute is defined as a class attribute
-                    try:
-                        cnode.local_attr(attr)
-                    except astng.NotFoundError:
-                        self.add_message('W0201', args=attr, node=node)
-
-    def visit_function(self, node):
-        """check method arguments, overriding"""
-        # ignore actual functions
-        if not node.is_method():
-            return
-        klass = node.parent.frame()
-        self._meth_could_be_func = True
-        # check first argument is self if this is actually a method
-        self._check_first_arg_for_type(node, klass.type == 'metaclass')
-        if node.name == '__init__':
-            self._check_init(node)
-            return
-        # check signature if the method overloads inherited method
-        for overridden in klass.local_attr_ancestors(node.name):
-            # get astng for the searched method
-            try:
-                meth_node = overridden[node.name]
-            except KeyError:
-                # we have found the method but it's not in the local
-                # dictionary.
-                # This may happen with astng build from living objects
-                continue
-            if not isinstance(meth_node, astng.Function):
-                continue
-            self._check_signature(node, meth_node, 'overridden')
-            break
-        if node.decorators:
-            for decorator in node.decorators.nodes:
-                if isinstance(decorator, astng.Getattr) and \
-                        decorator.attrname in ('getter', 'setter', 'deleter'):
-                    # attribute affectation will call this method, not hiding it
-                    return
-                if isinstance(decorator, astng.Name) and decorator.name == 'property':
-                    # attribute affectation will either call a setter or raise
-                    # an attribute error, anyway not hiding the function
-                    return
-        # check if the method is hidden by an attribute
-        try:
-            overridden = klass.instance_attr(node.name)[0] # XXX
-            args = (overridden.root().name, overridden.fromlineno)
-            self.add_message('E0202', args=args, node=node)
-        except astng.NotFoundError:
-            pass
-
-    def leave_function(self, node):
-        """on method node, check if this method couldn't be a function
-
-        ignore class, static and abstract methods, initializer,
-        methods overridden from a parent class and any
-        kind of method defined in an interface for this warning
-        """
-        if node.is_method():
-            if node.args.args is not None:
-                self._first_attrs.pop()
-            if 'R0201' not in self.active_msgs:
-                return
-            class_node = node.parent.frame()
-            if (self._meth_could_be_func and node.type == 'method'
-                and not node.name in PYMETHODS
-                and not (node.is_abstract() or
-                         overrides_a_method(class_node, node.name))
-                and class_node.type != 'interface'):
-                self.add_message('R0201', node=node)
-
-    def visit_getattr(self, node):
-        """check if the getattr is an access to a class member
-        if so, register it. Also check for access to protected
-        class member from outside its class (but ignore __special__
-        methods)
-        """
-        attrname = node.attrname
-        # Check self
-        if self.is_first_attr(node):
-            self._accessed[-1].setdefault(attrname, []).append(node)
-            return
-        if 'W0212' not in self.active_msgs:
-            return
-
-        self._check_protected_attribute_access(node)
-
-    def visit_assign(self, assign_node):
-        if 'W0212' not in self.active_msgs:
-            return
-
-        node = assign_node.targets[0]
-        if not isinstance(node, AssAttr):
-            return
-
-        if self.is_first_attr(node):
-            return
-
-        self._check_protected_attribute_access(node)
-
-    def _check_protected_attribute_access(self, node):
-        '''Given an attribute access node (set or get), check if attribute
-        access is legitimate. Call _check_first_attr with node before calling
-        this method. Valid cases are:
-        * self._attr in a method or cls._attr in a classmethod. Checked by
-        _check_first_attr.
-        * Klass._attr inside "Klass" class.
-        * Klass2._attr inside "Klass" class when Klass2 is a base class of
-            Klass.
-        '''
-        attrname = node.attrname
-
-        if is_attr_protected(attrname):
-
-            klass = node_frame_class(node)
-
-            # XXX infer to be more safe and less dirty ??
-            # in classes, check we are not getting a parent method
-            # through the class object or through super
-            callee = node.expr.as_string()
-
-            # We are not in a class, no remaining valid case
-            if klass is None:
-                self.add_message('W0212', node=node, args=attrname)
-                return
-
-            # We are in a class, one remaining valid cases, Klass._attr inside
-            # Klass
-            if not (callee == klass.name or callee in klass.basenames):
-
-                self.add_message('W0212', node=node, args=attrname)
-
-    def visit_name(self, node):
-        """check if the name handle an access to a class member
-        if so, register it
-        """
-        if self._first_attrs and (node.name == self._first_attrs[-1] or
-                                  not self._first_attrs[-1]):
-            self._meth_could_be_func = False
-
-    def _check_accessed_members(self, node, accessed):
-        """check that accessed members are defined"""
-        # XXX refactor, probably much simpler now that E0201 is in type checker
-        for attr, nodes in accessed.items():
-            # deactivate "except doesn't do anything", that's expected
-            # pylint: disable=W0704
-            # is it a class attribute ?
-            try:
-                node.local_attr(attr)
-                # yes, stop here
-                continue
-            except astng.NotFoundError:
-                pass
-            # is it an instance attribute of a parent class ?
-            try:
-                node.instance_attr_ancestors(attr).next()
-                # yes, stop here
-                continue
-            except StopIteration:
-                pass
-            # is it an instance attribute ?
-            try:
-                defstmts = node.instance_attr(attr)
-            except astng.NotFoundError:
-                pass
-            else:
-                if len(defstmts) == 1:
-                    defstmt = defstmts[0]
-                    # check that if the node is accessed in the same method as
-                    # it's defined, it's accessed after the initial assignment
-                    frame = defstmt.frame()
-                    lno = defstmt.fromlineno
-                    for _node in nodes:
-                        if _node.frame() is frame and _node.fromlineno < lno \
-                           and not are_exclusive(_node.statement(), defstmt, ('AttributeError', 'Exception', 'BaseException')):
-                            self.add_message('E0203', node=_node,
-                                             args=(attr, lno))
-
-    def _check_first_arg_for_type(self, node, metaclass=0):
-        """check the name of first argument, expect:
-
-        * 'self' for a regular method
-        * 'cls' for a class method
-        * 'mcs' for a metaclass
-        * not one of the above for a static method
-        """
-        # don't care about functions with unknown argument (builtins)
-        if node.args.args is None:
-            return
-        first_arg = node.args.args and node.argnames()[0]
-        self._first_attrs.append(first_arg)
-        first = self._first_attrs[-1]
-        # static method
-        if node.type == 'staticmethod':
-            if first_arg in ('self', 'cls', 'mcs'):
-                self.add_message('W0211', args=first, node=node)
-            self._first_attrs[-1] = None
-        # class / regular method with no args
-        elif not node.args.args:
-            self.add_message('E0211', node=node)
-        # metaclass method
-        elif metaclass:
-            if first != 'mcs':
-                self.add_message('C0203', node=node)
-        # class method
-        elif node.type == 'classmethod':
-            if first not in self.config.valid_classmethod_first_arg:
-                if len(self.config.valid_classmethod_first_arg) == 1:
-                    valid = repr(self.config.valid_classmethod_first_arg[0])
-                else:
-                    valid = ', '.join(
-                      repr(v)
-                      for v in self.config.valid_classmethod_first_arg[:-1])
-                    valid = '%s or %r' % (
-                        valid, self.config.valid_classmethod_first_arg[-1])
-                self.add_message('C0202', args=valid, node=node)
-        # regular method without self as argument
-        elif first != 'self':
-            self.add_message('E0213', node=node)
-
-    def _check_bases_classes(self, node):
-        """check that the given class node implements abstract methods from
-        base classes
-        """
-        # check if this class abstract
-        if class_is_abstract(node):
-            return
-        for method in node.methods():
-            owner = method.parent.frame()
-            if owner is node:
-                continue
-            # owner is not this class, it must be a parent class
-            # check that the ancestor's method is not abstract
-            if method.is_abstract(pass_is_abstract=False):
-                self.add_message('W0223', node=node,
-                                 args=(method.name, owner.name))
-
-    def _check_interfaces(self, node):
-        """check that the given class node really implements declared
-        interfaces
-        """
-        e0221_hack = [False]
-        def iface_handler(obj):
-            """filter interface objects, it should be classes"""
-            if not isinstance(obj, astng.Class):
-                e0221_hack[0] = True
-                self.add_message('E0221', node=node,
-                                 args=(obj.as_string(),))
-                return False
-            return True
-        ignore_iface_methods = self.config.ignore_iface_methods
-        try:
-            for iface in node.interfaces(handler_func=iface_handler):
-                for imethod in iface.methods():
-                    name = imethod.name
-                    if name.startswith('_') or name in ignore_iface_methods:
-                        # don't check method beginning with an underscore,
-                        # usually belonging to the interface implementation
-                        continue
-                    # get class method astng
-                    try:
-                        method = node_method(node, name)
-                    except astng.NotFoundError:
-                        self.add_message('E0222', args=(name, iface.name),
-                                         node=node)
-                        continue
-                    # ignore inherited methods
-                    if method.parent.frame() is not node:
-                        continue
-                    # check signature
-                    self._check_signature(method, imethod,
-                                         '%s interface' % iface.name)
-        except astng.InferenceError:
-            if e0221_hack[0]:
-                return
-            implements = Instance(node).getattr('__implements__')[0]
-            assignment = implements.parent
-            assert isinstance(assignment, astng.Assign)
-            # assignment.expr can be a Name or a Tuple or whatever.
-            # Use as_string() for the message
-            # FIXME: in case of multiple interfaces, find which one could not
-            #        be resolved
-            self.add_message('F0220', node=implements,
-                             args=(node.name, assignment.value.as_string()))
-
-    def _check_init(self, node):
-        """check that the __init__ method call super or ancestors'__init__
-        method
-        """
-        if not set(('W0231', 'W0233')) & self.active_msgs:
-            return
-        klass_node = node.parent.frame()
-        to_call = _ancestors_to_call(klass_node)
-        not_called_yet = dict(to_call)
-        for stmt in node.nodes_of_class(astng.CallFunc):
-            expr = stmt.func
-            if not isinstance(expr, astng.Getattr) \
-                   or expr.attrname != '__init__':
-                continue
-            # skip the test if using super
-            if isinstance(expr.expr, astng.CallFunc) and \
-               isinstance(expr.expr.func, astng.Name) and \
-               expr.expr.func.name == 'super':
-                return
-            try:
-                klass = expr.expr.infer().next()
-                if klass is YES:
-                    continue
-                try:
-                    del not_called_yet[klass]
-                except KeyError:
-                    if klass not in to_call:
-                        self.add_message('W0233', node=expr, args=klass.name)
-            except astng.InferenceError:
-                continue
-        for klass, method in not_called_yet.items():
-            if klass.name == 'object' or method.parent.name == 'object':
-                continue
-            self.add_message('W0231', args=klass.name, node=node)
-
-    def _check_signature(self, method1, refmethod, class_type):
-        """check that the signature of the two given methods match
-
-        class_type is in 'class', 'interface'
-        """
-        if not (isinstance(method1, astng.Function)
-                and isinstance(refmethod, astng.Function)):
-            self.add_message('F0202', args=(method1, refmethod), node=method1)
-            return
-        # don't care about functions with unknown argument (builtins)
-        if method1.args.args is None or refmethod.args.args is None:
-            return
-        # if we use *args, **kwargs, skip the below checks
-        if method1.args.vararg or method1.args.kwarg:
-            return
-        if is_attr_private(method1.name):
-            return
-        if len(method1.args.args) != len(refmethod.args.args):
-            self.add_message('W0221', args=class_type, node=method1)
-        elif len(method1.args.defaults) < len(refmethod.args.defaults):
-            self.add_message('W0222', args=class_type, node=method1)
-
-    def is_first_attr(self, node):
-        """Check that attribute lookup name use first attribute variable name
-        (self for method, cls for classmethod and mcs for metaclass).
-        """
-        return self._first_attrs and isinstance(node.expr, astng.Name) and \
-                   node.expr.name == self._first_attrs[-1]
-
-def _ancestors_to_call(klass_node, method='__init__'):
-    """return a dictionary where keys are the list of base classes providing
-    the queried method, and so that should/may be called from the method node
-    """
-    to_call = {}
-    for base_node in klass_node.ancestors(recurs=False):
-        try:
-            to_call[base_node] = base_node.local_attr(method)[-1]
-        except astng.NotFoundError:
-            continue
-    return to_call
-
-
-def node_method(node, method_name):
-    """get astng for <method_name> on the given class node, ensuring it
-    is a Function node
-    """
-    for n in node.local_attr(method_name):
-        if isinstance(n, astng.Function):
-            return n
-    raise astng.NotFoundError(method_name)
-
-def register(linter):
-    """required method to auto register this checker """
-    linter.register_checker(ClassChecker(linter))

checkers/design_analysis.py

-# Copyright (c) 2003-2006 LOGILAB S.A. (Paris, FRANCE).
-# http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-"""check for signs of poor design
-
-
- see http://intranet.logilab.fr/jpl/view?rql=Any%20X%20where%20X%20eid%201243
- FIXME: missing 13, 15, 16
-"""
-
-from logilab.astng import Function, If, InferenceError
-
-from pylint.interfaces import IASTNGChecker
-from pylint.checkers import BaseChecker
-
-import re
-
-# regexp for ignored argument name
-IGNORED_ARGUMENT_NAMES = re.compile('_.*')
-
-def class_is_abstract(klass):
-    """return true if the given class node should be considered as an abstract
-    class
-    """
-    for attr in klass.values():
-        if isinstance(attr, Function):
-            if attr.is_abstract(pass_is_abstract=False):
-                return True
-    return False
-
-
-MSGS = {
-    'R0901': ('Too many ancestors (%s/%s)',
-              '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)',
-              '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)',
-              'Used when class has too few public methods, so be sure it\'s \
-              really worth it.'),
-    'R0904': ('Too many public methods (%s/%s)',
-              '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)',
-              'Used when a function or method has too many return statement, \
-              making it hard to follow.'),
-    'R0912': ('Too many branches (%s/%s)',
-              'Used when a function or method has too many branches, \
-              making it hard to follow.'),
-    'R0913': ('Too many arguments (%s/%s)',
-              'Used when a function or method takes too many arguments.'),
-    'R0914': ('Too many local variables (%s/%s)',
-              'Used when a function or method has too many local variables.'),
-    'R0915': ('Too many statements (%s/%s)',
-              'Used when a function or method has too many statements. You \
-              should then split it in smaller functions / methods.'),
-    
-    'R0921': ('Abstract class not referenced',
-              'Used when an abstract class is not used as ancestor anywhere.'),
-    'R0922': ('Abstract class is only referenced %s times',
-              'Used when an abstract class is used less than X times as \
-              ancestor.'),
-    'R0923': ('Interface not implemented',
-              'Used when an interface class is not implemented anywhere.'),
-    }
-
-
-class MisdesignChecker(BaseChecker):
-    """checks for sign of poor/misdesign:                                      
-    * number of methods, attributes, local variables...                        
-    * size, complexity of functions, methods                                   
-    """
-    
-    __implements__ = (IASTNGChecker,)
-
-    # configuration section name
-    name = 'design'
-    # messages
-    msgs = MSGS
-    priority = -2
-    # configuration options
-    options = (('max-args',
-                {'default' : 5, 'type' : 'int', 'metavar' : '<int>',
-                 'help': 'Maximum number of arguments for function / method'}
-                ),
-               ('ignored-argument-names',
-                {'default' : IGNORED_ARGUMENT_NAMES,
-                 'type' :'regexp', 'metavar' : '<regexp>',
-                 'help' : 'Argument names that match this expression will be '
-                          'ignored. Default to name with leading underscore'}
-                ),
-               ('max-locals',
-                {'default' : 15, 'type' : 'int', 'metavar' : '<int>',
-                 'help': 'Maximum number of locals for function / method body'}
-                ),
-               ('max-returns',
-                {'default' : 6, 'type' : 'int', 'metavar' : '<int>',
-                 'help': 'Maximum number of return / yield for function / '
-                         'method body'}
-                ),
-               ('max-branchs',
-                {'default' : 12, 'type' : 'int', 'metavar' : '<int>',
-                 'help': 'Maximum number of branch for function / method body'}
-                ),
-               ('max-statements',
-                {'default' : 50, 'type' : 'int', 'metavar' : '<int>',
-                 'help': 'Maximum number of statements in function / method '
-                         'body'}
-                ),
-               ('max-parents',
-                {'default' : 7,
-                 'type' : 'int',
-                 'metavar' : '<num>',
-                 'help' : 'Maximum number of parents for a class (see R0901).'}
-                ),
-               ('max-attributes',
-                {'default' : 7,
-                 'type' : 'int',
-                 'metavar' : '<num>',
-                 'help' : 'Maximum number of attributes for a class \
-(see R0902).'}
-                ),
-               ('min-public-methods',
-                {'default' : 2,
-                 'type' : 'int',
-                 'metavar' : '<num>',
-                 'help' : 'Minimum number of public methods for a class \
-(see R0903).'}
-                ),
-               ('max-public-methods',
-                {'default' : 20,
-                 'type' : 'int',
-                 'metavar' : '<num>',
-                 'help' : 'Maximum number of public methods for a class \
-(see R0904).'}
-                ),
-               )
-
-    def __init__(self, linter=None):
-        BaseChecker.__init__(self, linter)
-        self.stats = None
-        self._returns = None
-        self._branchs = None
-        self._used_abstracts = None
-        self._used_ifaces = None
-        self._abstracts = None
-        self._ifaces = None
-        self._stmts = 0
-        
-    def open(self):
-        """initialize visit variables"""
-        self.stats = self.linter.add_stats()
-        self._returns = []
-        self._branchs = []
-        self._used_abstracts = {}
-        self._used_ifaces = {}
-        self._abstracts = []
-        self._ifaces = []
-
-    def close(self):
-        """check that abstract/interface classes are used"""
-        for abstract in self._abstracts:
-            if not abstract in self._used_abstracts:
-                self.add_message('R0921', node=abstract)
-            elif self._used_abstracts[abstract] < 2:
-                self.add_message('R0922', node=abstract,
-                                 args=self._used_abstracts[abstract])
-        for iface in self._ifaces:
-            if not iface in self._used_ifaces:
-                self.add_message('R0923', node=iface)
-                
-    def visit_class(self, node):
-        """check size of inheritance hierarchy and number of instance attributes
-        """
-        self._inc_branch()
-        # Is the total inheritance hierarchy is 7 or less?
-        nb_parents = len(list(node.ancestors()))
-        if nb_parents > self.config.max_parents:
-            self.add_message('R0901', node=node,
-                             args=(nb_parents, self.config.max_parents))
-        # Does the class contain less than 20 attributes for
-        # non-GUI classes (40 for GUI)?
-        # FIXME detect gui classes
-        if len(node.instance_attrs) > self.config.max_attributes:
-            self.add_message('R0902', node=node,
-                             args=(len(node.instance_attrs),
-                                   self.config.max_attributes))
-        # update abstract / interface classes structures
-        if class_is_abstract(node):
-            self._abstracts.append(node)
-        elif node.type == 'interface' and node.name != 'Interface':
-            self._ifaces.append(node)
-            for parent in node.ancestors(False):
-                if parent.name == 'Interface':
-                    continue
-                self._used_ifaces[parent] = 1
-        try:
-            for iface in node.interfaces():
-                self._used_ifaces[iface] = 1
-        except InferenceError:
-            # XXX log ? 
-            pass
-        for parent in node.ancestors():
-            try:
-                self._used_abstracts[parent] += 1
-            except KeyError:
-                self._used_abstracts[parent] = 1
-            
-    def leave_class(self, node):
-        """check number of public methods"""
-        nb_public_methods = 0
-        for method in node.methods():
-            if not method.name.startswith('_'):
-                nb_public_methods += 1
-        # Does the class contain less than 20 public methods ?
-        if nb_public_methods > self.config.max_public_methods:
-            self.add_message('R0904', node=node,
-                             args=(nb_public_methods,
-                                   self.config.max_public_methods))
-        # stop here for exception, metaclass and interface classes
-        if node.type != 'class':
-            return
-        # Does the class contain more than 5 public methods ?
-        if nb_public_methods < self.config.min_public_methods:
-            self.add_message('R0903', node=node,
-                             args=(nb_public_methods,
-                                   self.config.min_public_methods))
-
-        
-    def visit_function(self, node):
-        """check function name, docstring, arguments, redefinition,
-        variable names, max locals
-        """
-        self._inc_branch()
-        # init branch and returns counters
-        self._returns.append(0)
-        self._branchs.append(0)
-        # check number of arguments
-        args = node.args.args
-        if args is not None:
-            ignored_args_num = len(
-                [arg for arg in args
-                 if self.config.ignored_argument_names.match(arg.name)])
-            argnum = len(args) - ignored_args_num
-            if  argnum > self.config.max_args:
-                self.add_message('R0913', node=node,
-                                 args=(len(args), self.config.max_args))
-        else:
-            ignored_args_num = 0
-        # check number of local variables
-        locnum = len(node.locals) - ignored_args_num
-        if locnum > self.config.max_locals:
-            self.add_message('R0914', node=node,
-                             args=(locnum, self.config.max_locals))
-        # init statements counter
-        self._stmts = 1
-
-    def leave_function(self, node):
-        """most of the work is done here on close:
-        checks for max returns, branch, return in __init__
-        """
-        returns = self._returns.pop()
-        if returns > self.config.max_returns:
-            self.add_message('R0911', node=node,
-                             args=(returns, self.config.max_returns))
-        branchs = self._branchs.pop()
-        if branchs > self.config.max_branchs:
-            self.add_message('R0912', node=node,
-                             args=(branchs, self.config.max_branchs))
-        # check number of statements
-        if self._stmts > self.config.max_statements:
-            self.add_message('R0915', node=node,
-                             args=(self._stmts, self.config.max_statements))
-
-    def visit_return(self, _):
-        """count number of returns"""
-        if not self._returns:
-            return # return outside function, reported by the base checker
-        self._returns[-1] += 1
-        
-    def visit_default(self, node):
-        """default visit method -> increments the statements counter if
-        necessary
-        """
-        if node.is_statement:
-            self._stmts += 1
-
-    def visit_tryexcept(self, node):
-        """increments the branchs counter"""
-        branchs = len(node.handlers)
-        if node.orelse:
-            branchs += 1
-        self._inc_branch(branchs)
-        self._stmts += branchs
-        
-    def visit_tryfinally(self, _):
-        """increments the branchs counter"""
-        self._inc_branch(2)
-        self._stmts += 2
-        
-    def visit_if(self, node):
-        """increments the branchs counter"""
-        branchs = 1
-        # don't double count If nodes coming from some 'elif'
-        if node.orelse and (len(node.orelse)>1 or
-                            not isinstance(node.orelse[0], If)):
-            branchs += 1
-        self._inc_branch(branchs)
-        self._stmts += branchs
-        
-    def visit_while(self, node):
-        """increments the branchs counter"""
-        branchs = 1
-        if node.orelse:
-            branchs += 1
-        self._inc_branch(branchs)
-        
-    visit_for = visit_while
-
-    def _inc_branch(self, branchsnum=1):
-        """increments the branchs counter"""
-        branchs = self._branchs
-        for i in xrange(len(branchs)):
-            branchs[i] += branchsnum
-
-    # FIXME: make a nice report...
-
-def register(linter):
-    """required method to auto register this checker """
-    linter.register_checker(MisdesignChecker(linter))

checkers/exceptions.py

-# Copyright (c) 2003-2007 LOGILAB S.A. (Paris, FRANCE).
-# http://www.logilab.fr/ -- mailto:contact@logilab.fr
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-"""exceptions handling (raising, catching, exceptions classes) checker
-"""
-import sys
-
-from logilab.common.compat import builtins
-BUILTINS_NAME = builtins.__name__
-from logilab import astng
-from logilab.astng import YES, Instance, unpack_infer
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import is_empty, is_raising
-from pylint.interfaces import IASTNGChecker
-
-
-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.'),
-    'E0702': ('Raising %s while only classes, instances or string are allowed',
-              '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',
-              'Used when a new style class which doesn\'t inherit from \
-               BaseException is raised.'),
-    'E0711': ('NotImplemented raised - should raise NotImplementedError',
-              'Used when NotImplemented is raised instead of \
-              NotImplementedError'),
-    
-    'W0701': ('Raising a string exception',
-              'Used when a string exception is raised.'),
-    'W0702': ('No exception type(s) specified',
-              'Used when an except clause doesn\'t specify exceptions type to \
-              catch.'),
-    'W0703': ('Catching too general exception %s',
-              'Used when an except catches a too general exception, \
-              possibly burying unrelated errors.'),
-    'W0704': ('Except doesn\'t do anything',
-              'Used when an except clause does nothing but "pass" and there is\
-              no "else" clause.'),
-    'W0710': ('Exception doesn\'t inherit from standard "Exception" class',
-              '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',
-              'Used when the exception to catch is of the form \
-              "except A or B:".  If intending to catch multiple, \
-              rewrite as "except (A, B):"'),
-    }
-
-
-if sys.version_info < (3, 0):
-    EXCEPTIONS_MODULE = "exceptions"
-else:
-    EXCEPTIONS_MODULE = "builtins"
-
-class ExceptionsChecker(BaseChecker):
-    """checks for                                                              
-    * excepts without exception filter                                         
-    * type of raise argument : string, Exceptions, other values
-    """
-    
-    __implements__ = IASTNGChecker
-
-    name = 'exceptions'
-    msgs = MSGS
-    priority = -4
-    options = (('overgeneral-exceptions',
-                {'default' : OVERGENERAL_EXCEPTIONS,
-                 'type' :'csv', 'metavar' : '<comma-separated class names>',
-                 'help' : 'Exceptions that will emit a warning '
-                          'when being caught. Defaults to "%s"' % (
-                              ', '.join(OVERGENERAL_EXCEPTIONS),)}
-                ),
-               )
-
-    def visit_raise(self, node):
-        """visit raise possibly inferring value"""
-        # ignore empty raise
-        if node.exc is None:
-            return
-        expr = node.exc
-        if self._check_raise_value(node, expr):
-            return
-        else:
-            try:
-                value = unpack_infer(expr).next()
-            except astng.InferenceError:
-                return
-            self._check_raise_value(node, value)
-
-    def _check_raise_value(self, node, expr):
-        """check for bad values, string exception and class inheritance
-        """
-        value_found = True
-        if isinstance(expr, astng.Const):
-            value = expr.value
-            if isinstance(value, str):
-                self.add_message('W0701', node=node)
-            else:
-                self.add_message('E0702', node=node,
-                                 args=value.__class__.__name__)
-        elif (isinstance(expr, astng.Name) and \
-                 expr.name in ('None', 'True', 'False')) or \
-                 isinstance(expr, (astng.List, astng.Dict, astng.Tuple, 
-                                   astng.Module, astng.Function)):
-            self.add_message('E0702', node=node, args=expr.name)
-        elif ( (isinstance(expr, astng.Name) and expr.name == 'NotImplemented')
-               or (isinstance(expr, astng.CallFunc) and
-                   isinstance(expr.func, astng.Name) and
-                   expr.func.name == 'NotImplemented') ):
-            self.add_message('E0711', node=node)
-        elif isinstance(expr, astng.BinOp) and expr.op == '%':
-            self.add_message('W0701', node=node)
-        elif isinstance(expr, (Instance, astng.Class)):
-            if isinstance(expr, Instance):
-                expr = expr._proxied
-            if (isinstance(expr, astng.Class) and
-                    not inherit_from_std_ex(expr) and
-                    expr.root().name != BUILTINS_NAME):
-                if expr.newstyle:
-                    self.add_message('E0710', node=node)
-                else:
-                    self.add_message('W0710', node=node)
-            else:
-                value_found = False
-        else:
-            value_found = False
-        return value_found
-
-
-    def visit_tryexcept(self, node):
-        """check for empty except"""
-        exceptions_classes = []
-        nb_handlers = len(node.handlers)
-        for index, handler  in enumerate(node.handlers):
-            # single except doing nothing but "pass" without else clause
-            if nb_handlers == 1 and is_empty(handler.body) and not node.orelse:
-                self.add_message('W0704', node=handler.type or handler.body[0])
-            if handler.type is None:
-                if nb_handlers == 1 and not is_raising(handler.body):
-                    self.add_message('W0702', node=handler)
-                # check if a "except:" is followed by some other
-                # except
-                elif index < (nb_handlers - 1):
-                    msg = 'empty except clause should always appear last'
-                    self.add_message('E0701', node=node, args=msg)
-
-            elif isinstance(handler.type, astng.BoolOp):
-                self.add_message('W0711', node=handler, args=handler.type.op)
-            else:
-                try:
-                    excs = list(unpack_infer(handler.type))
-                except astng.InferenceError:
-                    continue
-                for exc in excs:
-                    # XXX skip other non class nodes 
-                    if exc is YES or not isinstance(exc, astng.Class):
-                        continue
-                    exc_ancestors = [anc for anc in exc.ancestors()
-                                     if isinstance(anc, astng.Class)]