Skip to content

Commit ce0ed07

Browse files
Merge pull request plotly#3386 from plotly/json_remove_sort_keys
Do not sort keys during json serialization
2 parents 0a83329 + c25e710 commit ce0ed07

File tree

7 files changed

+26
-14
lines changed

7 files changed

+26
-14
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## [next] - ???
6+
7+
### Fixed
8+
- Fixed error when serializing dict with mix of string and non-string keys [#3380](https://github.com/plotly/plotly.py/issues/3380)
9+
10+
### Updated
11+
- The JSON serialization engines no longer sort their keys [#3380](https://github.com/plotly/plotly.py/issues/3380)
12+
513
## [5.3.1] - 2021-08-31
614

715
### Updated

packages/python/plotly/plotly/io/_json.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def to_json_plotly(plotly_object, pretty=False, engine=None):
112112
# Dump to a JSON string and return
113113
# --------------------------------
114114
if engine == "json":
115-
opts = {"sort_keys": True}
115+
opts = {}
116116
if pretty:
117117
opts["indent"] = 2
118118
else:
@@ -124,7 +124,7 @@ def to_json_plotly(plotly_object, pretty=False, engine=None):
124124
return json.dumps(plotly_object, cls=PlotlyJSONEncoder, **opts)
125125
elif engine == "orjson":
126126
JsonConfig.validate_orjson()
127-
opts = orjson.OPT_SORT_KEYS | orjson.OPT_SERIALIZE_NUMPY
127+
opts = orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY
128128

129129
if pretty:
130130
opts |= orjson.OPT_INDENT_2
@@ -462,7 +462,7 @@ def clean_to_json_compatible(obj, **kwargs):
462462
return obj
463463

464464
if isinstance(obj, dict):
465-
return {str(k): clean_to_json_compatible(v, **kwargs) for k, v in obj.items()}
465+
return {k: clean_to_json_compatible(v, **kwargs) for k, v in obj.items()}
466466
elif isinstance(obj, (list, tuple)):
467467
if obj:
468468
# Must process list recursively even though it may be slow

packages/python/plotly/plotly/tests/test_core/test_graph_objs/test_template.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ def test_move_nested_trace_properties(self):
356356
},
357357
)
358358

359-
self.assertEqual(pio.to_json(templated_fig), pio.to_json(expected_fig))
359+
self.assertEqual(templated_fig.to_dict(), expected_fig.to_dict())
360360

361361
def test_move_nested_trace_properties_existing_traces(self):
362362
fig = go.Figure(

packages/python/plotly/plotly/tests/test_io/test_deepcopy_pickle.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def test_deepcopy_figure(fig1):
3838
fig_copied = copy.deepcopy(fig1)
3939

4040
# Contents should be equal
41-
assert pio.to_json(fig_copied) == pio.to_json(fig1)
41+
assert fig_copied.to_dict() == fig1.to_dict()
4242

4343
# Identities should be distinct
4444
assert fig_copied is not fig1
@@ -50,7 +50,7 @@ def test_deepcopy_figure_subplots(fig_subplots):
5050
fig_copied = copy.deepcopy(fig_subplots)
5151

5252
# Contents should be equal
53-
assert pio.to_json(fig_copied) == pio.to_json(fig_subplots)
53+
assert fig_copied.to_dict() == fig_subplots.to_dict()
5454

5555
# Subplot metadata should be equal
5656
assert fig_subplots._grid_ref == fig_copied._grid_ref
@@ -66,7 +66,7 @@ def test_deepcopy_figure_subplots(fig_subplots):
6666
fig_copied.add_bar(y=[0, 0, 1], row=1, col=2)
6767

6868
# And contents should be still equal
69-
assert pio.to_json(fig_copied) == pio.to_json(fig_subplots)
69+
assert fig_copied.to_dict() == fig_subplots.to_dict()
7070

7171

7272
def test_deepcopy_layout(fig1):
@@ -91,21 +91,21 @@ def test_pickle_figure_round_trip(fig1):
9191
fig_copied = pickle.loads(pickle.dumps(fig1))
9292

9393
# Contents should be equal
94-
assert pio.to_json(fig_copied) == pio.to_json(fig1)
94+
assert fig_copied.to_dict() == fig1.to_dict()
9595

9696

9797
def test_pickle_figure_subplots_round_trip(fig_subplots):
9898
fig_copied = pickle.loads(pickle.dumps(fig_subplots))
9999

100100
# Contents should be equal
101-
assert pio.to_json(fig_copied) == pio.to_json(fig_subplots)
101+
assert fig_copied.to_dict() == fig_subplots.to_dict()
102102

103103
# Should be possible to add new trace to subplot location
104104
fig_subplots.add_bar(y=[0, 0, 1], row=1, col=2)
105105
fig_copied.add_bar(y=[0, 0, 1], row=1, col=2)
106106

107107
# And contents should be still equal
108-
assert pio.to_json(fig_copied) == pio.to_json(fig_subplots)
108+
assert fig_copied.to_dict() == fig_subplots.to_dict()
109109

110110

111111
def test_pickle_layout(fig1):

packages/python/plotly/plotly/tests/test_io/test_to_from_json.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ def fig1(request):
2929
opts = {
3030
"separators": (",", ":"),
3131
"cls": plotly.utils.PlotlyJSONEncoder,
32-
"sort_keys": True,
3332
}
34-
pretty_opts = {"indent": 2, "cls": plotly.utils.PlotlyJSONEncoder, "sort_keys": True}
33+
pretty_opts = {"indent": 2, "cls": plotly.utils.PlotlyJSONEncoder}
3534

3635

3736
# to_json

packages/python/plotly/plotly/tests/test_io/test_to_from_plotly_json.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def datetime_array(request, datetime_value):
135135
def test_graph_object_input(engine, pretty):
136136
scatter = go.Scatter(x=[1, 2, 3], y=np.array([4, 5, 6]))
137137
result = pio.to_json_plotly(scatter, engine=engine)
138-
expected = """{"type":"scatter","x":[1,2,3],"y":[4,5,6]}"""
138+
expected = """{"x":[1,2,3],"y":[4,5,6],"type":"scatter"}"""
139139
assert result == expected
140140
check_roundtrip(result, engine=engine, pretty=pretty)
141141

@@ -215,3 +215,9 @@ def test_nonstring_key(engine, pretty):
215215
value = build_test_dict({0: 1})
216216
result = pio.to_json_plotly(value, engine=engine)
217217
check_roundtrip(result, engine=engine, pretty=pretty)
218+
219+
220+
def test_mixed_string_nonstring_key(engine, pretty):
221+
value = build_test_dict({0: 1, "a": 2})
222+
result = pio.to_json_plotly(value, engine=engine)
223+
check_roundtrip(result, engine=engine, pretty=pretty)

packages/python/plotly/plotly/tests/test_optional/test_offline/test_offline.py

-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ def test_default_mpl_plot_generates_expected_html(self):
8989
# just make sure a few of the parts are in here
9090
# like PlotlyOfflineTestCase(TestCase) in test_core
9191
self.assertTrue(data_json in html) # data is in there
92-
self.assertTrue(layout_json in html) # layout is in there too
9392
self.assertTrue(PLOTLYJS in html) # and the source code
9493
# and it's an <html> doc
9594
self.assertTrue(html.startswith("<html>") and html.endswith("</html>"))

0 commit comments

Comments
 (0)