summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMads Kiilerich <mads@kiilerich.com>2009-01-18 16:04:44 +0100
committerMads Kiilerich <mads@kiilerich.com>2009-01-18 16:04:44 +0100
commit466af879a36bad38c830c0c09ee10d7a93ae9624 (patch)
tree42a3a5cb74578f823229428bc2d709669e429987
parent45694b2338d18291cb3d1931cd0434cab8aa65e6 (diff)
downloadpylint-466af879a36bad38c830c0c09ee10d7a93ae9624.tar.gz
Decorators of methods should see the class namespace
- just like default values does but the body doesn't. Fixes https://www.logilab.net/elo/ticket/3711 - bug finding decorator arguments https://www.logilab.net/elo/ticket/5626 - name resolution bug inside classes
-rw-r--r--checkers/utils.py12
-rw-r--r--checkers/variables.py8
-rw-r--r--test/input/func_noerror_decorator_scope.py16
3 files changed, 31 insertions, 5 deletions
diff --git a/checkers/utils.py b/checkers/utils.py
index 036a4cd..860999d 100644
--- a/checkers/utils.py
+++ b/checkers/utils.py
@@ -136,7 +136,17 @@ def is_func_default(node):
node in parent.defaults:
return 1
return is_func_default(parent)
-
+
+def is_func_decorator(node):
+ """return true if the name is used in function decorator
+ """
+ parent = node.parent
+ if parent is None:
+ return 0
+ if isinstance(parent, astng.Decorators):
+ return 1
+ return is_func_decorator(parent)
+
def is_ancestor_name(frame, node):
"""return True if `frame` is a astng.Class node with `node` in the
subtree of its bases attribute
diff --git a/checkers/variables.py b/checkers/variables.py
index a3b1501..d57df66 100644
--- a/checkers/variables.py
+++ b/checkers/variables.py
@@ -24,7 +24,7 @@ from logilab.astng.lookup import builtin_lookup
from pylint.interfaces import IASTNGChecker
from pylint.checkers import BaseChecker
-from pylint.checkers.utils import is_error, is_builtin, is_func_default, \
+from pylint.checkers.utils import is_error, is_builtin, is_func_default, is_func_decorator, \
is_ancestor_name, assign_parent, are_exclusive, \
is_defined_before #, is_parent, FOR_NODE_TYPES
@@ -326,10 +326,10 @@ builtins. Remember that you should avoid to define new builtins when possible.'
name = node.name
stmt = node.statement()
frame = stmt.scope()
- # if the name node is used as a function default argument's value, then
+ # if the name node is used as a function default argument's value or as a decorator, then
# start from the parent frame of the function instead of the function
- # frame
- if is_func_default(node) or is_ancestor_name(frame, node):
+ # frame - and thus open an inner class scope
+ if is_func_default(node) or is_func_decorator(node) or is_ancestor_name(frame, node):
start_index = len(self._to_consume) - 2
else:
start_index = len(self._to_consume) - 1
diff --git a/test/input/func_noerror_decorator_scope.py b/test/input/func_noerror_decorator_scope.py
new file mode 100644
index 0000000..1d21522
--- /dev/null
+++ b/test/input/func_noerror_decorator_scope.py
@@ -0,0 +1,16 @@
+"""Test that decorators sees the class namespace - just like
+function default values does but function body doesn't.
+
+https://www.logilab.net/elo/ticket/3711 - bug finding decorator arguments
+https://www.logilab.net/elo/ticket/5626 - name resolution bug inside classes
+"""
+
+class Test:
+
+ ident = lambda x: x
+
+ @ident(ident)
+ def f(self, val=ident(7), f=ident):
+ return f(val)
+
+print Test().f()