summaryrefslogtreecommitdiff
path: root/scoped_nodes.py
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2014-05-07 17:14:48 +0300
committerClaudiu Popa <pcmanticore@gmail.com>2014-05-07 17:14:48 +0300
commitcd08d8724ec41f4630b143a62f0d4e5479ab0607 (patch)
tree436e1040e9de8e5f9f4dc58aa72dce1811deac9a /scoped_nodes.py
parentb13ef13e8365348b957e77105fdeeeb5bde69c49 (diff)
downloadastroid-git-cd08d8724ec41f4630b143a62f0d4e5479ab0607.tar.gz
Function nodes can detect if they are decorated with subclasses of builtin descriptors when determining their type (`classmethod` and `staticmethod`).
--HG-- branch : classmethod_subclasses
Diffstat (limited to 'scoped_nodes.py')
-rw-r--r--scoped_nodes.py34
1 files changed, 32 insertions, 2 deletions
diff --git a/scoped_nodes.py b/scoped_nodes.py
index 20bb664f..889baa0e 100644
--- a/scoped_nodes.py
+++ b/scoped_nodes.py
@@ -31,13 +31,13 @@ except ImportError:
from cStringIO import StringIO as BytesIO
from logilab.common.compat import builtins
-from logilab.common.decorators import cached
+from logilab.common.decorators import cached, cachedproperty
from astroid.exceptions import NotFoundError, \
AstroidBuildingException, InferenceError
from astroid.node_classes import Const, DelName, DelAttr, \
Dict, From, List, Pass, Raise, Return, Tuple, Yield, YieldFrom, \
- LookupMixIn, const_factory as cf, unpack_infer
+ LookupMixIn, const_factory as cf, unpack_infer, Name
from astroid.bases import NodeNG, InferenceContext, Instance,\
YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, copy_context, \
BUILTINS
@@ -476,6 +476,34 @@ else:
"""class representing a ListComp node"""
# Function ###################################################################
+
+def _function_type(self):
+ """
+ Function type, possible values are:
+ method, function, staticmethod, classmethod.
+ """
+ # Can't infer that this node is decorated
+ # with a subclass of `classmethod` where `type` is first set,
+ # so do it here.
+ if self.decorators:
+ for node in self.decorators.nodes:
+ if not isinstance(node, Name):
+ continue
+ try:
+ for infered in node.infer():
+ if not isinstance(infered, Class):
+ continue
+ for ancestor in infered.ancestors():
+ if isinstance(ancestor, Class):
+ if (ancestor.name == 'classmethod' and
+ ancestor.root().name == BUILTINS):
+ return 'classmethod'
+ elif (ancestor.name == 'staticmethod' and
+ ancestor.root().name == BUILTINS):
+ return 'staticmethod'
+ except InferenceError:
+ pass
+ return self._type
class Lambda(LocalsDictNodeNG, FilterStmtsMixin):
@@ -539,6 +567,8 @@ class Function(Statement, Lambda):
# attributes below are set by the builder module or by raw factories
blockstart_tolineno = None
decorators = None
+ _type = "function"
+ type = cachedproperty(_function_type)
def __init__(self, name, doc):
self.locals = {}