mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Merge pull request #96 from fabioz/ptvsd_998_dict_order
Keep order of items in dictionary (Py3.6 onwards) or odict.
This commit is contained in:
commit
cd803cc14b
6 changed files with 156 additions and 43 deletions
|
|
@ -8,7 +8,7 @@ import traceback
|
|||
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)
|
||||
|
|
@ -241,6 +241,8 @@ class DefaultResolver:
|
|||
#=======================================================================================================================
|
||||
class DictResolver:
|
||||
|
||||
sort_keys = not IS_PY36_OR_GREATER
|
||||
|
||||
def resolve(self, dict, key):
|
||||
if key in ('__len__', TOO_LARGE_ATTR):
|
||||
return None
|
||||
|
|
@ -302,6 +304,9 @@ class DictResolver:
|
|||
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):
|
||||
|
|
@ -580,6 +585,8 @@ class DequeResolver(TupleResolver):
|
|||
#=======================================================================================================================
|
||||
class OrderedDictResolver(DictResolver):
|
||||
|
||||
sort_keys = False
|
||||
|
||||
def init_dict(self):
|
||||
return OrderedDict()
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
@ -16,7 +16,8 @@ from _pydevd_bundle._debug_adapter.pydevd_schema import (ThreadEvent, ModuleEven
|
|||
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
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -166,7 +166,10 @@ def test_variable_sort(pyfile, target, run):
|
|||
"variables", {"variablesReference": b_test["variablesReference"]}
|
||||
)["variables"]
|
||||
var_names = [v["name"] for v in b_test_vars]
|
||||
assert var_names == ["'abcd'", "'eggs'", "'spam'", "__len__"]
|
||||
if sys.version_info[:2] >= (3, 6):
|
||||
assert var_names == ["'spam'", "'eggs'", "'abcd'", "__len__"]
|
||||
else:
|
||||
assert var_names == ["'abcd'", "'eggs'", "'spam'", "__len__"]
|
||||
|
||||
# Numeric dict keys must be sorted as numbers.
|
||||
if not "https://github.com/microsoft/ptvsd/issues/213":
|
||||
|
|
@ -394,45 +397,89 @@ def test_hex_numbers(pyfile, target, run):
|
|||
"variables",
|
||||
{"variablesReference": c["variablesReference"], "format": {"hex": True}},
|
||||
)["variables"]
|
||||
assert c_vars == [
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "0x3e8",
|
||||
"value": "0x3e8",
|
||||
"type": "int",
|
||||
"evaluateName": "c[1000]",
|
||||
"variablesReference": 0,
|
||||
}
|
||||
),
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "0x64",
|
||||
"value": "0x64",
|
||||
"type": "int",
|
||||
"evaluateName": "c[100]",
|
||||
"variablesReference": 0,
|
||||
}
|
||||
),
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "0xa",
|
||||
"value": "0xa",
|
||||
"type": "int",
|
||||
"evaluateName": "c[10]",
|
||||
"variablesReference": 0,
|
||||
}
|
||||
),
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "__len__",
|
||||
"value": "0x3",
|
||||
"type": "int",
|
||||
"evaluateName": "len(c)",
|
||||
"variablesReference": 0,
|
||||
"presentationHint": {"attributes": ["readOnly"]},
|
||||
}
|
||||
),
|
||||
]
|
||||
if sys.version_info[:2] < (3, 6):
|
||||
# Sorted dict keys by the name before Python 3.6.
|
||||
assert c_vars == [
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "0x3e8",
|
||||
"value": "0x3e8",
|
||||
"type": "int",
|
||||
"evaluateName": "c[1000]",
|
||||
"variablesReference": 0,
|
||||
}
|
||||
),
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "0x64",
|
||||
"value": "0x64",
|
||||
"type": "int",
|
||||
"evaluateName": "c[100]",
|
||||
"variablesReference": 0,
|
||||
}
|
||||
),
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "0xa",
|
||||
"value": "0xa",
|
||||
"type": "int",
|
||||
"evaluateName": "c[10]",
|
||||
"variablesReference": 0,
|
||||
}
|
||||
),
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "__len__",
|
||||
"value": "0x3",
|
||||
"type": "int",
|
||||
"evaluateName": "len(c)",
|
||||
"variablesReference": 0,
|
||||
"presentationHint": {"attributes": ["readOnly"]},
|
||||
}
|
||||
),
|
||||
]
|
||||
else:
|
||||
# Use dict sequence on Python 3.6 onwards.
|
||||
assert c_vars == [
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "0xa",
|
||||
"value": "0xa",
|
||||
"type": "int",
|
||||
"evaluateName": "c[10]",
|
||||
"variablesReference": 0,
|
||||
}
|
||||
),
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "0x64",
|
||||
"value": "0x64",
|
||||
"type": "int",
|
||||
"evaluateName": "c[100]",
|
||||
"variablesReference": 0,
|
||||
}
|
||||
),
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "0x3e8",
|
||||
"value": "0x3e8",
|
||||
"type": "int",
|
||||
"evaluateName": "c[1000]",
|
||||
"variablesReference": 0,
|
||||
}
|
||||
),
|
||||
some.dict.containing(
|
||||
{
|
||||
"name": "__len__",
|
||||
"value": "0x3",
|
||||
"type": "int",
|
||||
"evaluateName": "len(c)",
|
||||
"variablesReference": 0,
|
||||
"presentationHint": {"attributes": ["readOnly"]},
|
||||
}
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
d_vars = session.request(
|
||||
"variables",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue