diff options
author | cpopa <devnull@localhost> | 2014-07-01 13:35:52 +0300 |
---|---|---|
committer | cpopa <devnull@localhost> | 2014-07-01 13:35:52 +0300 |
commit | 7f71cbb5cc39d981a544c6a1af50521a132ba44d (patch) | |
tree | 6dec69182bcedb55d0b5d952ebc005eaf070557e | |
parent | f607ae828edb94f36732ca2797c5b010e1a49fa4 (diff) | |
download | pylint-7f71cbb5cc39d981a544c6a1af50521a132ba44d.tar.gz |
Emit attribute-defined-outside-init for all cases, not just for the last assignment. Closes issue #262.
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | checkers/classes.py | 44 | ||||
-rw-r--r-- | test/input/func_defining-attr-methods_order.py | 8 | ||||
-rw-r--r-- | test/messages/func_defining-attr-methods_order.txt | 2 |
4 files changed, 36 insertions, 21 deletions
@@ -15,6 +15,9 @@ ChangeLog for Pylint * Issue broad-except and bare-except even if the number of except handlers is different than 1. Fixes issue #113. + * Issue attribute-defined-outside-init for all cases, not just + for the last assignment. Closes issue #262. + 2014-04-30 -- 1.2.1 * Restore the ability to specify the init-hook option via the configuration file, which was accidentally broken in 1.2.0. diff --git a/checkers/classes.py b/checkers/classes.py index f5e2783..02d304b 100644 --- a/checkers/classes.py +++ b/checkers/classes.py @@ -272,28 +272,30 @@ a metaclass class method.'} isinstance(n.statement(), (astroid.Delete, astroid.AugAssign))] if not nodes: continue # error detected by typechecking - attr_defined = False # check if any method attr is defined in is a defining method - for node in nodes: - if node.frame().name in defining_methods: - attr_defined = True - if not attr_defined: - # check attribute is defined in a parent's __init__ - for parent in cnode.instance_attr_ancestors(attr): - attr_defined = False - # check if any parent method attr is defined in is a defining method - for node in parent.instance_attrs[attr]: - if node.frame().name in defining_methods: - attr_defined = True - if attr_defined: - # we're done :) - break - else: - # check attribute is defined as a class attribute - try: - cnode.local_attr(attr) - except astroid.NotFoundError: - self.add_message('attribute-defined-outside-init', args=attr, node=node) + if any(node.frame().name in defining_methods + for node in nodes): + continue + + # check attribute is defined in a parent's __init__ + for parent in cnode.instance_attr_ancestors(attr): + attr_defined = False + # check if any parent method attr is defined in is a defining method + for node in parent.instance_attrs[attr]: + if node.frame().name in defining_methods: + attr_defined = True + if attr_defined: + # we're done :) + break + else: + # check attribute is defined as a class attribute + try: + cnode.local_attr(attr) + except astroid.NotFoundError: + for node in nodes: + if node.frame().name not in defining_methods: + self.add_message('attribute-defined-outside-init', + args=attr, node=node) def visit_function(self, node): """check method arguments, overriding""" diff --git a/test/input/func_defining-attr-methods_order.py b/test/input/func_defining-attr-methods_order.py index d64217d..888b192 100644 --- a/test/input/func_defining-attr-methods_order.py +++ b/test/input/func_defining-attr-methods_order.py @@ -26,8 +26,16 @@ class A(object): def set_z(self, z): ''' set_z docstring filler ''' self.z = z + self.z = z def setUp(self): ''' setUp docstring filler ''' self.x = 0 self.y = 0 + +class B(A): + ''' class B ''' + + def test(self): + """ test """ + self.z = 44 diff --git a/test/messages/func_defining-attr-methods_order.txt b/test/messages/func_defining-attr-methods_order.txt index 3594754..5588319 100644 --- a/test/messages/func_defining-attr-methods_order.txt +++ b/test/messages/func_defining-attr-methods_order.txt @@ -1 +1,3 @@ W: 28:A.set_z: Attribute 'z' defined outside __init__ +W: 29:A.set_z: Attribute 'z' defined outside __init__ +W: 41:B.test: Attribute 'z' defined outside __init__ |