| OLD | NEW | 
|     1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). |     1 # Copyright (c) 2003-2010 LOGILAB S.A. (Paris, FRANCE). | 
 |     2 # Copyright (c) 2009-2010 Arista Networks, Inc. | 
|     2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr |     3 # http://www.logilab.fr/ -- mailto:contact@logilab.fr | 
|     3 # Copyright (c) 2009-2010 Arista Networks, Inc. |  | 
|     4 # |  | 
|     5 # This program is free software; you can redistribute it and/or modify it under |     4 # This program is free software; you can redistribute it and/or modify it under | 
|     6 # the terms of the GNU General Public License as published by the Free Software |     5 # the terms of the GNU General Public License as published by the Free Software | 
|     7 # Foundation; either version 2 of the License, or (at your option) any later |     6 # Foundation; either version 2 of the License, or (at your option) any later | 
|     8 # version. |     7 # version. | 
|     9 # |     8 # | 
|    10 # This program is distributed in the hope that it will be useful, but WITHOUT |     9 # This program is distributed in the hope that it will be useful, but WITHOUT | 
|    11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |    10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
|    12 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |    11 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | 
|    13 # |    12 # | 
|    14 # You should have received a copy of the GNU General Public License along with |    13 # You should have received a copy of the GNU General Public License along with | 
|    15 # this program; if not, write to the Free Software Foundation, Inc., |    14 # this program; if not, write to the Free Software Foundation, Inc., | 
|    16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |    15 # 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. | 
|    17 """basic checker for Python code""" |    16 """basic checker for Python code""" | 
|    18  |    17  | 
|    19 import sys |    18  | 
|    20 import astroid |    19 from logilab import astng | 
|    21 from logilab.common.ureports import Table |    20 from logilab.common.ureports import Table | 
|    22 from astroid import are_exclusive, InferenceError |    21 from logilab.astng import are_exclusive | 
|    23 import astroid.bases |  | 
|    24  |    22  | 
|    25 from pylint.interfaces import IAstroidChecker |    23 from pylint.interfaces import IASTNGChecker | 
|    26 from pylint.utils import EmptyReport |  | 
|    27 from pylint.reporters import diff_string |    24 from pylint.reporters import diff_string | 
|    28 from pylint.checkers import BaseChecker |    25 from pylint.checkers import BaseChecker, EmptyReport | 
|    29 from pylint.checkers.utils import ( |    26 from pylint.checkers.utils import check_messages, clobber_in_except, is_inside_e
      xcept | 
|    30     check_messages, |  | 
|    31     clobber_in_except, |  | 
|    32     is_builtin_object, |  | 
|    33     is_inside_except, |  | 
|    34     overrides_a_method, |  | 
|    35     safe_infer, |  | 
|    36     get_argument_from_call, |  | 
|    37     NoSuchArgumentError, |  | 
|    38     ) |  | 
|    39  |    27  | 
|    40  |    28  | 
|    41 import re |    29 import re | 
|    42  |    30  | 
|    43 # regex for class/function/variable/constant name |    31 # regex for class/function/variable/constant name | 
|    44 CLASS_NAME_RGX = re.compile('[A-Z_][a-zA-Z0-9]+$') |    32 CLASS_NAME_RGX = re.compile('[A-Z_][a-zA-Z0-9]+$') | 
|    45 MOD_NAME_RGX = re.compile('(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$') |    33 MOD_NAME_RGX = re.compile('(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$') | 
|    46 CONST_NAME_RGX = re.compile('(([A-Z_][A-Z0-9_]*)|(__.*__))$') |    34 CONST_NAME_RGX = re.compile('(([A-Z_][A-Z0-9_]*)|(__.*__))$') | 
|    47 COMP_VAR_RGX = re.compile('[A-Za-z_][A-Za-z0-9_]*$') |    35 COMP_VAR_RGX = re.compile('[A-Za-z_][A-Za-z0-9_]*$') | 
|    48 DEFAULT_NAME_RGX = re.compile('[a-z_][a-z0-9_]{2,30}$') |    36 DEFAULT_NAME_RGX = re.compile('[a-z_][a-z0-9_]{2,30}$') | 
|    49 CLASS_ATTRIBUTE_RGX = re.compile(r'([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$') |  | 
|    50 # do not require a doc string on system methods |    37 # do not require a doc string on system methods | 
|    51 NO_REQUIRED_DOC_RGX = re.compile('__.*__') |    38 NO_REQUIRED_DOC_RGX = re.compile('__.*__') | 
|    52 REVERSED_METHODS = (('__getitem__', '__len__'), |  | 
|    53                     ('__reversed__', )) |  | 
|    54  |  | 
|    55 PY33 = sys.version_info >= (3, 3) |  | 
|    56 PY3K = sys.version_info >= (3, 0) |  | 
|    57 BAD_FUNCTIONS = ['map', 'filter', 'apply'] |  | 
|    58 if sys.version_info < (3, 0): |  | 
|    59     BAD_FUNCTIONS.append('input') |  | 
|    60     BAD_FUNCTIONS.append('file') |  | 
|    61  |  | 
|    62 # Name categories that are always consistent with all naming conventions. |  | 
|    63 EXEMPT_NAME_CATEGORIES = set(('exempt', 'ignore')) |  | 
|    64  |    39  | 
|    65 del re |    40 del re | 
|    66  |    41  | 
|    67 def in_loop(node): |    42 def in_loop(node): | 
|    68     """return True if the node is inside a kind of for loop""" |    43     """return True if the node is inside a kind of for loop""" | 
|    69     parent = node.parent |    44     parent = node.parent | 
|    70     while parent is not None: |    45     while parent is not None: | 
|    71         if isinstance(parent, (astroid.For, astroid.ListComp, astroid.SetComp, |    46         if isinstance(parent, (astng.For, astng.ListComp, astng.SetComp, | 
|    72                                astroid.DictComp, astroid.GenExpr)): |    47                                astng.DictComp, astng.GenExpr)): | 
|    73             return True |    48             return True | 
|    74         parent = parent.parent |    49         parent = parent.parent | 
|    75     return False |    50     return False | 
|    76  |    51  | 
|    77 def in_nested_list(nested_list, obj): |    52 def in_nested_list(nested_list, obj): | 
|    78     """return true if the object is an element of <nested_list> or of a nested |    53     """return true if the object is an element of <nested_list> or of a nested | 
|    79     list |    54     list | 
|    80     """ |    55     """ | 
|    81     for elmt in nested_list: |    56     for elmt in nested_list: | 
|    82         if isinstance(elmt, (list, tuple)): |    57         if isinstance(elmt, (list, tuple)): | 
|    83             if in_nested_list(elmt, obj): |    58             if in_nested_list(elmt, obj): | 
|    84                 return True |    59                 return True | 
|    85         elif elmt == obj: |    60         elif elmt == obj: | 
|    86             return True |    61             return True | 
|    87     return False |    62     return False | 
|    88  |    63  | 
|    89 def _loop_exits_early(loop): |  | 
|    90     """Returns true if a loop has a break statement in its body.""" |  | 
|    91     loop_nodes = (astroid.For, astroid.While) |  | 
|    92     # Loop over body explicitly to avoid matching break statements |  | 
|    93     # in orelse. |  | 
|    94     for child in loop.body: |  | 
|    95         if isinstance(child, loop_nodes): |  | 
|    96             # break statement may be in orelse of child loop. |  | 
|    97             for orelse in (child.orelse or ()): |  | 
|    98                 for _ in orelse.nodes_of_class(astroid.Break, skip_klass=loop_no
      des): |  | 
|    99                     return True |  | 
|   100             continue |  | 
|   101         for _ in child.nodes_of_class(astroid.Break, skip_klass=loop_nodes): |  | 
|   102             return True |  | 
|   103     return False |  | 
|   104  |  | 
|   105 if sys.version_info < (3, 0): |  | 
|   106     PROPERTY_CLASSES = set(('__builtin__.property', 'abc.abstractproperty')) |  | 
|   107 else: |  | 
|   108     PROPERTY_CLASSES = set(('builtins.property', 'abc.abstractproperty')) |  | 
|   109 ABC_METHODS = set(('abc.abstractproperty', 'abc.abstractmethod', |  | 
|   110                    'abc.abstractclassmethod', 'abc.abstractstaticmethod')) |  | 
|   111  |  | 
|   112 def _determine_function_name_type(node): |  | 
|   113     """Determine the name type whose regex the a function's name should match. |  | 
|   114  |  | 
|   115     :param node: A function node. |  | 
|   116     :returns: One of ('function', 'method', 'attr') |  | 
|   117     """ |  | 
|   118     if not node.is_method(): |  | 
|   119         return 'function' |  | 
|   120     if node.decorators: |  | 
|   121         decorators = node.decorators.nodes |  | 
|   122     else: |  | 
|   123         decorators = [] |  | 
|   124     for decorator in decorators: |  | 
|   125         # If the function is a property (decorated with @property |  | 
|   126         # or @abc.abstractproperty), the name type is 'attr'. |  | 
|   127         if (isinstance(decorator, astroid.Name) or |  | 
|   128                 (isinstance(decorator, astroid.Getattr) and |  | 
|   129                  decorator.attrname == 'abstractproperty')): |  | 
|   130             infered = safe_infer(decorator) |  | 
|   131             if infered and infered.qname() in PROPERTY_CLASSES: |  | 
|   132                 return 'attr' |  | 
|   133         # If the function is decorated using the prop_method.{setter,getter} |  | 
|   134         # form, treat it like an attribute as well. |  | 
|   135         elif (isinstance(decorator, astroid.Getattr) and |  | 
|   136               decorator.attrname in ('setter', 'deleter')): |  | 
|   137             return 'attr' |  | 
|   138     return 'method' |  | 
|   139  |  | 
|   140 def decorated_with_abc(func): |  | 
|   141     """ Determine if the `func` node is decorated |  | 
|   142     with `abc` decorators (abstractmethod et co.) |  | 
|   143     """ |  | 
|   144     if func.decorators: |  | 
|   145         for node in func.decorators.nodes: |  | 
|   146             try: |  | 
|   147                 infered = node.infer().next() |  | 
|   148             except InferenceError: |  | 
|   149                 continue |  | 
|   150             if infered and infered.qname() in ABC_METHODS: |  | 
|   151                 return True |  | 
|   152  |  | 
|   153 def has_abstract_methods(node): |  | 
|   154     """ Determine if the given `node` has |  | 
|   155     abstract methods, defined with `abc` module. |  | 
|   156     """ |  | 
|   157     return any(decorated_with_abc(meth) |  | 
|   158                for meth in node.mymethods()) |  | 
|   159  |  | 
|   160 def report_by_type_stats(sect, stats, old_stats): |    64 def report_by_type_stats(sect, stats, old_stats): | 
|   161     """make a report of |    65     """make a report of | 
|   162  |    66  | 
|   163     * percentage of different types documented |    67     * percentage of different types documented | 
|   164     * percentage of different types with a bad name |    68     * percentage of different types with a bad name | 
|   165     """ |    69     """ | 
|   166     # percentage of different types documented and/or with a bad name |    70     # percentage of different types documented and/or with a bad name | 
|   167     nice_stats = {} |    71     nice_stats = {} | 
|   168     for node_type in ('module', 'class', 'method', 'function'): |    72     for node_type in ('module', 'class', 'method', 'function'): | 
|   169         try: |    73         try: | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   201     """return True if the object is a method redefined via decorator. |   105     """return True if the object is a method redefined via decorator. | 
|   202  |   106  | 
|   203     For example: |   107     For example: | 
|   204         @property |   108         @property | 
|   205         def x(self): return self._x |   109         def x(self): return self._x | 
|   206         @x.setter |   110         @x.setter | 
|   207         def x(self, value): self._x = value |   111         def x(self, value): self._x = value | 
|   208     """ |   112     """ | 
|   209     if node.decorators: |   113     if node.decorators: | 
|   210         for decorator in node.decorators.nodes: |   114         for decorator in node.decorators.nodes: | 
|   211             if (isinstance(decorator, astroid.Getattr) and |   115             if (isinstance(decorator, astng.Getattr) and | 
|   212                     getattr(decorator.expr, 'name', None) == node.name): |   116                 decorator.expr.name == node.name): | 
|   213                 return True |   117                 return True | 
|   214     return False |   118     return False | 
|   215  |   119  | 
|   216 class _BasicChecker(BaseChecker): |   120 class _BasicChecker(BaseChecker): | 
|   217     __implements__ = IAstroidChecker |   121     __implements__ = IASTNGChecker | 
|   218     name = 'basic' |   122     name = 'basic' | 
|   219  |   123  | 
|   220 class BasicErrorChecker(_BasicChecker): |   124 class BasicErrorChecker(_BasicChecker): | 
|   221     msgs = { |   125     msgs = { | 
|   222         'E0100': ('__init__ method is a generator', |   126     'E0100': ('__init__ method is a generator', | 
|   223                   'init-is-generator', |   127               'Used when the special class method __init__ is turned into a ' | 
|   224                   'Used when the special class method __init__ is turned into a 
      ' |   128               'generator by a yield in its body.'), | 
|   225                   'generator by a yield in its body.'), |   129     'E0101': ('Explicit return in __init__', | 
|   226         'E0101': ('Explicit return in __init__', |   130               'Used when the special class method __init__ has an explicit \ | 
|   227                   'return-in-init', |   131               return value.'), | 
|   228                   'Used when the special class method __init__ has an explicit ' |   132     'E0102': ('%s already defined line %s', | 
|   229                   'return value.'), |   133               'Used when a function / class / method is redefined.'), | 
|   230         'E0102': ('%s already defined line %s', |   134     'E0103': ('%r not properly in loop', | 
|   231                   'function-redefined', |   135               'Used when break or continue keywords are used outside a loop.'), | 
|   232                   'Used when a function / class / method is redefined.'), |  | 
|   233         'E0103': ('%r not properly in loop', |  | 
|   234                   'not-in-loop', |  | 
|   235                   'Used when break or continue keywords are used outside a loop.
      '), |  | 
|   236         'E0104': ('Return outside function', |  | 
|   237                   'return-outside-function', |  | 
|   238                   'Used when a "return" statement is found outside a function or
       ' |  | 
|   239                   'method.'), |  | 
|   240         'E0105': ('Yield outside function', |  | 
|   241                   'yield-outside-function', |  | 
|   242                   'Used when a "yield" statement is found outside a function or 
      ' |  | 
|   243                   'method.'), |  | 
|   244         'E0106': ('Return with argument inside generator', |  | 
|   245                   'return-arg-in-generator', |  | 
|   246                   'Used when a "return" statement with an argument is found ' |  | 
|   247                   'outside in a generator function or method (e.g. with some ' |  | 
|   248                   '"yield" statements).', |  | 
|   249                   {'maxversion': (3, 3)}), |  | 
|   250         'E0107': ("Use of the non-existent %s operator", |  | 
|   251                   'nonexistent-operator', |  | 
|   252                   "Used when you attempt to use the C-style pre-increment or" |  | 
|   253                   "pre-decrement operator -- and ++, which doesn't exist in Pyth
      on."), |  | 
|   254         'E0108': ('Duplicate argument name %s in function definition', |  | 
|   255                   'duplicate-argument-name', |  | 
|   256                   'Duplicate argument names in function definitions are syntax' |  | 
|   257                   ' errors.'), |  | 
|   258         'E0110': ('Abstract class with abstract methods instantiated', |  | 
|   259                   'abstract-class-instantiated', |  | 
|   260                   'Used when an abstract class with `abc.ABCMeta` as metaclass ' |  | 
|   261                   'has abstract methods and is instantiated.', |  | 
|   262                   {'minversion': (3, 0)}), |  | 
|   263         'W0120': ('Else clause on loop without a break statement', |  | 
|   264                   'useless-else-on-loop', |  | 
|   265                   'Loops should only have an else clause if they can exit early 
      ' |  | 
|   266                   'with a break statement, otherwise the statements under else ' |  | 
|   267                   'should be on the same scope as the loop itself.'), |  | 
|   268         } |  | 
|   269  |   136  | 
|   270     @check_messages('function-redefined') |   137     'E0104': ('Return outside function', | 
 |   138               'Used when a "return" statement is found outside a function or ' | 
 |   139               'method.'), | 
 |   140     'E0105': ('Yield outside function', | 
 |   141               'Used when a "yield" statement is found outside a function or ' | 
 |   142               'method.'), | 
 |   143     'E0106': ('Return with argument inside generator', | 
 |   144               'Used when a "return" statement with an argument is found ' | 
 |   145               'outside in a generator function or method (e.g. with some ' | 
 |   146               '"yield" statements).'), | 
 |   147     'E0107': ("Use of the non-existent %s operator", | 
 |   148               "Used when you attempt to use the C-style pre-increment or" | 
 |   149               "pre-decrement operator -- and ++, which doesn't exist in Python."
      ), | 
 |   150     } | 
 |   151  | 
 |   152     def __init__(self, linter): | 
 |   153         _BasicChecker.__init__(self, linter) | 
 |   154  | 
 |   155     @check_messages('E0102') | 
|   271     def visit_class(self, node): |   156     def visit_class(self, node): | 
|   272         self._check_redefinition('class', node) |   157         self._check_redefinition('class', node) | 
|   273  |   158  | 
|   274     @check_messages('init-is-generator', 'return-in-init', |   159     @check_messages('E0100', 'E0101', 'E0102', 'E0106') | 
|   275                     'function-redefined', 'return-arg-in-generator', |  | 
|   276                     'duplicate-argument-name') |  | 
|   277     def visit_function(self, node): |   160     def visit_function(self, node): | 
|   278         if not redefined_by_decorator(node): |   161         if not redefined_by_decorator(node): | 
|   279             self._check_redefinition(node.is_method() and 'method' or 'function'
      , node) |   162             self._check_redefinition(node.is_method() and 'method' or 'function'
      , node) | 
|   280         # checks for max returns, branch, return in __init__ |   163         # checks for max returns, branch, return in __init__ | 
|   281         returns = node.nodes_of_class(astroid.Return, |   164         returns = node.nodes_of_class(astng.Return, | 
|   282                                       skip_klass=(astroid.Function, astroid.Clas
      s)) |   165                                       skip_klass=(astng.Function, astng.Class)) | 
|   283         if node.is_method() and node.name == '__init__': |   166         if node.is_method() and node.name == '__init__': | 
|   284             if node.is_generator(): |   167             if node.is_generator(): | 
|   285                 self.add_message('init-is-generator', node=node) |   168                 self.add_message('E0100', node=node) | 
|   286             else: |   169             else: | 
|   287                 values = [r.value for r in returns] |   170                 values = [r.value for r in returns] | 
|   288                 # Are we returning anything but None from constructors |   171                 if  [v for v in values if not (v is None or | 
|   289                 if [v for v in values |   172                     (isinstance(v, astng.Const) and v.value is None) | 
|   290                         if not (v is None or |   173                     or  (isinstance(v, astng.Name) and v.name == 'None'))]: | 
|   291                                 (isinstance(v, astroid.Const) and v.value is Non
      e) or |   174                     self.add_message('E0101', node=node) | 
|   292                                 (isinstance(v, astroid.Name)  and v.name == 'Non
      e') |  | 
|   293                                )]: |  | 
|   294                     self.add_message('return-in-init', node=node) |  | 
|   295         elif node.is_generator(): |   175         elif node.is_generator(): | 
|   296             # make sure we don't mix non-None returns and yields |   176             # make sure we don't mix non-None returns and yields | 
|   297             if not PY33: |   177             for retnode in returns: | 
|   298                 for retnode in returns: |   178                 if isinstance(retnode.value, astng.Const) and \ | 
|   299                     if isinstance(retnode.value, astroid.Const) and \ |   179                        retnode.value.value is not None: | 
|   300                            retnode.value.value is not None: |   180                     self.add_message('E0106', node=node, | 
|   301                         self.add_message('return-arg-in-generator', node=node, |   181                                      line=retnode.fromlineno) | 
|   302                                          line=retnode.fromlineno) |  | 
|   303         # Check for duplicate names |  | 
|   304         args = set() |  | 
|   305         for name in node.argnames(): |  | 
|   306             if name in args: |  | 
|   307                 self.add_message('duplicate-argument-name', node=node, args=(nam
      e,)) |  | 
|   308             else: |  | 
|   309                 args.add(name) |  | 
|   310  |   182  | 
 |   183     @check_messages('E0104') | 
 |   184     def visit_return(self, node): | 
 |   185         if not isinstance(node.frame(), astng.Function): | 
 |   186             self.add_message('E0104', node=node) | 
|   311  |   187  | 
|   312     @check_messages('return-outside-function') |   188     @check_messages('E0105') | 
|   313     def visit_return(self, node): |   189     def visit_yield(self, node): | 
|   314         if not isinstance(node.frame(), astroid.Function): |   190         if not isinstance(node.frame(), astng.Function): | 
|   315             self.add_message('return-outside-function', node=node) |   191             self.add_message('E0105', node=node) | 
|   316  |   192  | 
|   317     @check_messages('yield-outside-function') |   193     @check_messages('E0103') | 
|   318     def visit_yield(self, node): |  | 
|   319         if not isinstance(node.frame(), (astroid.Function, astroid.Lambda)): |  | 
|   320             self.add_message('yield-outside-function', node=node) |  | 
|   321  |  | 
|   322     @check_messages('not-in-loop') |  | 
|   323     def visit_continue(self, node): |   194     def visit_continue(self, node): | 
|   324         self._check_in_loop(node, 'continue') |   195         self._check_in_loop(node, 'continue') | 
|   325  |   196  | 
|   326     @check_messages('not-in-loop') |   197     @check_messages('E0103') | 
|   327     def visit_break(self, node): |   198     def visit_break(self, node): | 
|   328         self._check_in_loop(node, 'break') |   199         self._check_in_loop(node, 'break') | 
|   329  |   200  | 
|   330     @check_messages('useless-else-on-loop') |   201     @check_messages('E0107') | 
|   331     def visit_for(self, node): |  | 
|   332         self._check_else_on_loop(node) |  | 
|   333  |  | 
|   334     @check_messages('useless-else-on-loop') |  | 
|   335     def visit_while(self, node): |  | 
|   336         self._check_else_on_loop(node) |  | 
|   337  |  | 
|   338     @check_messages('nonexistent-operator') |  | 
|   339     def visit_unaryop(self, node): |   202     def visit_unaryop(self, node): | 
|   340         """check use of the non-existent ++ and -- operator operator""" |   203         """check use of the non-existent ++ adn -- operator operator""" | 
|   341         if ((node.op in '+-') and |   204         if ((node.op in '+-') and | 
|   342                 isinstance(node.operand, astroid.UnaryOp) and |   205             isinstance(node.operand, astng.UnaryOp) and | 
|   343                 (node.operand.op == node.op)): |   206             (node.operand.op == node.op)): | 
|   344             self.add_message('nonexistent-operator', node=node, args=node.op*2) |   207             self.add_message('E0107', node=node, args=node.op*2) | 
|   345  |  | 
|   346     @check_messages('abstract-class-instantiated') |  | 
|   347     def visit_callfunc(self, node): |  | 
|   348         """ Check instantiating abstract class with |  | 
|   349         abc.ABCMeta as metaclass. |  | 
|   350         """ |  | 
|   351         try: |  | 
|   352             infered = node.func.infer().next() |  | 
|   353         except astroid.InferenceError: |  | 
|   354             return |  | 
|   355         if not isinstance(infered, astroid.Class): |  | 
|   356             return |  | 
|   357         # __init__ was called |  | 
|   358         metaclass = infered.metaclass() |  | 
|   359         if metaclass is None: |  | 
|   360             # Python 3.4 has `abc.ABC`, which won't be detected |  | 
|   361             # by ClassNode.metaclass() |  | 
|   362             for ancestor in infered.ancestors(): |  | 
|   363                 if (ancestor.qname() == 'abc.ABC' and |  | 
|   364                         has_abstract_methods(infered)): |  | 
|   365                     self.add_message('abstract-class-instantiated', node=node) |  | 
|   366                     break |  | 
|   367             return |  | 
|   368         if (metaclass.qname() == 'abc.ABCMeta' and |  | 
|   369                 has_abstract_methods(infered)): |  | 
|   370             self.add_message('abstract-class-instantiated', node=node) |  | 
|   371  |  | 
|   372     def _check_else_on_loop(self, node): |  | 
|   373         """Check that any loop with an else clause has a break statement.""" |  | 
|   374         if node.orelse and not _loop_exits_early(node): |  | 
|   375             self.add_message('useless-else-on-loop', node=node, |  | 
|   376                              # This is not optimal, but the line previous |  | 
|   377                              # to the first statement in the else clause |  | 
|   378                              # will usually be the one that contains the else:. |  | 
|   379                              line=node.orelse[0].lineno - 1) |  | 
|   380  |   208  | 
|   381     def _check_in_loop(self, node, node_name): |   209     def _check_in_loop(self, node, node_name): | 
|   382         """check that a node is inside a for or while loop""" |   210         """check that a node is inside a for or while loop""" | 
|   383         _node = node.parent |   211         _node = node.parent | 
|   384         while _node: |   212         while _node: | 
|   385             if isinstance(_node, (astroid.For, astroid.While)): |   213             if isinstance(_node, (astng.For, astng.While)): | 
|   386                 break |   214                 break | 
|   387             _node = _node.parent |   215             _node = _node.parent | 
|   388         else: |   216         else: | 
|   389             self.add_message('not-in-loop', node=node, args=node_name) |   217             self.add_message('E0103', node=node, args=node_name) | 
|   390  |   218  | 
|   391     def _check_redefinition(self, redeftype, node): |   219     def _check_redefinition(self, redeftype, node): | 
|   392         """check for redefinition of a function / method / class name""" |   220         """check for redefinition of a function / method / class name""" | 
|   393         defined_self = node.parent.frame()[node.name] |   221         defined_self = node.parent.frame()[node.name] | 
|   394         if defined_self is not node and not are_exclusive(node, defined_self): |   222         if defined_self is not node and not are_exclusive(node, defined_self): | 
|   395             self.add_message('function-redefined', node=node, |   223             self.add_message('E0102', node=node, | 
|   396                              args=(redeftype, defined_self.fromlineno)) |   224                              args=(redeftype, defined_self.fromlineno)) | 
|   397  |   225  | 
|   398  |   226  | 
|   399  |   227  | 
|   400 class BasicChecker(_BasicChecker): |   228 class BasicChecker(_BasicChecker): | 
|   401     """checks for : |   229     """checks for : | 
|   402     * doc strings |   230     * doc strings | 
 |   231     * modules / classes / functions / methods / arguments / variables name | 
|   403     * number of arguments, local variables, branches, returns and statements in |   232     * number of arguments, local variables, branches, returns and statements in | 
|   404 functions, methods |   233 functions, methods | 
|   405     * required module attributes |   234     * required module attributes | 
|   406     * dangerous default values as arguments |   235     * dangerous default values as arguments | 
|   407     * redefinition of function / method / class |   236     * redefinition of function / method / class | 
|   408     * uses of the global statement |   237     * uses of the global statement | 
|   409     """ |   238     """ | 
|   410  |   239  | 
|   411     __implements__ = IAstroidChecker |   240     __implements__ = IASTNGChecker | 
|   412  |   241  | 
|   413     name = 'basic' |   242     name = 'basic' | 
|   414     msgs = { |   243     msgs = { | 
|   415         'W0101': ('Unreachable code', |   244     'W0101': ('Unreachable code', | 
|   416                   'unreachable', |   245               'Used when there is some code behind a "return" or "raise" \ | 
|   417                   'Used when there is some code behind a "return" or "raise" ' |   246               statement, which will never be accessed.'), | 
|   418                   'statement, which will never be accessed.'), |   247     'W0102': ('Dangerous default value %s as argument', | 
|   419         'W0102': ('Dangerous default value %s as argument', |   248               'Used when a mutable value as list or dictionary is detected in \ | 
|   420                   'dangerous-default-value', |   249               a default value for an argument.'), | 
|   421                   'Used when a mutable value as list or dictionary is detected i
      n ' |   250     'W0104': ('Statement seems to have no effect', | 
|   422                   'a default value for an argument.'), |   251               'Used when a statement doesn\'t have (or at least seems to) \ | 
|   423         'W0104': ('Statement seems to have no effect', |   252               any effect.'), | 
|   424                   'pointless-statement', |   253     'W0105': ('String statement has no effect', | 
|   425                   'Used when a statement doesn\'t have (or at least seems to) ' |   254               'Used when a string is used as a statement (which of course \ | 
|   426                   'any effect.'), |   255               has no effect). This is a particular case of W0104 with its \ | 
|   427         'W0105': ('String statement has no effect', |   256               own message so you can easily disable it if you\'re using \ | 
|   428                   'pointless-string-statement', |   257               those strings as documentation, instead of comments.'), | 
|   429                   'Used when a string is used as a statement (which of course ' |   258     'W0106': ('Expression "%s" is assigned to nothing', | 
|   430                   'has no effect). This is a particular case of W0104 with its ' |   259               'Used when an expression that is not a function call is assigned\ | 
|   431                   'own message so you can easily disable it if you\'re using ' |   260               to nothing. Probably something else was intended.'), | 
|   432                   'those strings as documentation, instead of comments.'), |   261     'W0108': ('Lambda may not be necessary', | 
|   433         'W0106': ('Expression "%s" is assigned to nothing', |   262               'Used when the body of a lambda expression is a function call \ | 
|   434                   'expression-not-assigned', |   263               on the same argument list as the lambda itself; such lambda \ | 
|   435                   'Used when an expression that is not a function call is assign
      ed ' |   264               expressions are in all but a few cases replaceable with the \ | 
|   436                   'to nothing. Probably something else was intended.'), |   265               function being called in the body of the lambda.'), | 
|   437         'W0108': ('Lambda may not be necessary', |   266     'W0109': ("Duplicate key %r in dictionary", | 
|   438                   'unnecessary-lambda', |   267               "Used when a dictionary expression binds the same key multiple \ | 
|   439                   'Used when the body of a lambda expression is a function call 
      ' |   268               times."), | 
|   440                   'on the same argument list as the lambda itself; such lambda ' |   269     'W0122': ('Use of the exec statement', | 
|   441                   'expressions are in all but a few cases replaceable with the ' |   270               'Used when you use the "exec" statement, to discourage its \ | 
|   442                   'function being called in the body of the lambda.'), |   271               usage. That doesn\'t mean you can not use it !'), | 
|   443         'W0109': ("Duplicate key %r in dictionary", |  | 
|   444                   'duplicate-key', |  | 
|   445                   'Used when a dictionary expression binds the same key multiple
       ' |  | 
|   446                   'times.'), |  | 
|   447         'W0122': ('Use of exec', |  | 
|   448                   'exec-used', |  | 
|   449                   'Used when you use the "exec" statement (function for Python 3
      ), to discourage its ' |  | 
|   450                   'usage. That doesn\'t mean you can not use it !'), |  | 
|   451         'W0123': ('Use of eval', |  | 
|   452                   'eval-used', |  | 
|   453                   'Used when you use the "eval" function, to discourage its ' |  | 
|   454                   'usage. Consider using `ast.literal_eval` for safely evaluatin
      g ' |  | 
|   455                   'strings containing Python expressions ' |  | 
|   456                   'from untrusted sources. '), |  | 
|   457         'W0141': ('Used builtin function %r', |  | 
|   458                   'bad-builtin', |  | 
|   459                   'Used when a black listed builtin function is used (see the ' |  | 
|   460                   'bad-function option). Usual black listed functions are the on
      es ' |  | 
|   461                   'like map, or filter , where Python offers now some cleaner ' |  | 
|   462                   'alternative like list comprehension.'), |  | 
|   463         'W0142': ('Used * or ** magic', |  | 
|   464                   'star-args', |  | 
|   465                   'Used when a function or method is called using `*args` or ' |  | 
|   466                   '`**kwargs` to dispatch arguments. This doesn\'t improve ' |  | 
|   467                   'readability and should be used with care.'), |  | 
|   468         'W0150': ("%s statement in finally block may swallow exception", |  | 
|   469                   'lost-exception', |  | 
|   470                   'Used when a break or a return statement is found inside the ' |  | 
|   471                   'finally clause of a try...finally block: the exceptions raise
      d ' |  | 
|   472                   'in the try clause will be silently swallowed instead of being
       ' |  | 
|   473                   're-raised.'), |  | 
|   474         'W0199': ('Assert called on a 2-uple. Did you mean \'assert x,y\'?', |  | 
|   475                   'assert-on-tuple', |  | 
|   476                   'A call of assert on a tuple will always evaluate to true if ' |  | 
|   477                   'the tuple is not empty, and will always evaluate to false if 
      ' |  | 
|   478                   'it is.'), |  | 
|   479         'W0121': ('Use raise ErrorClass(args) instead of raise ErrorClass, args.
      ', |  | 
|   480                   'old-raise-syntax', |  | 
|   481                   "Used when the alternate raise syntax 'raise foo, bar' is used
       " |  | 
|   482                   "instead of 'raise foo(bar)'.", |  | 
|   483                   {'maxversion': (3, 0)}), |  | 
|   484  |   272  | 
|   485         'C0121': ('Missing required attribute "%s"', # W0103 |   273     'W0141': ('Used builtin function %r', | 
|   486                   'missing-module-attribute', |   274               'Used when a black listed builtin function is used (see the ' | 
|   487                   'Used when an attribute required for modules is missing.'), |   275               'bad-function option). Usual black listed functions are the ones ' | 
 |   276               'like map, or filter , where Python offers now some cleaner ' | 
 |   277               'alternative like list comprehension.'), | 
 |   278     'W0142': ('Used * or ** magic', | 
 |   279               'Used when a function or method is called using `*args` or ' | 
 |   280               '`**kwargs` to dispatch arguments. This doesn\'t improve ' | 
 |   281               'readability and should be used with care.'), | 
 |   282     'W0150': ("%s statement in finally block may swallow exception", | 
 |   283               "Used when a break or a return statement is found inside the \ | 
 |   284               finally clause of a try...finally block: the exceptions raised \ | 
 |   285               in the try clause will be silently swallowed instead of being \ | 
 |   286               re-raised."), | 
 |   287     'W0199': ('Assert called on a 2-uple. Did you mean \'assert x,y\'?', | 
 |   288               'A call of assert on a tuple will always evaluate to true if ' | 
 |   289               'the tuple is not empty, and will always evaluate to false if ' | 
 |   290               'it is.'), | 
|   488  |   291  | 
|   489         'E0109': ('Missing argument to reversed()', |   292     'C0121': ('Missing required attribute "%s"', # W0103 | 
|   490                   'missing-reversed-argument', |   293               'Used when an attribute required for modules is missing.'), | 
|   491                   'Used when reversed() builtin didn\'t receive an argument.'), |  | 
|   492         'E0111': ('The first reversed() argument is not a sequence', |  | 
|   493                   'bad-reversed-sequence', |  | 
|   494                   'Used when the first argument to reversed() builtin ' |  | 
|   495                   'isn\'t a sequence (does not implement __reversed__, ' |  | 
|   496                   'nor __getitem__ and __len__'), |  | 
|   497  |   294  | 
|   498     } |   295     } | 
|   499  |   296  | 
|   500     options = (('required-attributes', |   297     options = (('required-attributes', | 
|   501                 {'default' : (), 'type' : 'csv', |   298                 {'default' : (), 'type' : 'csv', | 
|   502                  'metavar' : '<attributes>', |   299                  'metavar' : '<attributes>', | 
|   503                  'help' : 'Required attributes for module, separated by a ' |   300                  'help' : 'Required attributes for module, separated by a ' | 
|   504                           'comma'} |   301                           'comma'} | 
|   505                ), |   302                 ), | 
|   506                ('bad-functions', |   303                ('bad-functions', | 
|   507                 {'default' : BAD_FUNCTIONS, |   304                 {'default' : ('map', 'filter', 'apply', 'input'), | 
|   508                  'type' :'csv', 'metavar' : '<builtin function names>', |   305                  'type' :'csv', 'metavar' : '<builtin function names>', | 
|   509                  'help' : 'List of builtins function names that should not be ' |   306                  'help' : 'List of builtins function names that should not be ' | 
|   510                           'used, separated by a comma'} |   307                           'used, separated by a comma'} | 
|   511                ), |   308                 ), | 
|   512               ) |   309                ) | 
|   513     reports = (('RP0101', 'Statistics by type', report_by_type_stats),) |   310     reports = ( ('RP0101', 'Statistics by type', report_by_type_stats), ) | 
|   514  |   311  | 
|   515     def __init__(self, linter): |   312     def __init__(self, linter): | 
|   516         _BasicChecker.__init__(self, linter) |   313         _BasicChecker.__init__(self, linter) | 
|   517         self.stats = None |   314         self.stats = None | 
|   518         self._tryfinallys = None |   315         self._tryfinallys = None | 
|   519  |   316  | 
|   520     def open(self): |   317     def open(self): | 
|   521         """initialize visit variables and statistics |   318         """initialize visit variables and statistics | 
|   522         """ |   319         """ | 
|   523         self._tryfinallys = [] |   320         self._tryfinallys = [] | 
|   524         self.stats = self.linter.add_stats(module=0, function=0, |   321         self.stats = self.linter.add_stats(module=0, function=0, | 
|   525                                            method=0, class_=0) |   322                                            method=0, class_=0) | 
|   526     @check_messages('missing-module-attribute') |   323  | 
|   527     def visit_module(self, node): |   324     def visit_module(self, node): | 
|   528         """check module name, docstring and required arguments |   325         """check module name, docstring and required arguments | 
|   529         """ |   326         """ | 
|   530         self.stats['module'] += 1 |   327         self.stats['module'] += 1 | 
|   531         for attr in self.config.required_attributes: |   328         for attr in self.config.required_attributes: | 
|   532             if attr not in node: |   329             if attr not in node: | 
|   533                 self.add_message('missing-module-attribute', node=node, args=att
      r) |   330                 self.add_message('C0121', node=node, args=attr) | 
|   534  |   331  | 
|   535     def visit_class(self, node): |   332     def visit_class(self, node): | 
|   536         """check module name, docstring and redefinition |   333         """check module name, docstring and redefinition | 
|   537         increment branch counter |   334         increment branch counter | 
|   538         """ |   335         """ | 
|   539         self.stats['class'] += 1 |   336         self.stats['class'] += 1 | 
|   540  |   337  | 
|   541     @check_messages('pointless-statement', 'pointless-string-statement', |   338     @check_messages('W0104', 'W0105') | 
|   542                     'expression-not-assigned') |  | 
|   543     def visit_discard(self, node): |   339     def visit_discard(self, node): | 
|   544         """check for various kind of statements without effect""" |   340         """check for various kind of statements without effect""" | 
|   545         expr = node.value |   341         expr = node.value | 
|   546         if isinstance(expr, astroid.Const) and isinstance(expr.value, |   342         if isinstance(expr, astng.Const) and isinstance(expr.value, | 
|   547                                                           basestring): |   343                                                         basestring): | 
|   548             # treat string statement in a separated message |   344             # treat string statement in a separated message | 
|   549             # Handle PEP-257 attribute docstrings. |   345             self.add_message('W0105', node=node) | 
|   550             # An attribute docstring is defined as being a string right after |  | 
|   551             # an assignment at the module level, class level or __init__ level. |  | 
|   552             scope = expr.scope() |  | 
|   553             if isinstance(scope, (astroid.Class, astroid.Module, astroid.Functio
      n)): |  | 
|   554                 if isinstance(scope, astroid.Function) and scope.name != '__init
      __': |  | 
|   555                     pass |  | 
|   556                 else: |  | 
|   557                     sibling = expr.previous_sibling() |  | 
|   558                     if (sibling is not None and sibling.scope() is scope and |  | 
|   559                             isinstance(sibling, astroid.Assign)): |  | 
|   560                         return |  | 
|   561             self.add_message('pointless-string-statement', node=node) |  | 
|   562             return |   346             return | 
|   563         # ignore if this is : |   347         # ignore if this is : | 
|   564         # * a direct function call |   348         # * a direct function call | 
|   565         # * the unique child of a try/except body |   349         # * the unique child of a try/except body | 
|   566         # * a yield (which are wrapped by a discard node in _ast XXX) |   350         # * a yield (which are wrapped by a discard node in _ast XXX) | 
|   567         # warn W0106 if we have any underlying function call (we can't predict |   351         # warn W0106 if we have any underlying function call (we can't predict | 
|   568         # side effects), else pointless-statement |   352         # side effects), else W0104 | 
|   569         if (isinstance(expr, (astroid.Yield, astroid.CallFunc)) or |   353         if (isinstance(expr, (astng.Yield, astng.CallFunc)) or | 
|   570                 (isinstance(node.parent, astroid.TryExcept) and |   354             (isinstance(node.parent, astng.TryExcept) and | 
|   571                  node.parent.body == [node])): |   355              node.parent.body == [node])): | 
|   572             return |   356             return | 
|   573         if any(expr.nodes_of_class(astroid.CallFunc)): |   357         if any(expr.nodes_of_class(astng.CallFunc)): | 
|   574             self.add_message('expression-not-assigned', node=node, |   358             self.add_message('W0106', node=node, args=expr.as_string()) | 
|   575                              args=expr.as_string()) |  | 
|   576         else: |   359         else: | 
|   577             self.add_message('pointless-statement', node=node) |   360             self.add_message('W0104', node=node) | 
|   578  |   361  | 
|   579     @check_messages('unnecessary-lambda') |   362     @check_messages('W0108') | 
|   580     def visit_lambda(self, node): |   363     def visit_lambda(self, node): | 
|   581         """check whether or not the lambda is suspicious |   364         """check whether or not the lambda is suspicious | 
|   582         """ |   365         """ | 
|   583         # if the body of the lambda is a call expression with the same |   366         # if the body of the lambda is a call expression with the same | 
|   584         # argument list as the lambda itself, then the lambda is |   367         # argument list as the lambda itself, then the lambda is | 
|   585         # possibly unnecessary and at least suspicious. |   368         # possibly unnecessary and at least suspicious. | 
|   586         if node.args.defaults: |   369         if node.args.defaults: | 
|   587             # If the arguments of the lambda include defaults, then a |   370             # If the arguments of the lambda include defaults, then a | 
|   588             # judgment cannot be made because there is no way to check |   371             # judgment cannot be made because there is no way to check | 
|   589             # that the defaults defined by the lambda are the same as |   372             # that the defaults defined by the lambda are the same as | 
|   590             # the defaults defined by the function called in the body |   373             # the defaults defined by the function called in the body | 
|   591             # of the lambda. |   374             # of the lambda. | 
|   592             return |   375             return | 
|   593         call = node.body |   376         call = node.body | 
|   594         if not isinstance(call, astroid.CallFunc): |   377         if not isinstance(call, astng.CallFunc): | 
|   595             # The body of the lambda must be a function call expression |   378             # The body of the lambda must be a function call expression | 
|   596             # for the lambda to be unnecessary. |   379             # for the lambda to be unnecessary. | 
|   597             return |   380             return | 
|   598         # XXX are lambda still different with astroid >= 0.18 ? |   381         # XXX are lambda still different with astng >= 0.18 ? | 
|   599         # *args and **kwargs need to be treated specially, since they |   382         # *args and **kwargs need to be treated specially, since they | 
|   600         # are structured differently between the lambda and the function |   383         # are structured differently between the lambda and the function | 
|   601         # call (in the lambda they appear in the args.args list and are |   384         # call (in the lambda they appear in the args.args list and are | 
|   602         # indicated as * and ** by two bits in the lambda's flags, but |   385         # indicated as * and ** by two bits in the lambda's flags, but | 
|   603         # in the function call they are omitted from the args list and |   386         # in the function call they are omitted from the args list and | 
|   604         # are indicated by separate attributes on the function call node). |   387         # are indicated by separate attributes on the function call node). | 
|   605         ordinary_args = list(node.args.args) |   388         ordinary_args = list(node.args.args) | 
|   606         if node.args.kwarg: |   389         if node.args.kwarg: | 
|   607             if (not call.kwargs |   390             if (not call.kwargs | 
|   608                     or not isinstance(call.kwargs, astroid.Name) |   391                 or not isinstance(call.kwargs, astng.Name) | 
|   609                     or node.args.kwarg != call.kwargs.name): |   392                 or node.args.kwarg != call.kwargs.name): | 
|   610                 return |   393                 return | 
|   611         elif call.kwargs: |   394         elif call.kwargs: | 
|   612             return |   395             return | 
|   613         if node.args.vararg: |   396         if node.args.vararg: | 
|   614             if (not call.starargs |   397             if (not call.starargs | 
|   615                     or not isinstance(call.starargs, astroid.Name) |   398                 or not isinstance(call.starargs, astng.Name) | 
|   616                     or node.args.vararg != call.starargs.name): |   399                 or node.args.vararg != call.starargs.name): | 
|   617                 return |   400                 return | 
|   618         elif call.starargs: |   401         elif call.starargs: | 
|   619             return |   402             return | 
|   620         # The "ordinary" arguments must be in a correspondence such that: |   403         # The "ordinary" arguments must be in a correspondence such that: | 
|   621         # ordinary_args[i].name == call.args[i].name. |   404         # ordinary_args[i].name == call.args[i].name. | 
|   622         if len(ordinary_args) != len(call.args): |   405         if len(ordinary_args) != len(call.args): | 
|   623             return |   406             return | 
|   624         for i in xrange(len(ordinary_args)): |   407         for i in xrange(len(ordinary_args)): | 
|   625             if not isinstance(call.args[i], astroid.Name): |   408             if not isinstance(call.args[i], astng.Name): | 
|   626                 return |   409                 return | 
|   627             if node.args.args[i].name != call.args[i].name: |   410             if node.args.args[i].name != call.args[i].name: | 
|   628                 return |   411                 return | 
|   629         if (isinstance(node.body.func, astroid.Getattr) and |   412         self.add_message('W0108', line=node.fromlineno, node=node) | 
|   630             isinstance(node.body.func.expr, astroid.CallFunc)): |  | 
|   631             # Chained call, the intermediate call might |  | 
|   632             # return something else (but we don't check that, yet). |  | 
|   633             return |  | 
|   634         self.add_message('unnecessary-lambda', line=node.fromlineno, node=node) |  | 
|   635  |   413  | 
|   636     @check_messages('dangerous-default-value') |  | 
|   637     def visit_function(self, node): |   414     def visit_function(self, node): | 
|   638         """check function name, docstring, arguments, redefinition, |   415         """check function name, docstring, arguments, redefinition, | 
|   639         variable names, max locals |   416         variable names, max locals | 
|   640         """ |   417         """ | 
|   641         self.stats[node.is_method() and 'method' or 'function'] += 1 |   418         self.stats[node.is_method() and 'method' or 'function'] += 1 | 
|   642         # check for dangerous default values as arguments |   419         # check for dangerous default values as arguments | 
|   643         for default in node.args.defaults: |   420         for default in node.args.defaults: | 
|   644             try: |   421             try: | 
|   645                 value = default.infer().next() |   422                 value = default.infer().next() | 
|   646             except astroid.InferenceError: |   423             except astng.InferenceError: | 
|   647                 continue |   424                 continue | 
|   648             builtins = astroid.bases.BUILTINS |   425             if isinstance(value, (astng.Dict, astng.List)): | 
|   649             if (isinstance(value, astroid.Instance) and |  | 
|   650                     value.qname() in ['.'.join([builtins, x]) for x in ('set', '
      dict', 'list')]): |  | 
|   651                 if value is default: |   426                 if value is default: | 
|   652                     msg = default.as_string() |   427                     msg = default.as_string() | 
|   653                 elif type(value) is astroid.Instance: |  | 
|   654                     msg = '%s (%s)' % (default.as_string(), value.qname()) |  | 
|   655                 else: |   428                 else: | 
|   656                     msg = '%s (%s)' % (default.as_string(), value.as_string()) |   429                     msg = '%s (%s)' % (default.as_string(), value.as_string()) | 
|   657                 self.add_message('dangerous-default-value', node=node, args=(msg
      ,)) |   430                 self.add_message('W0102', node=node, args=(msg,)) | 
|   658  |   431  | 
|   659     @check_messages('unreachable', 'lost-exception') |   432     @check_messages('W0101', 'W0150') | 
|   660     def visit_return(self, node): |   433     def visit_return(self, node): | 
|   661         """1 - check is the node has a right sibling (if so, that's some |   434         """1 - check is the node has a right sibling (if so, that's some | 
|   662         unreachable code) |   435         unreachable code) | 
|   663         2 - check is the node is inside the finally clause of a try...finally |   436         2 - check is the node is inside the finally clause of a try...finally | 
|   664         block |   437         block | 
|   665         """ |   438         """ | 
|   666         self._check_unreachable(node) |   439         self._check_unreachable(node) | 
|   667         # Is it inside final body of a try...finally bloc ? |   440         # Is it inside final body of a try...finally bloc ? | 
|   668         self._check_not_in_finally(node, 'return', (astroid.Function,)) |   441         self._check_not_in_finally(node, 'return', (astng.Function,)) | 
|   669  |   442  | 
|   670     @check_messages('unreachable') |   443     @check_messages('W0101') | 
|   671     def visit_continue(self, node): |   444     def visit_continue(self, node): | 
|   672         """check is the node has a right sibling (if so, that's some unreachable |   445         """check is the node has a right sibling (if so, that's some unreachable | 
|   673         code) |   446         code) | 
|   674         """ |   447         """ | 
|   675         self._check_unreachable(node) |   448         self._check_unreachable(node) | 
|   676  |   449  | 
|   677     @check_messages('unreachable', 'lost-exception') |   450     @check_messages('W0101', 'W0150') | 
|   678     def visit_break(self, node): |   451     def visit_break(self, node): | 
|   679         """1 - check is the node has a right sibling (if so, that's some |   452         """1 - check is the node has a right sibling (if so, that's some | 
|   680         unreachable code) |   453         unreachable code) | 
|   681         2 - check is the node is inside the finally clause of a try...finally |   454         2 - check is the node is inside the finally clause of a try...finally | 
|   682         block |   455         block | 
|   683         """ |   456         """ | 
|   684         # 1 - Is it right sibling ? |   457         # 1 - Is it right sibling ? | 
|   685         self._check_unreachable(node) |   458         self._check_unreachable(node) | 
|   686         # 2 - Is it inside final body of a try...finally bloc ? |   459         # 2 - Is it inside final body of a try...finally bloc ? | 
|   687         self._check_not_in_finally(node, 'break', (astroid.For, astroid.While,)) |   460         self._check_not_in_finally(node, 'break', (astng.For, astng.While,)) | 
|   688  |   461  | 
|   689     @check_messages('unreachable', 'old-raise-syntax') |   462     @check_messages('W0101') | 
|   690     def visit_raise(self, node): |   463     def visit_raise(self, node): | 
|   691         """check if the node has a right sibling (if so, that's some unreachable |   464         """check is the node has a right sibling (if so, that's some unreachable | 
|   692         code) |   465         code) | 
|   693         """ |   466         """ | 
|   694         self._check_unreachable(node) |   467         self._check_unreachable(node) | 
|   695         if sys.version_info >= (3, 0): |  | 
|   696             return |  | 
|   697         if node.exc is not None and node.inst is not None and node.tback is None
      : |  | 
|   698             self.add_message('old-raise-syntax', node=node) |  | 
|   699  |   468  | 
|   700     @check_messages('exec-used') |   469     @check_messages('W0122') | 
|   701     def visit_exec(self, node): |   470     def visit_exec(self, node): | 
|   702         """just print a warning on exec statements""" |   471         """just print a warning on exec statements""" | 
|   703         self.add_message('exec-used', node=node) |   472         self.add_message('W0122', node=node) | 
|   704  |   473  | 
|   705     @check_messages('bad-builtin', 'star-args', 'eval-used', |   474     @check_messages('W0141', 'W0142') | 
|   706                     'exec-used', 'missing-reversed-argument', |  | 
|   707                     'bad-reversed-sequence') |  | 
|   708     def visit_callfunc(self, node): |   475     def visit_callfunc(self, node): | 
|   709         """visit a CallFunc node -> check if this is not a blacklisted builtin |   476         """visit a CallFunc node -> check if this is not a blacklisted builtin | 
|   710         call and check for * or ** use |   477         call and check for * or ** use | 
|   711         """ |   478         """ | 
|   712         if isinstance(node.func, astroid.Name): |   479         if isinstance(node.func, astng.Name): | 
|   713             name = node.func.name |   480             name = node.func.name | 
|   714             # ignore the name if it's not a builtin (i.e. not defined in the |   481             # ignore the name if it's not a builtin (i.e. not defined in the | 
|   715             # locals nor globals scope) |   482             # locals nor globals scope) | 
|   716             if not (name in node.frame() or |   483             if not (name in node.frame() or | 
|   717                     name in node.root()): |   484                     name in node.root()): | 
|   718                 if name == 'exec': |  | 
|   719                     self.add_message('exec-used', node=node) |  | 
|   720                 elif name == 'reversed': |  | 
|   721                     self._check_reversed(node) |  | 
|   722                 elif name == 'eval': |  | 
|   723                     self.add_message('eval-used', node=node) |  | 
|   724                 if name in self.config.bad_functions: |   485                 if name in self.config.bad_functions: | 
|   725                     self.add_message('bad-builtin', node=node, args=name) |   486                     self.add_message('W0141', node=node, args=name) | 
|   726         if node.starargs or node.kwargs: |   487         if node.starargs or node.kwargs: | 
|   727             scope = node.scope() |   488             scope = node.scope() | 
|   728             if isinstance(scope, astroid.Function): |   489             if isinstance(scope, astng.Function): | 
|   729                 toprocess = [(n, vn) for (n, vn) in ((node.starargs, scope.args.
      vararg), |   490                 toprocess = [(n, vn) for (n, vn) in ((node.starargs, scope.args.
      vararg), | 
|   730                                                      (node.kwargs, scope.args.kw
      arg)) if n] |   491                                                      (node.kwargs, scope.args.kw
      arg)) if n] | 
|   731                 if toprocess: |   492                 if toprocess: | 
|   732                     for cfnode, fargname in toprocess[:]: |   493                     for cfnode, fargname in toprocess[:]: | 
|   733                         if getattr(cfnode, 'name', None) == fargname: |   494                         if getattr(cfnode, 'name', None) == fargname: | 
|   734                             toprocess.remove((cfnode, fargname)) |   495                             toprocess.remove((cfnode, fargname)) | 
|   735                     if not toprocess: |   496                     if not toprocess: | 
|   736                         return # star-args can be skipped |   497                         return # W0142 can be skipped | 
|   737             self.add_message('star-args', node=node.func) |   498             self.add_message('W0142', node=node.func) | 
|   738  |   499  | 
|   739     @check_messages('assert-on-tuple') |   500     @check_messages('W0199') | 
|   740     def visit_assert(self, node): |   501     def visit_assert(self, node): | 
|   741         """check the use of an assert statement on a tuple.""" |   502         """check the use of an assert statement on a tuple.""" | 
|   742         if node.fail is None and isinstance(node.test, astroid.Tuple) and \ |   503         if node.fail is None and isinstance(node.test, astng.Tuple) and \ | 
|   743                 len(node.test.elts) == 2: |   504            len(node.test.elts) == 2: | 
|   744             self.add_message('assert-on-tuple', node=node) |   505              self.add_message('W0199', line=node.fromlineno, node=node) | 
|   745  |   506  | 
|   746     @check_messages('duplicate-key') |   507     @check_messages('W0109') | 
|   747     def visit_dict(self, node): |   508     def visit_dict(self, node): | 
|   748         """check duplicate key in dictionary""" |   509         """check duplicate key in dictionary""" | 
|   749         keys = set() |   510         keys = set() | 
|   750         for k, _ in node.items: |   511         for k, v in node.items: | 
|   751             if isinstance(k, astroid.Const): |   512             if isinstance(k, astng.Const): | 
|   752                 key = k.value |   513                 key = k.value | 
|   753                 if key in keys: |   514                 if key in keys: | 
|   754                     self.add_message('duplicate-key', node=node, args=key) |   515                     self.add_message('W0109', node=node, args=key) | 
|   755                 keys.add(key) |   516                 keys.add(key) | 
|   756  |   517  | 
|   757     def visit_tryfinally(self, node): |   518     def visit_tryfinally(self, node): | 
|   758         """update try...finally flag""" |   519         """update try...finally flag""" | 
|   759         self._tryfinallys.append(node) |   520         self._tryfinallys.append(node) | 
|   760  |   521  | 
|   761     def leave_tryfinally(self, node): |   522     def leave_tryfinally(self, node): | 
|   762         """update try...finally flag""" |   523         """update try...finally flag""" | 
|   763         self._tryfinallys.pop() |   524         self._tryfinallys.pop() | 
|   764  |   525  | 
|   765     def _check_unreachable(self, node): |   526     def _check_unreachable(self, node): | 
|   766         """check unreachable code""" |   527         """check unreachable code""" | 
|   767         unreach_stmt = node.next_sibling() |   528         unreach_stmt = node.next_sibling() | 
|   768         if unreach_stmt is not None: |   529         if unreach_stmt is not None: | 
|   769             self.add_message('unreachable', node=unreach_stmt) |   530             self.add_message('W0101', node=unreach_stmt) | 
|   770  |   531  | 
|   771     def _check_not_in_finally(self, node, node_name, breaker_classes=()): |   532     def _check_not_in_finally(self, node, node_name, breaker_classes=()): | 
|   772         """check that a node is not inside a finally clause of a |   533         """check that a node is not inside a finally clause of a | 
|   773         try...finally statement. |   534         try...finally statement. | 
|   774         If we found before a try...finally bloc a parent which its type is |   535         If we found before a try...finally bloc a parent which its type is | 
|   775         in breaker_classes, we skip the whole check.""" |   536         in breaker_classes, we skip the whole check.""" | 
|   776         # if self._tryfinallys is empty, we're not a in try...finally bloc |   537         # if self._tryfinallys is empty, we're not a in try...finally bloc | 
|   777         if not self._tryfinallys: |   538         if not self._tryfinallys: | 
|   778             return |   539             return | 
|   779         # the node could be a grand-grand...-children of the try...finally |   540         # the node could be a grand-grand...-children of the try...finally | 
|   780         _parent = node.parent |   541         _parent = node.parent | 
|   781         _node = node |   542         _node = node | 
|   782         while _parent and not isinstance(_parent, breaker_classes): |   543         while _parent and not isinstance(_parent, breaker_classes): | 
|   783             if hasattr(_parent, 'finalbody') and _node in _parent.finalbody: |   544             if hasattr(_parent, 'finalbody') and _node in _parent.finalbody: | 
|   784                 self.add_message('lost-exception', node=node, args=node_name) |   545                 self.add_message('W0150', node=node, args=node_name) | 
|   785                 return |   546                 return | 
|   786             _node = _parent |   547             _node = _parent | 
|   787             _parent = _node.parent |   548             _parent = _node.parent | 
|   788  |   549  | 
|   789     def _check_reversed(self, node): |  | 
|   790         """ check that the argument to `reversed` is a sequence """ |  | 
|   791         try: |  | 
|   792             argument = safe_infer(get_argument_from_call(node, position=0)) |  | 
|   793         except NoSuchArgumentError: |  | 
|   794             self.add_message('missing-reversed-argument', node=node) |  | 
|   795         else: |  | 
|   796             if argument is astroid.YES: |  | 
|   797                 return |  | 
|   798             if argument is None: |  | 
|   799                 # nothing was infered |  | 
|   800                 # try to see if we have iter() |  | 
|   801                 if isinstance(node.args[0], astroid.CallFunc): |  | 
|   802                     try: |  | 
|   803                         func = node.args[0].func.infer().next() |  | 
|   804                     except InferenceError: |  | 
|   805                         return |  | 
|   806                     if (getattr(func, 'name', None) == 'iter' and |  | 
|   807                             is_builtin_object(func)): |  | 
|   808                         self.add_message('bad-reversed-sequence', node=node) |  | 
|   809                 return |  | 
|   810  |   550  | 
|   811             if isinstance(argument, astroid.Instance): |  | 
|   812                 if (argument._proxied.name == 'dict' and |  | 
|   813                         is_builtin_object(argument._proxied)): |  | 
|   814                     self.add_message('bad-reversed-sequence', node=node) |  | 
|   815                     return |  | 
|   816                 elif any(ancestor.name == 'dict' and is_builtin_object(ancestor) |  | 
|   817                          for ancestor in argument._proxied.ancestors()): |  | 
|   818                     # mappings aren't accepted by reversed() |  | 
|   819                     self.add_message('bad-reversed-sequence', node=node) |  | 
|   820                     return |  | 
|   821  |  | 
|   822                 for methods in REVERSED_METHODS: |  | 
|   823                     for meth in methods: |  | 
|   824                         try: |  | 
|   825                             argument.getattr(meth) |  | 
|   826                         except astroid.NotFoundError: |  | 
|   827                             break |  | 
|   828                     else: |  | 
|   829                         break |  | 
|   830                 else: |  | 
|   831                     # check if it is a .deque. It doesn't seem that |  | 
|   832                     # we can retrieve special methods |  | 
|   833                     # from C implemented constructs |  | 
|   834                     if argument._proxied.qname().endswith(".deque"): |  | 
|   835                         return |  | 
|   836                     self.add_message('bad-reversed-sequence', node=node) |  | 
|   837             elif not isinstance(argument, (astroid.List, astroid.Tuple)): |  | 
|   838                 # everything else is not a proper sequence for reversed() |  | 
|   839                 self.add_message('bad-reversed-sequence', node=node) |  | 
|   840  |  | 
|   841 _NAME_TYPES = { |  | 
|   842     'module': (MOD_NAME_RGX, 'module'), |  | 
|   843     'const': (CONST_NAME_RGX, 'constant'), |  | 
|   844     'class': (CLASS_NAME_RGX, 'class'), |  | 
|   845     'function': (DEFAULT_NAME_RGX, 'function'), |  | 
|   846     'method': (DEFAULT_NAME_RGX, 'method'), |  | 
|   847     'attr': (DEFAULT_NAME_RGX, 'attribute'), |  | 
|   848     'argument': (DEFAULT_NAME_RGX, 'argument'), |  | 
|   849     'variable': (DEFAULT_NAME_RGX, 'variable'), |  | 
|   850     'class_attribute': (CLASS_ATTRIBUTE_RGX, 'class attribute'), |  | 
|   851     'inlinevar': (COMP_VAR_RGX, 'inline iteration'), |  | 
|   852 } |  | 
|   853  |  | 
|   854 def _create_naming_options(): |  | 
|   855     name_options = [] |  | 
|   856     for name_type, (rgx, human_readable_name) in _NAME_TYPES.iteritems(): |  | 
|   857         name_type = name_type.replace('_', '-') |  | 
|   858         name_options.append(( |  | 
|   859             '%s-rgx' % (name_type,), |  | 
|   860             {'default': rgx, 'type': 'regexp', 'metavar': '<regexp>', |  | 
|   861              'help': 'Regular expression matching correct %s names' % (human_rea
      dable_name,)})) |  | 
|   862         name_options.append(( |  | 
|   863             '%s-name-hint' % (name_type,), |  | 
|   864             {'default': rgx.pattern, 'type': 'string', 'metavar': '<string>', |  | 
|   865              'help': 'Naming hint for %s names' % (human_readable_name,)})) |  | 
|   866     return tuple(name_options) |  | 
|   867  |   551  | 
|   868 class NameChecker(_BasicChecker): |   552 class NameChecker(_BasicChecker): | 
|   869     msgs = { |   553     msgs = { | 
|   870         'C0102': ('Black listed name "%s"', |   554     'C0102': ('Black listed name "%s"', | 
|   871                   'blacklisted-name', |   555               'Used when the name is listed in the black list (unauthorized \ | 
|   872                   'Used when the name is listed in the black list (unauthorized 
      ' |   556               names).'), | 
|   873                   'names).'), |   557     'C0103': ('Invalid name "%s" (should match %s)', | 
|   874         'C0103': ('Invalid %s name "%s"%s', |   558               'Used when the name doesn\'t match the regular expression \ | 
|   875                   'invalid-name', |   559               associated to its type (constant, variable, class...).'), | 
|   876                   'Used when the name doesn\'t match the regular expression ' |   560  | 
|   877                   'associated to its type (constant, variable, class...).'), |  | 
|   878     } |   561     } | 
|   879  |   562     options = (('module-rgx', | 
|   880     options = (('good-names', |   563                 {'default' : MOD_NAME_RGX, | 
 |   564                  'type' :'regexp', 'metavar' : '<regexp>', | 
 |   565                  'help' : 'Regular expression which should only match correct ' | 
 |   566                           'module names'} | 
 |   567                 ), | 
 |   568                ('const-rgx', | 
 |   569                 {'default' : CONST_NAME_RGX, | 
 |   570                  'type' :'regexp', 'metavar' : '<regexp>', | 
 |   571                  'help' : 'Regular expression which should only match correct ' | 
 |   572                           'module level names'} | 
 |   573                 ), | 
 |   574                ('class-rgx', | 
 |   575                 {'default' : CLASS_NAME_RGX, | 
 |   576                  'type' :'regexp', 'metavar' : '<regexp>', | 
 |   577                  'help' : 'Regular expression which should only match correct ' | 
 |   578                           'class names'} | 
 |   579                 ), | 
 |   580                ('function-rgx', | 
 |   581                 {'default' : DEFAULT_NAME_RGX, | 
 |   582                  'type' :'regexp', 'metavar' : '<regexp>', | 
 |   583                  'help' : 'Regular expression which should only match correct ' | 
 |   584                           'function names'} | 
 |   585                 ), | 
 |   586                ('method-rgx', | 
 |   587                 {'default' : DEFAULT_NAME_RGX, | 
 |   588                  'type' :'regexp', 'metavar' : '<regexp>', | 
 |   589                  'help' : 'Regular expression which should only match correct ' | 
 |   590                           'method names'} | 
 |   591                 ), | 
 |   592                ('attr-rgx', | 
 |   593                 {'default' : DEFAULT_NAME_RGX, | 
 |   594                  'type' :'regexp', 'metavar' : '<regexp>', | 
 |   595                  'help' : 'Regular expression which should only match correct ' | 
 |   596                           'instance attribute names'} | 
 |   597                 ), | 
 |   598                ('argument-rgx', | 
 |   599                 {'default' : DEFAULT_NAME_RGX, | 
 |   600                  'type' :'regexp', 'metavar' : '<regexp>', | 
 |   601                  'help' : 'Regular expression which should only match correct ' | 
 |   602                           'argument names'}), | 
 |   603                ('variable-rgx', | 
 |   604                 {'default' : DEFAULT_NAME_RGX, | 
 |   605                  'type' :'regexp', 'metavar' : '<regexp>', | 
 |   606                  'help' : 'Regular expression which should only match correct ' | 
 |   607                           'variable names'} | 
 |   608                 ), | 
 |   609                ('inlinevar-rgx', | 
 |   610                 {'default' : COMP_VAR_RGX, | 
 |   611                  'type' :'regexp', 'metavar' : '<regexp>', | 
 |   612                  'help' : 'Regular expression which should only match correct ' | 
 |   613                           'list comprehension / generator expression variable \ | 
 |   614                           names'} | 
 |   615                 ), | 
 |   616                # XXX use set | 
 |   617                ('good-names', | 
|   881                 {'default' : ('i', 'j', 'k', 'ex', 'Run', '_'), |   618                 {'default' : ('i', 'j', 'k', 'ex', 'Run', '_'), | 
|   882                  'type' :'csv', 'metavar' : '<names>', |   619                  'type' :'csv', 'metavar' : '<names>', | 
|   883                  'help' : 'Good variable names which should always be accepted,' |   620                  'help' : 'Good variable names which should always be accepted,' | 
|   884                           ' separated by a comma'} |   621                           ' separated by a comma'} | 
|   885                ), |   622                 ), | 
|   886                ('bad-names', |   623                ('bad-names', | 
|   887                 {'default' : ('foo', 'bar', 'baz', 'toto', 'tutu', 'tata'), |   624                 {'default' : ('foo', 'bar', 'baz', 'toto', 'tutu', 'tata'), | 
|   888                  'type' :'csv', 'metavar' : '<names>', |   625                  'type' :'csv', 'metavar' : '<names>', | 
|   889                  'help' : 'Bad variable names which should always be refused, ' |   626                  'help' : 'Bad variable names which should always be refused, ' | 
|   890                           'separated by a comma'} |   627                           'separated by a comma'} | 
|   891                ), |   628                 ), | 
|   892                ('name-group', |   629                ) | 
|   893                 {'default' : (), |  | 
|   894                  'type' :'csv', 'metavar' : '<name1:name2>', |  | 
|   895                  'help' : ('Colon-delimited sets of names that determine each' |  | 
|   896                            ' other\'s naming style when the name regexes' |  | 
|   897                            ' allow several styles.')} |  | 
|   898                ), |  | 
|   899                ('include-naming-hint', |  | 
|   900                 {'default': False, 'type' : 'yn', 'metavar' : '<y_or_n>', |  | 
|   901                  'help': 'Include a hint for the correct naming format with inva
      lid-name'} |  | 
|   902                ), |  | 
|   903               ) + _create_naming_options() |  | 
|   904  |  | 
|   905  |  | 
|   906     def __init__(self, linter): |  | 
|   907         _BasicChecker.__init__(self, linter) |  | 
|   908         self._name_category = {} |  | 
|   909         self._name_group = {} |  | 
|   910  |   630  | 
|   911     def open(self): |   631     def open(self): | 
|   912         self.stats = self.linter.add_stats(badname_module=0, |   632         self.stats = self.linter.add_stats(badname_module=0, | 
|   913                                            badname_class=0, badname_function=0, |   633                                            badname_class=0, badname_function=0, | 
|   914                                            badname_method=0, badname_attr=0, |   634                                            badname_method=0, badname_attr=0, | 
|   915                                            badname_const=0, |   635                                            badname_const=0, | 
|   916                                            badname_variable=0, |   636                                            badname_variable=0, | 
|   917                                            badname_inlinevar=0, |   637                                            badname_inlinevar=0, | 
|   918                                            badname_argument=0, |   638                                            badname_argument=0) | 
|   919                                            badname_class_attribute=0) |  | 
|   920         for group in self.config.name_group: |  | 
|   921             for name_type in group.split(':'): |  | 
|   922                 self._name_group[name_type] = 'group_%s' % (group,) |  | 
|   923  |   639  | 
|   924     @check_messages('blacklisted-name', 'invalid-name') |   640     @check_messages('C0102', 'C0103') | 
|   925     def visit_module(self, node): |   641     def visit_module(self, node): | 
|   926         self._check_name('module', node.name.split('.')[-1], node) |   642         self._check_name('module', node.name.split('.')[-1], node) | 
|   927  |   643  | 
|   928     @check_messages('blacklisted-name', 'invalid-name') |   644     @check_messages('C0102', 'C0103') | 
|   929     def visit_class(self, node): |   645     def visit_class(self, node): | 
|   930         self._check_name('class', node.name, node) |   646         self._check_name('class', node.name, node) | 
|   931         for attr, anodes in node.instance_attrs.iteritems(): |   647         for attr, anodes in node.instance_attrs.items(): | 
|   932             if not list(node.instance_attr_ancestors(attr)): |   648             self._check_name('attr', attr, anodes[0]) | 
|   933                 self._check_name('attr', attr, anodes[0]) |  | 
|   934  |   649  | 
|   935     @check_messages('blacklisted-name', 'invalid-name') |   650     @check_messages('C0102', 'C0103') | 
|   936     def visit_function(self, node): |   651     def visit_function(self, node): | 
|   937         # Do not emit any warnings if the method is just an implementation |   652         self._check_name(node.is_method() and 'method' or 'function', | 
|   938         # of a base class method. |  | 
|   939         if node.is_method() and overrides_a_method(node.parent.frame(), node.nam
      e): |  | 
|   940             return |  | 
|   941         self._check_name(_determine_function_name_type(node), |  | 
|   942                          node.name, node) |   653                          node.name, node) | 
|   943         # Check argument names |   654         # check arguments name | 
|   944         args = node.args.args |   655         args = node.args.args | 
|   945         if args is not None: |   656         if args is not None: | 
|   946             self._recursive_check_names(args, node) |   657             self._recursive_check_names(args, node) | 
|   947  |   658  | 
|   948     @check_messages('blacklisted-name', 'invalid-name') |   659     @check_messages('C0102', 'C0103') | 
|   949     def visit_global(self, node): |  | 
|   950         for name in node.names: |  | 
|   951             self._check_name('const', name, node) |  | 
|   952  |  | 
|   953     @check_messages('blacklisted-name', 'invalid-name') |  | 
|   954     def visit_assname(self, node): |   660     def visit_assname(self, node): | 
|   955         """check module level assigned names""" |   661         """check module level assigned names""" | 
|   956         frame = node.frame() |   662         frame = node.frame() | 
|   957         ass_type = node.ass_type() |   663         ass_type = node.ass_type() | 
|   958         if isinstance(ass_type, astroid.Comprehension): |   664         if isinstance(ass_type, (astng.Comprehension, astng.Comprehension)): | 
|   959             self._check_name('inlinevar', node.name, node) |   665             self._check_name('inlinevar', node.name, node) | 
|   960         elif isinstance(frame, astroid.Module): |   666         elif isinstance(frame, astng.Module): | 
|   961             if isinstance(ass_type, astroid.Assign) and not in_loop(ass_type): |   667             if isinstance(ass_type, astng.Assign) and not in_loop(ass_type): | 
|   962                 if isinstance(safe_infer(ass_type.value), astroid.Class): |   668                 self._check_name('const', node.name, node) | 
|   963                     self._check_name('class', node.name, node) |   669             elif isinstance(ass_type, astng.ExceptHandler): | 
|   964                 else: |  | 
|   965                     self._check_name('const', node.name, node) |  | 
|   966             elif isinstance(ass_type, astroid.ExceptHandler): |  | 
|   967                 self._check_name('variable', node.name, node) |   670                 self._check_name('variable', node.name, node) | 
|   968         elif isinstance(frame, astroid.Function): |   671         elif isinstance(frame, astng.Function): | 
|   969             # global introduced variable aren't in the function locals |   672             # global introduced variable aren't in the function locals | 
|   970             if node.name in frame and node.name not in frame.argnames(): |   673             if node.name in frame: | 
|   971                 self._check_name('variable', node.name, node) |   674                 self._check_name('variable', node.name, node) | 
|   972         elif isinstance(frame, astroid.Class): |  | 
|   973             if not list(frame.local_attr_ancestors(node.name)): |  | 
|   974                 self._check_name('class_attribute', node.name, node) |  | 
|   975  |   675  | 
|   976     def _recursive_check_names(self, args, node): |   676     def _recursive_check_names(self, args, node): | 
|   977         """check names in a possibly recursive list <arg>""" |   677         """check names in a possibly recursive list <arg>""" | 
|   978         for arg in args: |   678         for arg in args: | 
|   979             if isinstance(arg, astroid.AssName): |   679             if isinstance(arg, astng.AssName): | 
|   980                 self._check_name('argument', arg.name, node) |   680                 self._check_name('argument', arg.name, node) | 
|   981             else: |   681             else: | 
|   982                 self._recursive_check_names(arg.elts, node) |   682                 self._recursive_check_names(arg.elts, node) | 
|   983  |   683  | 
|   984     def _find_name_group(self, node_type): |  | 
|   985         return self._name_group.get(node_type, node_type) |  | 
|   986  |  | 
|   987     def _is_multi_naming_match(self, match): |  | 
|   988         return (match is not None and |  | 
|   989                 match.lastgroup is not None and |  | 
|   990                 match.lastgroup not in EXEMPT_NAME_CATEGORIES) |  | 
|   991  |  | 
|   992     def _check_name(self, node_type, name, node): |   684     def _check_name(self, node_type, name, node): | 
|   993         """check for a name using the type's regexp""" |   685         """check for a name using the type's regexp""" | 
|   994         if is_inside_except(node): |   686         if is_inside_except(node): | 
|   995             clobbering, _ = clobber_in_except(node) |   687             clobbering, _ = clobber_in_except(node) | 
|   996             if clobbering: |   688             if clobbering: | 
|   997                 return |   689                 return | 
 |   690  | 
|   998         if name in self.config.good_names: |   691         if name in self.config.good_names: | 
|   999             return |   692             return | 
|  1000         if name in self.config.bad_names: |   693         if name in self.config.bad_names: | 
|  1001             self.stats['badname_' + node_type] += 1 |   694             self.stats['badname_' + node_type] += 1 | 
|  1002             self.add_message('blacklisted-name', node=node, args=name) |   695             self.add_message('C0102', node=node, args=name) | 
|  1003             return |   696             return | 
|  1004         regexp = getattr(self.config, node_type + '_rgx') |   697         regexp = getattr(self.config, node_type + '_rgx') | 
|  1005         match = regexp.match(name) |   698         if regexp.match(name) is None: | 
|  1006  |   699             self.add_message('C0103', node=node, args=(name, regexp.pattern)) | 
|  1007         if self._is_multi_naming_match(match): |  | 
|  1008             name_group = self._find_name_group(node_type) |  | 
|  1009             if name_group not in self._name_category: |  | 
|  1010                 self._name_category[name_group] = match.lastgroup |  | 
|  1011             elif self._name_category[name_group] != match.lastgroup: |  | 
|  1012                 match = None |  | 
|  1013  |  | 
|  1014         if match is None: |  | 
|  1015             type_label = _NAME_TYPES[node_type][1] |  | 
|  1016             hint = '' |  | 
|  1017             if self.config.include_naming_hint: |  | 
|  1018                 hint = ' (hint: %s)' % (getattr(self.config, node_type + '_name_
      hint')) |  | 
|  1019             self.add_message('invalid-name', node=node, args=(type_label, name, 
      hint)) |  | 
|  1020             self.stats['badname_' + node_type] += 1 |   700             self.stats['badname_' + node_type] += 1 | 
|  1021  |   701  | 
|  1022  |   702  | 
|  1023 class DocStringChecker(_BasicChecker): |   703 class DocStringChecker(_BasicChecker): | 
|  1024     msgs = { |   704     msgs = { | 
|  1025         'C0111': ('Missing %s docstring', # W0131 |   705     'C0111': ('Missing docstring', # W0131 | 
|  1026                   'missing-docstring', |   706               'Used when a module, function, class or method has no docstring.\ | 
|  1027                   'Used when a module, function, class or method has no docstrin
      g.' |   707               Some special methods like __init__ doesn\'t necessary require a \ | 
|  1028                   'Some special methods like __init__ doesn\'t necessary require
       a ' |   708               docstring.'), | 
|  1029                   'docstring.'), |   709     'C0112': ('Empty docstring', # W0132 | 
|  1030         'C0112': ('Empty %s docstring', # W0132 |   710               'Used when a module, function, class or method has an empty \ | 
|  1031                   'empty-docstring', |   711               docstring (it would be too easy ;).'), | 
|  1032                   'Used when a module, function, class or method has an empty ' |   712     } | 
|  1033                   'docstring (it would be too easy ;).'), |  | 
|  1034         } |  | 
|  1035     options = (('no-docstring-rgx', |   713     options = (('no-docstring-rgx', | 
|  1036                 {'default' : NO_REQUIRED_DOC_RGX, |   714                 {'default' : NO_REQUIRED_DOC_RGX, | 
|  1037                  'type' : 'regexp', 'metavar' : '<regexp>', |   715                  'type' : 'regexp', 'metavar' : '<regexp>', | 
|  1038                  'help' : 'Regular expression which should only match ' |   716                  'help' : 'Regular expression which should only match ' | 
|  1039                           'function or class names that do not require a ' |   717                           'functions or classes name which do not require a ' | 
|  1040                           'docstring.'} |   718                           'docstring'} | 
|  1041                ), |   719                 ), | 
|  1042                ('docstring-min-length', |   720                ) | 
|  1043                 {'default' : -1, |  | 
|  1044                  'type' : 'int', 'metavar' : '<int>', |  | 
|  1045                  'help': ('Minimum line length for functions/classes that' |  | 
|  1046                           ' require docstrings, shorter ones are exempt.')} |  | 
|  1047                ), |  | 
|  1048               ) |  | 
|  1049  |  | 
|  1050  |   721  | 
|  1051     def open(self): |   722     def open(self): | 
|  1052         self.stats = self.linter.add_stats(undocumented_module=0, |   723         self.stats = self.linter.add_stats(undocumented_module=0, | 
|  1053                                            undocumented_function=0, |   724                                            undocumented_function=0, | 
|  1054                                            undocumented_method=0, |   725                                            undocumented_method=0, | 
|  1055                                            undocumented_class=0) |   726                                            undocumented_class=0) | 
|  1056     @check_messages('missing-docstring', 'empty-docstring') |   727  | 
|  1057     def visit_module(self, node): |   728     def visit_module(self, node): | 
|  1058         self._check_docstring('module', node) |   729         self._check_docstring('module', node) | 
|  1059  |   730  | 
|  1060     @check_messages('missing-docstring', 'empty-docstring') |  | 
|  1061     def visit_class(self, node): |   731     def visit_class(self, node): | 
|  1062         if self.config.no_docstring_rgx.match(node.name) is None: |   732         if self.config.no_docstring_rgx.match(node.name) is None: | 
|  1063             self._check_docstring('class', node) |   733             self._check_docstring('class', node) | 
|  1064     @check_messages('missing-docstring', 'empty-docstring') |   734  | 
|  1065     def visit_function(self, node): |   735     def visit_function(self, node): | 
|  1066         if self.config.no_docstring_rgx.match(node.name) is None: |   736         if self.config.no_docstring_rgx.match(node.name) is None: | 
|  1067             ftype = node.is_method() and 'method' or 'function' |   737             ftype = node.is_method() and 'method' or 'function' | 
|  1068             if isinstance(node.parent.frame(), astroid.Class): |   738             if isinstance(node.parent.frame(), astng.Class): | 
|  1069                 overridden = False |   739                 overridden = False | 
|  1070                 # check if node is from a method overridden by its ancestor |   740                 # check if node is from a method overridden by its ancestor | 
|  1071                 for ancestor in node.parent.frame().ancestors(): |   741                 for ancestor in node.parent.frame().ancestors(): | 
|  1072                     if node.name in ancestor and \ |   742                     if node.name in ancestor and \ | 
|  1073                        isinstance(ancestor[node.name], astroid.Function): |   743                        isinstance(ancestor[node.name], astng.Function): | 
|  1074                         overridden = True |   744                         overridden = True | 
|  1075                         break |   745                         break | 
|  1076                 self._check_docstring(ftype, node, |   746                 if not overridden: | 
|  1077                                       report_missing=not overridden) |   747                     self._check_docstring(ftype, node) | 
|  1078             else: |   748             else: | 
|  1079                 self._check_docstring(ftype, node) |   749                 self._check_docstring(ftype, node) | 
|  1080  |   750  | 
|  1081     def _check_docstring(self, node_type, node, report_missing=True): |   751     def _check_docstring(self, node_type, node): | 
|  1082         """check the node has a non empty docstring""" |   752         """check the node has a non empty docstring""" | 
|  1083         docstring = node.doc |   753         docstring = node.doc | 
|  1084         if docstring is None: |   754         if docstring is None: | 
|  1085             if not report_missing: |  | 
|  1086                 return |  | 
|  1087             if node.body: |  | 
|  1088                 lines = node.body[-1].lineno - node.body[0].lineno + 1 |  | 
|  1089             else: |  | 
|  1090                 lines = 0 |  | 
|  1091             max_lines = self.config.docstring_min_length |  | 
|  1092  |  | 
|  1093             if node_type != 'module' and max_lines > -1 and lines < max_lines: |  | 
|  1094                 return |  | 
|  1095             self.stats['undocumented_'+node_type] += 1 |   755             self.stats['undocumented_'+node_type] += 1 | 
|  1096             if (node.body and isinstance(node.body[0], astroid.Discard) and |   756             self.add_message('C0111', node=node) | 
|  1097                 isinstance(node.body[0].value, astroid.CallFunc)): |  | 
|  1098                 # Most likely a string with a format call. Let's see. |  | 
|  1099                 func = safe_infer(node.body[0].value.func) |  | 
|  1100                 if (isinstance(func, astroid.BoundMethod) |  | 
|  1101                     and isinstance(func.bound, astroid.Instance)): |  | 
|  1102                     # Strings in Python 3, others in Python 2. |  | 
|  1103                     if PY3K and func.bound.name == 'str': |  | 
|  1104                         return |  | 
|  1105                     elif func.bound.name in ('str', 'unicode', 'bytes'): |  | 
|  1106                         return |  | 
|  1107             self.add_message('missing-docstring', node=node, args=(node_type,)) |  | 
|  1108         elif not docstring.strip(): |   757         elif not docstring.strip(): | 
|  1109             self.stats['undocumented_'+node_type] += 1 |   758             self.stats['undocumented_'+node_type] += 1 | 
|  1110             self.add_message('empty-docstring', node=node, args=(node_type,)) |   759             self.add_message('C0112', node=node) | 
|  1111  |   760  | 
|  1112  |   761  | 
|  1113 class PassChecker(_BasicChecker): |   762 class PassChecker(_BasicChecker): | 
|  1114     """check if the pass statement is really necessary""" |   763     """check is the pass statement is really necessary""" | 
|  1115     msgs = {'W0107': ('Unnecessary pass statement', |   764     msgs = {'W0107': ('Unnecessary pass statement', | 
|  1116                       'unnecessary-pass', |  | 
|  1117                       'Used when a "pass" statement that can be avoided is ' |   765                       'Used when a "pass" statement that can be avoided is ' | 
|  1118                       'encountered.'), |   766                       'encountered.)'), | 
|  1119            } |   767             } | 
|  1120     @check_messages('unnecessary-pass') |   768  | 
|  1121     def visit_pass(self, node): |   769     def visit_pass(self, node): | 
|  1122         if len(node.parent.child_sequence(node)) > 1: |   770         if len(node.parent.child_sequence(node)) > 1: | 
|  1123             self.add_message('unnecessary-pass', node=node) |   771             self.add_message('W0107', node=node) | 
|  1124  |  | 
|  1125  |  | 
|  1126 class LambdaForComprehensionChecker(_BasicChecker): |  | 
|  1127     """check for using a lambda where a comprehension would do. |  | 
|  1128  |  | 
|  1129     See <http://www.artima.com/weblogs/viewpost.jsp?thread=98196> |  | 
|  1130     where GvR says comprehensions would be clearer. |  | 
|  1131     """ |  | 
|  1132  |  | 
|  1133     msgs = {'W0110': ('map/filter on lambda could be replaced by comprehension', |  | 
|  1134                       'deprecated-lambda', |  | 
|  1135                       'Used when a lambda is the first argument to "map" or ' |  | 
|  1136                       '"filter". It could be clearer as a list ' |  | 
|  1137                       'comprehension or generator expression.', |  | 
|  1138                       {'maxversion': (3, 0)}), |  | 
|  1139            } |  | 
|  1140  |  | 
|  1141     @check_messages('deprecated-lambda') |  | 
|  1142     def visit_callfunc(self, node): |  | 
|  1143         """visit a CallFunc node, check if map or filter are called with a |  | 
|  1144         lambda |  | 
|  1145         """ |  | 
|  1146         if not node.args: |  | 
|  1147             return |  | 
|  1148         if not isinstance(node.args[0], astroid.Lambda): |  | 
|  1149             return |  | 
|  1150         infered = safe_infer(node.func) |  | 
|  1151         if (is_builtin_object(infered) |  | 
|  1152                 and infered.name in ['map', 'filter']): |  | 
|  1153             self.add_message('deprecated-lambda', node=node) |  | 
|  1154  |   772  | 
|  1155  |   773  | 
|  1156 def register(linter): |   774 def register(linter): | 
|  1157     """required method to auto register this checker""" |   775     """required method to auto register this checker""" | 
|  1158     linter.register_checker(BasicErrorChecker(linter)) |   776     linter.register_checker(BasicErrorChecker(linter)) | 
|  1159     linter.register_checker(BasicChecker(linter)) |   777     linter.register_checker(BasicChecker(linter)) | 
|  1160     linter.register_checker(NameChecker(linter)) |   778     linter.register_checker(NameChecker(linter)) | 
|  1161     linter.register_checker(DocStringChecker(linter)) |   779     linter.register_checker(DocStringChecker(linter)) | 
|  1162     linter.register_checker(PassChecker(linter)) |   780     linter.register_checker(PassChecker(linter)) | 
|  1163     linter.register_checker(LambdaForComprehensionChecker(linter)) |  | 
| OLD | NEW |