Skip to content

Commit ff60db4

Browse files
Paweł Andruszkiewiczrennox
authored andcommitted
BUG#35450521 Unable to use json.dumps with Shell dictionaries
Fix Python's dictionary wrapper: update item count in the base PyDictObject structure to keep it in sync with the wrapped Map object. Change-Id: I8c6bdac1ef749df7df2afc4437d6f7b50090fed5
1 parent 3e942bb commit ff60db4

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

mysqlshdk/scripting/python_map_wrapper.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2022, Oracle and/or its affiliates.
2+
* Copyright (c) 2015, 2023, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify
55
* it under the terms of the GNU General Public License, version 2.0,
@@ -1651,6 +1651,7 @@ PyObject *size_of(dict::Object *self) {
16511651
*/
16521652
PyObject *clear(dict::Object *self) {
16531653
self->dict->get()->clear();
1654+
self->base.ma_used = 0;
16541655
Py_RETURN_NONE;
16551656
}
16561657

@@ -1712,6 +1713,11 @@ PyObject *from_keys(PyTypeObject *type, PyObject *args) {
17121713
}
17131714
}
17141715

1716+
if (is_shell_dict) {
1717+
const auto shdict = reinterpret_cast<dict::Object *>(dict.get());
1718+
shdict->base.ma_used = length(shdict);
1719+
}
1720+
17151721
return dict.release();
17161722
}
17171723

@@ -1799,6 +1805,7 @@ PyObject *pop(dict::Object *self, PyObject *args) {
17991805
auto ret = py::convert(result->second);
18001806

18011807
self->dict->get()->erase(result);
1808+
--self->base.ma_used;
18021809

18031810
return ret.release();
18041811
}
@@ -1840,6 +1847,7 @@ PyObject *pop_item(dict::Object *self) {
18401847
}
18411848

18421849
self->dict->get()->erase(item);
1850+
--self->base.ma_used;
18431851

18441852
return result.release();
18451853
}
@@ -1866,6 +1874,7 @@ PyObject *set_default(dict::Object *self, PyObject *args) {
18661874
return py::convert(result->second).release();
18671875
} else {
18681876
self->dict->get()->set(key_to_find, py::convert(default_value));
1877+
++self->base.ma_used;
18691878

18701879
Py_INCREF(default_value);
18711880
return default_value;
@@ -1893,6 +1902,7 @@ PyObject *set_default(dict::Object *self, PyObject *args) {
18931902
PyObject *update(dict::Object *self, PyObject *args, PyObject *kwds) {
18941903
try {
18951904
if (update(self, args, kwds, "update")) {
1905+
self->base.ma_used = length(self);
18961906
Py_RETURN_NONE;
18971907
}
18981908
} catch (const std::exception &exc) {
@@ -2023,6 +2033,7 @@ int init(dict::Object *self, PyObject *args, PyObject *kwds) {
20232033

20242034
try {
20252035
if (update(self, args, kwds, "Dict")) {
2036+
self->base.ma_used = length(self);
20262037
return 0;
20272038
}
20282039
} catch (const std::exception &exc) {
@@ -2594,6 +2605,7 @@ py::Release wrap(const Dictionary_t &map) {
25942605

25952606
assert(!wrapper->dict);
25962607
wrapper->dict = new Dictionary_t(map);
2608+
wrapper->base.ma_used = length(wrapper);
25972609

25982610
return py::Release{reinterpret_cast<PyObject *>(wrapper)};
25992611
}

unittest/scripts/auto/py_shell/scripts/dict_norecord.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
## imports
2+
import json
23
import pickle
34
import random
45
import sys
@@ -2502,3 +2503,6 @@ def assign_none_to_mapping():
25022503
EXPECT_EQ('{"one": 1, "three": 3, "two": 2}', str(actual.mapping))
25032504

25042505
EXPECT_THROWS(assign_none_to_mapping, "AttributeError: attribute 'mapping' of 'Dict_values' objects is not writable")
2506+
2507+
#@<> json
2508+
EXPECT_EQ('{"one": 1, "three": 3, "two": 2}', json.dumps(shdict({'three': 3, 'one': 1, 'two': 2})))

0 commit comments

Comments
 (0)