diff options
author | Claudiu Popa <pcmanticore@gmail.com> | 2014-04-12 09:46:49 +0300 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2014-04-12 09:46:49 +0300 |
commit | bbb83b5b8356ef7432ed4741e171a483e88a49ee (patch) | |
tree | 10fbd880bed4fb5d367086f66749bc0b7f7a8d5e /scoped_nodes.py | |
parent | 9781343aa75f6425b4ea68ea9eb149770160dfba (diff) | |
download | astroid-git-bbb83b5b8356ef7432ed4741e171a483e88a49ee.tar.gz |
Unwrap instances found in `.ancestors()`, by using their _proxied class. Don't inherit the metaclass status if the current class can't be a metaclass.
--HG--
branch : ancestors
Diffstat (limited to 'scoped_nodes.py')
-rw-r--r-- | scoped_nodes.py | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/scoped_nodes.py b/scoped_nodes.py index b066cda7..b5956448 100644 --- a/scoped_nodes.py +++ b/scoped_nodes.py @@ -666,6 +666,28 @@ def _rec_get_names(args, names=None): # Class ###################################################################### + +def _is_metaclass(klass): + """ Return if the given class can be + used as a metaclass. + """ + if klass.name == 'type': + return True + for base in klass.bases: + try: + for baseobj in base.infer(): + if isinstance(baseobj, Instance): + # not abstract + return False + if baseobj is YES: + continue + if _is_metaclass(baseobj): + return True + except InferenceError: + continue + return False + + def _class_type(klass, ancestors=None): """return a Class node type to differ metaclass, interface and exception from 'regular' classes @@ -673,7 +695,7 @@ def _class_type(klass, ancestors=None): # XXX we have to store ancestors in case we have a ancestor loop if klass._type is not None: return klass._type - if klass.name == 'type': + if _is_metaclass(klass): klass._type = 'metaclass' elif klass.name.endswith('Interface'): klass._type = 'interface' @@ -689,9 +711,14 @@ def _class_type(klass, ancestors=None): ancestors.add(klass) # print >> sys.stderr, '_class_type', repr(klass) for base in klass.ancestors(recurs=False): - if _class_type(base, ancestors) != 'class': - klass._type = base.type - break + name = _class_type(base, ancestors) + if name != 'class': + if name == 'metaclass' and not _is_metaclass(klass): + # don't propagate it if the current class + # can't be a metaclass + continue + klass._type = base.type + break if klass._type is None: klass._type = 'class' return klass._type @@ -811,8 +838,11 @@ class Class(Statement, LocalsDictNodeNG, FilterStmtsMixin): try: for baseobj in stmt.infer(context): if not isinstance(baseobj, Class): - # duh ? - continue + if isinstance(baseobj, Instance): + baseobj = baseobj._proxied + else: + # duh ? + continue if baseobj in yielded: continue # cf xxx above yielded.add(baseobj) |