1
0
forked from VimPlug/jedi

Way better support for instantiated classes in REPL

Fixes several issues:

- It was not possible to correctly trace where instances were coming from in a
  REPL. This led to them being pretty much ignored.
- Instances were then just treated as classes and not as actual instances in
  MixedObjects. (However since they were ignored in the first place this
  wasn't really an issue).
- Avoiding the repr bug https://github.com/python/cpython/pull/2132/files in
  Jedi is working a bit differently. We're just never accessing Objects
  directly. This should work around 99.99% of the cases were people are using
  this stuff.

Fixes #872
This commit is contained in:
Dave Halter
2017-09-15 01:55:00 +02:00
parent 63edbdcc5b
commit 9dd2027299
4 changed files with 60 additions and 11 deletions

View File

@@ -11,6 +11,7 @@ from jedi.cache import underscore_memoization
from jedi.evaluate import imports
from jedi.evaluate.context import Context
from jedi.evaluate.cache import evaluator_function_cache
from jedi.evaluate.compiled.getattr_static import getattr_static
class MixedObject(object):
@@ -77,13 +78,14 @@ class MixedName(compiled.CompiledName):
def infer(self):
obj = self.parent_context.obj
try:
# TODO use logic from compiled.CompiledObjectFilter
obj = getattr(obj, self.string_name)
except AttributeError:
# Happens e.g. in properties of
# PyQt4.QtGui.QStyleOptionComboBox.currentText
# -> just set it to None
obj = None
return [create(self._evaluator, obj, parent_context=self.parent_context)]
return [_create(self._evaluator, obj, parent_context=self.parent_context)]
@property
def api_type(self):
@@ -116,21 +118,26 @@ def _load_module(evaluator, path, python_object):
return module
def source_findable(python_object):
def _get_object_to_check(python_object):
"""Check if inspect.getfile has a chance to find the source."""
return (inspect.ismodule(python_object) or
if (inspect.ismodule(python_object) or
inspect.isclass(python_object) or
inspect.ismethod(python_object) or
inspect.isfunction(python_object) or
inspect.istraceback(python_object) or
inspect.isframe(python_object) or
inspect.iscode(python_object))
inspect.iscode(python_object)):
return python_object
try:
return python_object.__class__
except AttributeError:
raise TypeError # Prevents computation of `repr` within inspect.
def find_syntax_node_name(evaluator, python_object):
try:
if not source_findable(python_object):
raise TypeError # Prevents computation of `repr` within inspect.
python_object = _get_object_to_check(python_object)
path = inspect.getsourcefile(python_object)
except TypeError:
# The type might not be known (e.g. class_with_dict.__weakref__)
@@ -188,7 +195,7 @@ def find_syntax_node_name(evaluator, python_object):
@compiled.compiled_objects_cache('mixed_cache')
def create(evaluator, obj, parent_context=None, *args):
def _create(evaluator, obj, parent_context=None, *args):
tree_node, path = find_syntax_node_name(evaluator, obj)
compiled_object = compiled.create(
@@ -210,6 +217,10 @@ def create(evaluator, obj, parent_context=None, *args):
node_is_context=True,
node_is_object=True
)
if tree_node.type == 'classdef':
if not isinstance(obj, type):
# Is an instance, not a class.
tree_context, = tree_context.execute_evaluated()
return MixedObject(
evaluator,