def test_dict(self): data = ImmutableDict(a=123) self.assertEqual(data.meta, {}) data.meta["been here"] = True self.assertTrue(ImmutableDict(a=123).meta["been here"])
def example_immutable_data(): return ImmutableDict( foo=1, bar=ImmutableDict(baz=99), xxx=ImmutableList((None, True, ImmutableList())), yyy=ImmutableDict(), zzz=None, )
def test_getset(self): d = ImmutableDict() with self.assertRaises(KeyError): d["foo"] self.assertEqual(d.get("foo"), None) e = d.set("foo", "bar") with self.assertRaises(KeyError): d["foo"] self.assertEqual(e.get("foo"), "bar")
def test_simple(self): self.assertTrue(sanitize(ImmutableDict()) is ImmutableDict()) self.assertTrue(sanitize({}) is ImmutableDict()) self.assertTrue(sanitize(ImmutableList()) is ImmutableList()) self.assertTrue(sanitize([]) is ImmutableList()) self.assertTrue(sanitize(None) is None) self.assertTrue(sanitize(True) is True) self.assertTrue(sanitize(False) is False) self.assertEqual(sanitize("foobar"), "foobar") self.assertEqual(sanitize(1234), 1234) self.assertEqual(sanitize(1.234), 1.234)
def setDataForPath(data, path: PathType, value, *, undefined=ImmutableDict()): if not path: if value is Undefined: return undefined else: return sanitize(value) p, path = path[0], path[1:] if type(p) is str: if data is Undefined: data = ImmutableDict() elif type(data) is not ImmutableDict: raise PathElementTypeMismatch(p, data) if value is Undefined and not path: return data.discard(p) elif type(p) is int: if data is Undefined: data = ImmutableList() elif type(data) is not ImmutableList: raise PathElementTypeMismatch(p, data) if value is Undefined and not path: if 0 <= p < len(data): return data[0:p] + data[p + 1:] else: return data if p < 0 or p > len(data): raise IndexError if p == len(data): return data.append(setDataForPath(Undefined, path, value)) else: raise InvalidPathElement(p) return data.set(p, setDataForPath(data.get(p, Undefined), path, value))
def clear(self): for rc in self.__registeredCommands.values(): rc.disabled = True rc.unregister() self.__registeredCommands = {} self.__state = ImmutableDict() self.__reportedState = Undefined self.__parentSet(self.__path, Undefined)
def test_dict_weakref(self): # Create one ImmutableDict self.assertEqual(ImmutableDict._get_instance_count(), 0) d = ImmutableDict(foo=1, bar=2) self.assertEqual(ImmutableDict._get_instance_count(), 1) # Store in a weakref.WeakValueDictionary wvd = weakref.WeakValueDictionary() wvd[1] = d self.assertEqual(ImmutableDict._get_instance_count(), 1) self.assertEqual(len(wvd), 1) self.assertTrue(wvd[1] is d) # Release the only reference to the ImmutableDict d = None self.assertEqual(ImmutableDict._get_instance_count(), 0) # Check that it is no longer in wkd self.assertEqual(len(wvd), 0) with self.assertRaises(KeyError): wvd[1] # Create a new ImmutableDict, check that it not magically appears in # wkd d = ImmutableDict(foo=1, bar=2) self.assertEqual(ImmutableDict._get_instance_count(), 1) self.assertEqual(len(wvd), 0) with self.assertRaises(KeyError): wvd[1]
def __init__(self): self.__rawState = self.__unresolvedState = ImmutableDict() self.__resolvedState = self.__nextState = ImmutableDict() self.__realpath = makePath self.__rawSubscriptionRoot = Directory(None, None) self.__unresolvedSubscriptionRoot = Directory(None, None) self.__resolvedSubscriptionRoot = Directory(None, None) self.__updatedSubscriptions = set() self.__pluginInfos = [] self.__pluginList = ImmutableList() self.__coreState = ImmutableDict(commands=ImmutableDict()) self.__corePluginPaths = [] self.__commands = {} # path -> {name: Command} self.__stateUpdateEvent = asyncio.Event() self.__stateUpdateTask = asyncio.create_task( self.__stateUpdateTaskImpl() ) self.__stateUpdateTask.add_done_callback(print_exception_task_callback)
def test_tuple(self): key1 = ("x" * 10000,) key2 = (("x" * 9999 + "x"),) self.assertTrue(type(key1) is tuple) self.assertTrue(type(key2) is tuple) self.assertEqual(key1, key2) if key1 is key2: self.skipTest( "failed to construct two different tuple objects " "with same value" ) d = ImmutableDict({key1: 123}) self.assertEqual(d.get(key1), 123) self.assertEqual(d.get(key2), 123) self.assertTrue(key1 in d) self.assertTrue(key2 in d)
def test_nested(self): self.assertTrue( sanitize({ "a": 1, "b": None, "c": { "x": True }, "d": ImmutableDict(y=False), }) is ImmutableDict( a=1, b=None, c=ImmutableDict(x=True), d=ImmutableDict( y=False))) self.assertTrue( sanitize([1, None, [True], ImmutableList([False])]) is ImmutableList( [1, None, ImmutableList([True]), ImmutableList([False])]))
def test_bytes(self): key1 = b"x" * 10000 key2 = b"x" * 9999 + b"x" self.assertTrue(type(key1) is bytes) self.assertTrue(type(key2) is bytes) self.assertEqual(key1, key2) if key1 is key2: self.skipTest( "failed to construct two different bytes objects " "with same value" ) d = ImmutableDict({key1: 123}) self.assertEqual(d.get(key1), 123) self.assertEqual(d.get(key2), 123) self.assertTrue(key1 in d) self.assertTrue(key2 in d) self.assertFalse(key1.decode("ascii") in d)
def test_pass_immutable(self): self.assertTrue( sanitize([[]]) is sanitize(ImmutableList([[]])) is sanitize( ImmutableList([ImmutableList()])) is ImmutableList( [ImmutableList()])) self.assertTrue( sanitize({"a": {}}) is sanitize(ImmutableDict({"a": {}})) is sanitize(ImmutableDict( a={})) is sanitize(ImmutableDict( a=ImmutableDict())) is ImmutableDict(a=ImmutableDict()))
def __init__( self, path, *, parent_set, parent_register_command, immediate_updates=True ): self.__path = path self.__parentSet = parent_set self.__parentRegisterCommand = parent_register_command self.__state = ImmutableDict() self.__reportedState = Undefined self.__registeredCommands = {} self.__immediate_updates = immediate_updates self.__deactivated = False self.__hidden = False
def sanitize(data): t = type(data) if (t is ImmutableList or t is ImmutableDict) and data.isImmutableJson: return data if data is None or t is bool or t is str or t is int or t is float: return data elif isinstance(data, Sequence): data = ImmutableList(sanitize(x) for x in data if x is not Undefined) if data.isImmutableJson: return data elif isinstance(data, Mapping): data = ImmutableDict((enforceKeyType(key), sanitize(value)) for key, value in data.items() if value is not Undefined) if data.isImmutableJson: return data raise TypeError("data cannot be sanitized to immutable json")
def __newPlugin(self, path, config): plugin_info = PluginInfo(path=path, configuration=config) try: plugin_identifier = config["__plugin__"] module, class_ = plugin_identifier.rsplit(".", 1) sys.modules.pop(module, None) mod = importlib.import_module(module) PluginType = getattr(mod, class_) plugin_info.plugin_object = PluginType( path=path, get=lambda path: self.get(path), subscribe=lambda callback, *paths, initial=True: ( self.subscribe( plugin_info, paths, callback, initial=initial ) ), command=self.command, set_state=functools.partial( self.__setPluginState, plugin_info ), register_command=functools.partial( self.registerCommand, plugin_info ), ) plugin_info.plugin_object.init(config) except Exception as ex: traceback.print_exc() plugin_info.state = ImmutableDict( exception=str(ex), traceback=traceback.format_exc() ) plugin_info.plugin_object = None return plugin_info
def test_mixed(self): ch = ImmutableChecker(self) keys = ( "", "a", "foobar", "baz", "0", "123", "xxx", None, False, unittest, ) values = keys + ( 123, 0, -1, 12.34, 567.76, True, [], {}, [1, 2], { "a": 1 }, ) idicts = set() for k1 in keys: for v1 in values: i = ImmutableDict().set(k1, v1) idicts.add(i) ch.add(i) for k2 in keys: for v2 in values: i = i.set(k2, v2) idicts.add(i) ch.add(i) for i in set(idicts): for k in keys: i = i.discard(k) idicts.add(i) ch.add(i) ilists = set() for k1 in keys: i = ImmutableList().append(k1) ilists.add(i) ch.add(i) for k1 in keys: i = i.append(k2) ilists.add(i) ch.add(i) idicts = list(idicts) ilists = list(ilists) for n in range(100_000): d1 = idicts[n * 104_651 % len(idicts)] l1 = ilists[n * 104_659 % len(ilists)] k1 = keys[n * 104_677 % len(keys)] k2 = keys[n * 104_681 % len(keys)] d2 = idicts[n * 104_683 % len(idicts)] l2 = ilists[n * 104_693 % len(ilists)] nl = l1.append(d1) ilists.append(nl) ch.add(nl) nd = d1.set(k1, l1) idicts.append(nd) ch.add(nd) if k2 in d1: nd2 = d1.discard(k2) idicts.append(nd2) ch.add(nd2) nl = l2.append(l1) ilists.append(nl) ch.add(nl) nd = d2.set(k2, d1) idicts.append(nd) ch.add(nd)
def _symlinkInfoDict(data): return ImmutableDict((pathToString(k), pathToString(v)) for k, v in data)
import unittest from pyimmutable import ImmutableDict, ImmutableList from pykzee.core import AttachedInfo from pykzee.core.common import sanitize # Instantiante an empty ImmutableDict, since pykzee modules may or may not do # that anyway. This way we know what instance counts to expect in the tests # below. empty_immutable_dict = ImmutableDict() class TestResolved(unittest.TestCase): def test_basic(self): self.assertEqual(immutables_count(), 1) data = sanitize({ "foo": "bar", "x1": [0, 1, 2, { "__symlink__": "x2" }, 4], "x2": { "y1": 123, "y2": { "__symlink__": "foo" }, "y3": { "__symlink__": "/x1/[3]/y1" }, "y4": { "__symlink__": ["x2", "y2"]
def test_constructFromDict(self): pydict = {"a": 1, "b": None, "c": True, False: 5.678} d = ImmutableDict(pydict) self.assertEqual(set(d.items()), set(pydict.items()))
def test_convertToDict(self): pydict = {"a": 1, "b": None, "c": True, False: 5.678} d = ImmutableDict() for key, val in pydict.items(): d = d.set(key, val) self.assertEqual(dict(d), pydict)
def test_len(self): self.assertEqual(len(ImmutableDict()), 0) self.assertEqual(len(ImmutableDict().set("foo", 1)), 1) self.assertEqual(len(ImmutableDict().set("foo", 1).set("bar", 2)), 2) self.assertEqual( len(ImmutableDict().set("foo", 1).set("bar", 2).set("foo", 99)), 2)
def test_iter(self): d = ImmutableDict().set("foo", 1).set("bar", 2) self.assertEqual(set(d), {"foo", "bar"}) self.assertEqual(set(d.keys()), {"foo", "bar"}) self.assertEqual(set(d.values()), {1, 2}) self.assertEqual(set(d.items()), {("foo", 1), ("bar", 2)})
def test_equal(self): d = ImmutableDict().set("foo", 1).set("bar", 2) e = ImmutableDict().set("bar", 2).set("foo", 1) self.assertEqual(d, e) self.assertTrue(d is e)
def immutables_count(): return (ImmutableDict._get_instance_count() + ImmutableList._get_instance_count())
def test_stress(self): r = random.Random(123) class X: pass x = X() objects = [ x, x, True, False, None, "\uf111", -4.5, -4.501, -4.502, 4.5, ] objects.extend(range(-50, 50)) objects.extend(str(r.random()) for i in range(100)) objects.append(unittest) dicts = list((ImmutableDict(), {}) for i in range(10)) for i in range(1_000_000): # Mutate actions idx = random.randrange(0, len(dicts)) idict, pydict = dicts[idx] action = random.randint(0, 2) if action == 0: key, value = random.choice(objects), random.choice(objects) idict = idict.set(key, value) pydict[key] = value elif action == 1: key = random.choice(objects) idict = idict.discard(key) pydict.pop(key, None) elif action == 2: update = { random.choice(objects): random.choice(objects) for i in range(random.randint(0, 5)) } idict = idict.update(update) pydict.update(update) dicts[idx] = idict, pydict # Verify actions idict, pydict = random.choice(dicts) action = random.randint(0, 13) if action < 5: key = random.choice(objects) self.assertEqual(idict.get(key, -999), pydict.get(key, -999)) elif action < 10: key = random.choice(objects) try: value = idict[key] except KeyError: value = KeyError self.assertEqual(value, pydict.get(key, KeyError)) elif action == 10: self.assertTrue(compareUnsortedUniqueSequences(idict, pydict)) elif action == 11: self.assertTrue( compareUnsortedUniqueSequences(idict.keys(), pydict) ) elif action == 12: self.assertTrue( compareUnsortedSequences(idict.values(), pydict.values()) ) elif action == 13: self.assertTrue( compareUnsortedUniqueSequences( idict.items(), pydict.items() ) )
def test_dict(self): ch = ImmutableChecker(self) ch.addImmutable(ImmutableDict()) ch.addImmutable(ImmutableDict({"a": 1})) ch.addImmutable(ImmutableDict({"a": 1, "b": 2})) ch.addImmutable(ImmutableDict({"a": 1, "b": "foo"})) ch.addImmutable(ImmutableDict({"a": 1, "b": None})) ch.addImmutable(ImmutableDict({"a": 1, "b": True})) ch.addImmutable(ImmutableDict({"a": 1, "b": 9.876})) ch.addNonImmutable(ImmutableDict({"a": 1, "b": 2, "c": Exception()})) ch.addImmutable( ImmutableDict({ "a": 1, "b": 2, "c": Exception() }).discard("c")) ch.addImmutable( ImmutableDict({ "a": 99, "b": 2, "c": Exception() }).discard("c")) ch.addNonImmutable(ImmutableDict({"a": 1, "b": 2, True: 123})) ch.addImmutable( ImmutableDict({ "a": 1, "b": 2, True: 123 }).discard(True)) ch.addImmutable( ImmutableDict({ "a": 1, "b": 2, "c": 3, "d": 4 }).set("e", 5).set("d", 7)) ch.addNonImmutable( ImmutableDict({ "a": 1, "b": 2, "c": 3, "d": 4 }).set("d", Exception()).set("e", 5)) ch.addImmutable( ImmutableDict({ "a": 1, "b": 2, "c": 3 }).update(b=2, c=4)) ch.check_all()