Skip to content

Commit 9567ad1

Browse files
committed
fix: update ReadOnlyDict to match latest mozbuild vendor
The mozbuild version of ReadOnlyDict has a few extra dunder methods that allow copying and pickling it. This discrepency caused some regressions in mozilla-central when we switched over to using the Taskgraph version of it in bug 1901281. Bug: 1903576
1 parent 9a0ca1f commit 9567ad1

File tree

2 files changed

+69
-26
lines changed

2 files changed

+69
-26
lines changed

src/taskgraph/util/readonlydict.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
# You can obtain one at http://mozilla.org/MPL/2.0/.
44

55
# Imported from
6-
# https://searchfox.org/mozilla-central/rev/c3ebaf6de2d481c262c04bb9657eaf76bf47e2ac/python/mozbuild/mozbuild/util.py#115-127
6+
# https://searchfox.org/mozilla-central/rev/ece43b04e7baa4680dac46a06d5ad42b27b124f4/python/mozbuild/mozbuild/util.py#102
7+
8+
import copy
79

810

911
class ReadOnlyDict(dict):
@@ -20,3 +22,20 @@ def __setitem__(self, key, value):
2022

2123
def update(self, *args, **kwargs):
2224
raise Exception("Object does not support update.")
25+
26+
def __copy__(self, *args, **kwargs):
27+
return ReadOnlyDict(**dict.copy(self, *args, **kwargs))
28+
29+
def __deepcopy__(self, memo):
30+
result = {}
31+
for k, v in self.items():
32+
result[k] = copy.deepcopy(v, memo)
33+
34+
return ReadOnlyDict(**result)
35+
36+
def __reduce__(self, *args, **kwargs):
37+
"""
38+
Support for `pickle`.
39+
"""
40+
41+
return (self.__class__, (dict(self),))

test/test_util_readonlydict.py

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,69 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
33
# You can obtain one at http://mozilla.org/MPL/2.0/.
44

5-
# Imported from
6-
# https://searchfox.org/mozilla-central/rev/c3ebaf6de2d481c262c04bb9657eaf76bf47e2ac/python/mozbuild/mozbuild/util.py#115-127
5+
import copy
6+
import pickle
77

8-
import unittest
8+
import pytest
99

1010
from taskgraph.util.readonlydict import ReadOnlyDict
1111

1212

13-
class TestReadOnlyDict(unittest.TestCase):
14-
def test_basic(self):
15-
original = {"foo": 1, "bar": 2}
13+
def test_basic():
14+
original = {"foo": 1, "bar": 2}
1615

17-
test = ReadOnlyDict(original)
16+
test = ReadOnlyDict(original)
1817

19-
self.assertEqual(original, test)
20-
self.assertEqual(test["foo"], 1)
18+
assert original == test
19+
assert test["foo"] == 1
2120

22-
with self.assertRaises(KeyError):
23-
test["missing"]
21+
with pytest.raises(KeyError):
22+
test["missing"]
2423

25-
with self.assertRaises(Exception):
26-
test["baz"] = True
24+
with pytest.raises(Exception):
25+
test["baz"] = True
2726

28-
def test_update(self):
29-
original = {"foo": 1, "bar": 2}
3027

31-
test = ReadOnlyDict(original)
28+
def test_update():
29+
original = {"foo": 1, "bar": 2}
3230

33-
with self.assertRaises(Exception):
34-
test.update(foo=2)
31+
test = ReadOnlyDict(original)
3532

36-
self.assertEqual(original, test)
33+
with pytest.raises(Exception):
34+
test.update(foo=2)
3735

38-
def test_del(self):
39-
original = {"foo": 1, "bar": 2}
36+
assert original == test
4037

41-
test = ReadOnlyDict(original)
4238

43-
with self.assertRaises(Exception):
44-
del test["foo"]
39+
def test_del():
40+
original = {"foo": 1, "bar": 2}
4541

46-
self.assertEqual(original, test)
42+
test = ReadOnlyDict(original)
43+
44+
with pytest.raises(Exception):
45+
del test["foo"]
46+
47+
assert original == test
48+
49+
50+
def test_copy():
51+
d = ReadOnlyDict(foo="bar")
52+
53+
d_copy = d.copy()
54+
assert d == d_copy
55+
# TODO Returning a dict here feels like a bug, but there are places in-tree
56+
# relying on this behaviour.
57+
assert isinstance(d_copy, dict)
58+
59+
d_copy = copy.copy(d)
60+
assert d == d_copy
61+
assert isinstance(d_copy, ReadOnlyDict)
62+
63+
d_copy = copy.deepcopy(d)
64+
assert d == d_copy
65+
assert isinstance(d_copy, ReadOnlyDict)
66+
67+
68+
def test_pickle():
69+
d = ReadOnlyDict(foo="bar")
70+
pickle.loads(pickle.dumps(d))

0 commit comments

Comments
 (0)