From a7c21eff4bf08688f85c096050b45482bd6d81fa Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sat, 1 Dec 2018 15:24:21 +0100 Subject: [PATCH] Move py__mro__ to ClassMixin --- jedi/evaluate/context/klass.py | 94 ++++++++++++++++------------------ 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/jedi/evaluate/context/klass.py b/jedi/evaluate/context/klass.py index 563d8960..0690e59c 100644 --- a/jedi/evaluate/context/klass.py +++ b/jedi/evaluate/context/klass.py @@ -60,53 +60,6 @@ def apply_py__get__(context, instance, class_context): yield descriptor_context -@evaluator_method_cache(default=()) -def py__mro__(context): - try: - # TODO is this really needed? - method = context.py__mro__ - except AttributeError: - pass - else: - if not isinstance(context, ClassMixin): - # Currently only used for compiled objects. - return method() - - def add(cls): - if cls not in mro: - mro.append(cls) - - mro = [context] - # TODO Do a proper mro resolution. Currently we are just listing - # classes. However, it's a complicated algorithm. - for lazy_cls in context.py__bases__(): - # TODO there's multiple different mro paths possible if this yields - # multiple possibilities. Could be changed to be more correct. - for cls in lazy_cls.infer(): - # TODO detect for TypeError: duplicate base class str, - # e.g. `class X(str, str): pass` - try: - cls.py__bases__ - except AttributeError: - # TODO add a TypeError like: - """ - >>> class Y(lambda: test): pass - Traceback (most recent call last): - File "", line 1, in - TypeError: function() argument 1 must be code, not str - >>> class Y(1): pass - Traceback (most recent call last): - File "", line 1, in - TypeError: int() takes at most 2 arguments (3 given) - """ - debug.warning('Super class of %s is not a class: %s', context, cls) - else: - add(cls) - for cls_new in cls.py__mro__(): - add(cls_new) - return tuple(mro) - - class ClassName(TreeNameDefinition): def __init__(self, parent_context, tree_name, name_context, apply_decorators): super(ClassName, self).__init__(parent_context, tree_name) @@ -188,8 +141,51 @@ class ClassMixin(object): return list(context_.get_param_names())[1:] return [] - def py__mro__(self): - return py__mro__(self) + @evaluator_method_cache(default=()) + def py__mro__(context): + try: + # TODO is this really needed? + method = context.py__mro__ + except AttributeError: + pass + else: + if not isinstance(context, ClassMixin): + # Currently only used for compiled objects. + return method() + + def add(cls): + if cls not in mro: + mro.append(cls) + + mro = [context] + # TODO Do a proper mro resolution. Currently we are just listing + # classes. However, it's a complicated algorithm. + for lazy_cls in context.py__bases__(): + # TODO there's multiple different mro paths possible if this yields + # multiple possibilities. Could be changed to be more correct. + for cls in lazy_cls.infer(): + # TODO detect for TypeError: duplicate base class str, + # e.g. `class X(str, str): pass` + try: + cls.py__bases__ + except AttributeError: + # TODO add a TypeError like: + """ + >>> class Y(lambda: test): pass + Traceback (most recent call last): + File "", line 1, in + TypeError: function() argument 1 must be code, not str + >>> class Y(1): pass + Traceback (most recent call last): + File "", line 1, in + TypeError: int() takes at most 2 arguments (3 given) + """ + debug.warning('Super class of %s is not a class: %s', context, cls) + else: + add(cls) + for cls_new in cls.py__mro__(): + add(cls_new) + return tuple(mro) def _create_class_filter(self, cls, origin_scope, is_instance): return ClassFilter(