Skip to content

Commit

Permalink
Keep order of items in dictionary (Py3.6 onwards) or odict. Fixes mic…
Browse files Browse the repository at this point in the history
  • Loading branch information
fabioz committed Apr 1, 2020
1 parent 8fc238e commit 83d6914
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from os.path import basename

from functools import partial
from _pydevd_bundle.pydevd_constants import dict_iter_items, dict_keys, xrange
from _pydevd_bundle.pydevd_constants import dict_iter_items, dict_keys, xrange, IS_PY36_OR_GREATER
from _pydevd_bundle.pydevd_safe_repr import SafeRepr

# Note: 300 is already a lot to see in the outline (after that the user should really use the shell to get things)
Expand Down Expand Up @@ -241,6 +241,8 @@ def _get_py_dictionary(self, var, names=None, used___dict__=False):
#=======================================================================================================================
class DictResolver:

sort_keys = not IS_PY36_OR_GREATER

def resolve(self, dict, key):
if key in ('__len__', TOO_LARGE_ATTR):
return None
Expand Down Expand Up @@ -302,6 +304,9 @@ def get_contents_debug_adapter_protocol(self, dct, fmt=None):
if from_default_resolver:
ret = from_default_resolver + ret

if not self.sort_keys:
return ret

return sorted(ret, key=lambda tup: sorted_attributes_key(tup[0]))

def get_dictionary(self, dict):
Expand Down Expand Up @@ -580,6 +585,8 @@ def get_dictionary(self, var):
#=======================================================================================================================
class OrderedDictResolver(DictResolver):

sort_keys = False

def init_dict(self):
return OrderedDict()

Expand Down
7 changes: 7 additions & 0 deletions src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ def _create_default_type_map():
(list, pydevd_resolver.tupleResolver),
(dict, pydevd_resolver.dictResolver),
]
try:
from collections import OrderedDict
default_type_map.insert(0, (OrderedDict, pydevd_resolver.orderedDictResolver))
# we should put it before dict
except:
pass

try:
default_type_map.append((long, None)) # @UndefinedVariable
except:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
def check():
from collections import OrderedDict
import sys
# On 3.6 onwards, use a regular dict.
odict = OrderedDict() if sys.version_info[:2] < (3, 6) else {}
odict[4] = 'first'
odict[3] = 'second'
odict[2] = 'last'
print('break here')


if __name__ == '__main__':
check()
print('TEST SUCEEDED')
35 changes: 34 additions & 1 deletion src/debugpy/_vendored/pydevd/tests_python/test_debugger_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
InitializeRequestArguments, TerminateArguments, TerminateRequest, TerminatedEvent)
from _pydevd_bundle.pydevd_comm_constants import file_system_encoding
from _pydevd_bundle.pydevd_constants import (int_types, IS_64BIT_PROCESS,
PY_VERSION_STR, PY_IMPL_VERSION_STR, PY_IMPL_NAME, IS_PY36_OR_GREATER, IS_PY39_OR_GREATER)
PY_VERSION_STR, PY_IMPL_VERSION_STR, PY_IMPL_NAME, IS_PY36_OR_GREATER, IS_PY39_OR_GREATER,
IS_PY37_OR_GREATER)
from tests_python import debugger_unittest
from tests_python.debug_constants import TEST_CHERRYPY, IS_PY2, TEST_DJANGO, TEST_FLASK, IS_PY26, \
IS_PY27, IS_CPYTHON, TEST_GEVENT
Expand Down Expand Up @@ -1177,6 +1178,38 @@ def test_modules(case_setup):
writer.finished_ok = True


@pytest.mark.skipif(IS_PY26, reason='Python 2.6 does not have an ordered dict')
def test_dict_ordered(case_setup):
with case_setup.test_file('_debugger_case_odict.py') as writer:
json_facade = JsonFacade(writer)

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()
json_hit = json_facade.get_stack_as_json_hit(json_hit.thread_id)

variables_response = json_facade.get_variables_response(json_hit.frame_id)

variables_references = variables_response.body.variables
for dct in variables_references:
if dct['name'] == 'odict':
break
else:
raise AssertionError('Expected to find "odict".')
ref = dct['variablesReference']

assert isinstance(ref, int_types)
# : :type variables_response: VariablesResponse

variables_response = json_facade.get_variables_response(ref)
assert [(d['name'], d['value']) for d in variables_response.body.variables if not d['name'].startswith('_OrderedDict')] == [
('4', "'first'"), ('3', "'second'"), ('2', "'last'"), ('__len__', '3')]

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_dict(case_setup):
with case_setup.test_file('_debugger_case_local_variables.py') as writer:
Expand Down
7 changes: 6 additions & 1 deletion src/debugpy/_vendored/pydevd/tests_python/test_resolvers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from tests_python.debug_constants import IS_PY2
from _pydevd_bundle.pydevd_constants import IS_PY36_OR_GREATER


def check_len_entry(len_entry, first_2_params):
Expand All @@ -14,7 +15,11 @@ def test_dict_resolver():
contents_debug_adapter_protocol = dict_resolver.get_contents_debug_adapter_protocol(dct)
len_entry = contents_debug_adapter_protocol.pop(-1)
check_len_entry(len_entry, ('__len__', 2))
if IS_PY2:
if IS_PY36_OR_GREATER:
assert contents_debug_adapter_protocol == [
('(1, 2)', 2, '[(1, 2)]'), ("'22'", 22, "['22']")]

elif IS_PY2:
assert contents_debug_adapter_protocol == [
('(1, 2)', 2, '[(1, 2)]'), (u"u'22'", 22, u"[u'22']")]
else:
Expand Down

0 comments on commit 83d6914

Please sign in to comment.