Bug 1247836 - Add a ReadOnlyNamespace class to mozbuild.util
--- a/python/mozbuild/mozbuild/test/test_containers.py
+++ b/python/mozbuild/mozbuild/test/test_containers.py
@@ -5,24 +5,45 @@
import unittest
from mozunit import main
from mozbuild.util import (
KeyedDefaultDict,
List,
OrderedDefaultDict,
+ ReadOnlyNamespace,
ReadOnlyDefaultDict,
ReadOnlyDict,
ReadOnlyKeyedDefaultDict,
)
from collections import OrderedDict
+class TestReadOnlyNamespace(unittest.TestCase):
+ def test_basic(self):
+ test = ReadOnlyNamespace(foo=1, bar=2)
+
+ self.assertEqual(test.foo, 1)
+ self.assertEqual(test.bar, 2)
+ self.assertEqual(
+ sorted(i for i in dir(test) if not i.startswith('__')),
+ ['bar', 'foo'])
+
+ with self.assertRaises(AttributeError):
+ value = test.missing
+
+ with self.assertRaises(Exception):
+ test.foo = 2
+
+ with self.assertRaises(Exception):
+ del test.foo
+
+
class TestReadOnlyDict(unittest.TestCase):
def test_basic(self):
original = {'foo': 1, 'bar': 2}
test = ReadOnlyDict(original)
self.assertEqual(original, test)
self.assertEqual(test['foo'], 1)
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -67,16 +67,29 @@ class EmptyValue(unicode):
This type exists in order to support
:py:class:`mozbuild.frontend.reader.EmptyConfig`. It should likely not be
used elsewhere.
"""
def __init__(self):
super(EmptyValue, self).__init__()
+class ReadOnlyNamespace(object):
+ """A class for objects with immutable attributes set at initialization."""
+ def __init__(self, **kwargs):
+ for k, v in kwargs.iteritems():
+ super(ReadOnlyNamespace, self).__setattr__(k, v)
+
+ def __delattr__(self, key):
+ raise Exception('Object does not support deletion.')
+
+ def __setattr__(self, key, value):
+ raise Exception('Object does not support assignment.')
+
+
class ReadOnlyDict(dict):
"""A read-only dictionary."""
def __init__(self, *args, **kwargs):
dict.__init__(self, *args, **kwargs)
def __delitem__(self, key):
raise Exception('Object does not support deletion.')