Skip to content

Commit

Permalink
Consider that __class__ may not really be what we expect. Fixes #699
Browse files Browse the repository at this point in the history
  • Loading branch information
fabioz committed Sep 24, 2021
1 parent 869babb commit 02f3792
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_comm.py
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,7 @@ def internal_get_variable_json(py_db, request):
'name': '<error>',
'value': err,
'type': '<error>',
'variablesReference': 0
}]
except:
err = '<Internal error - unable to get traceback when getting variables>'
Expand Down
18 changes: 14 additions & 4 deletions src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,29 @@ def get_type(self, o):
try:
try:
# Faster than type(o) as we don't need the function call.
type_object = o.__class__
type_object = o.__class__ # could fail here
type_name = type_object.__name__
return self._get_type(o, type_object, type_name) # could fail here
except:
# Not all objects have __class__ (i.e.: there are bad bindings around).
type_object = type(o)
type_name = type_object.__name__

type_name = type_object.__name__
try:
return self._get_type(o, type_object, type_name)
except:
if isinstance(type_object, type):
# If it's still something manageable, use the default resolver, otherwise
# fallback to saying that it wasn't possible to get any info on it.
return type_object, str(type_name), pydevd_resolver.defaultResolver

return 'Unable to get Type', 'Unable to get Type', None
except:
# This happens for org.python.core.InitModule
return 'Unable to get Type', 'Unable to get Type', None

return self._get_type(o, type_object, type_name)

def _get_type(self, o, type_object, type_name):
# Note: we could have an exception here if the type_object is not hashable...
resolver = self._type_to_resolver_cache.get(type_object)
if resolver is not None:
return type_object, type_name, resolver
Expand Down
34 changes: 34 additions & 0 deletions src/debugpy/_vendored/pydevd/tests_python/test_debugger_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -2613,6 +2613,40 @@ def test_set_variable_multiple_cases(case_setup, _check_func):
writer.finished_ok = True


def test_get_variables_corner_case(case_setup, pyfile):

@pyfile
def case_with_class_as_object():

class ClassField(object):
__name__ = 'name?'

def __hash__(self):
raise RuntimeError()

class SomeClass(object):
__class__ = ClassField()

some_class = SomeClass()
print('TEST SUCEEDED') # Break here

with case_setup.test_file(case_with_class_as_object) as writer:
json_facade = JsonFacade(writer)
json_facade.write_launch(justMyCode=False)
json_facade.write_set_breakpoints(writer.get_line_index_with_content('Break here'))

json_facade.write_make_initial_run()

json_hit = json_facade.wait_for_thread_stopped()

set_var = json_facade.get_local_var(json_hit.frame_id, 'some_class')
assert '__main__.SomeClass' in set_var.value

json_facade.write_continue()

writer.finished_ok = True


@pytest.mark.skipif(IS_JYTHON, reason='Putting unicode on frame vars does not work on Jython.')
def test_stack_and_variables(case_setup):

Expand Down

0 comments on commit 02f3792

Please sign in to comment.