Bug 1632870 - [mozbuild] Allow making copies of 'mozbuild.util.ReadOnlyDict', r=firefox-build-system-reviewers,mhentges

The copy and deepcopy operations currently use 'setitem' which obviously fails
for 'ReadOnlyDict'. But copying the dict yields a new instance so there should
be no reason this is prevented.

Specifically, I'd like to make certain subsets of task configuration read-only.
But copying is needed when we split the task into multiple tasks (e.g for
chunking).

Differential Revision: https://phabricator.services.mozilla.com/D131284
This commit is contained in:
Andrew Halberstadt 2021-11-19 14:18:33 +00:00
Родитель 6340a6db91
Коммит 7856dcfe71
2 изменённых файлов: 41 добавлений и 0 удалений

Просмотреть файл

@ -5,6 +5,7 @@
from __future__ import absolute_import, print_function, unicode_literals
import copy
import hashlib
import io
import itertools
@ -15,6 +16,7 @@ import string
import sys
import textwrap
import pytest
from mozfile.mozfile import NamedTemporaryFile
from mozunit import main
@ -32,6 +34,7 @@ from mozbuild.util import (
HierarchicalStringList,
EnumString,
EnumStringComparisonError,
ReadOnlyDict,
StrictOrderingOnAppendList,
StrictOrderingOnAppendListWithAction,
StrictOrderingOnAppendListWithFlagsFactory,
@ -927,5 +930,32 @@ class TestHexDump(unittest.TestCase):
)
def test_read_only_dict():
d = ReadOnlyDict(foo="bar")
with pytest.raises(Exception):
d["foo"] = "baz"
with pytest.raises(Exception):
d.update({"foo": "baz"})
with pytest.raises(Exception):
del d["foo"]
# ensure copy still works
d_copy = d.copy()
assert d == d_copy
# TODO Returning a dict here feels like a bug, but there are places in-tree
# relying on this behaviour.
assert isinstance(d_copy, dict)
d_copy = copy.copy(d)
assert d == d_copy
assert isinstance(d_copy, ReadOnlyDict)
d_copy = copy.deepcopy(d)
assert d == d_copy
assert isinstance(d_copy, ReadOnlyDict)
if __name__ == "__main__":
main()

Просмотреть файл

@ -10,6 +10,7 @@ from __future__ import absolute_import, print_function, unicode_literals
import argparse
import collections
import collections.abc
import copy
import ctypes
import difflib
import errno
@ -133,6 +134,16 @@ class ReadOnlyDict(dict):
def update(self, *args, **kwargs):
raise Exception("Object does not support update.")
def __copy__(self, *args, **kwargs):
return ReadOnlyDict(**dict.copy(self, *args, **kwargs))
def __deepcopy__(self, memo):
result = {}
for k, v in self.items():
result[k] = copy.deepcopy(v, memo)
return ReadOnlyDict(**result)
class undefined_default(object):
"""Represents an undefined argument value that isn't None."""