# Path: monty/collections.py
# class frozendict(dict):
#     """
#     A dictionary that does not permit changes. The naming
#     violates PEP8 to be consistent with standard Python's "frozenset" naming.
#     """
# 
#     def __init__(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         dict.__init__(self, *args, **kwargs)
# 
#     def __setitem__(self, key, val):
#         raise KeyError(f"Cannot overwrite existing key: {str(key)}")
# 
#     def update(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         raise KeyError(f"Cannot update a {self.__class__.__name__}")
# 
# class Namespace(dict):
#     """A dictionary that does not permit to redefine its keys."""
# 
#     def __init__(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         self.update(*args, **kwargs)
# 
#     def __setitem__(self, key, val):
#         if key in self:
#             raise KeyError(f"Cannot overwrite existent key: {str(key)}")
# 
#         dict.__setitem__(self, key, val)
# 
#     def update(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         for k, v in dict(*args, **kwargs).items():
#             self[k] = v
# 
# class AttrDict(dict):
#     """
#     Allows to access dict keys as obj.foo in addition
#     to the traditional way obj['foo']"
# 
#     Example:
#         >>> d = AttrDict(foo=1, bar=2)
#         >>> assert d["foo"] == d.foo
#         >>> d.bar = "hello"
#         >>> assert d.bar == "hello"
#     """
# 
#     def __init__(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         super().__init__(*args, **kwargs)
#         self.__dict__ = self
# 
#     def copy(self):
#         """
#         :return: Copy of AttrDict
#         """
#         newd = super().copy()
#         return self.__class__(**newd)
# 
# class FrozenAttrDict(frozendict):
#     """
#     A dictionary that:
#         * does not permit changes.
#         * Allows to access dict keys as obj.foo in addition
#           to the traditional way obj['foo']
#     """
# 
#     def __init__(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         super().__init__(*args, **kwargs)
# 
#     def __getattribute__(self, name):
#         try:
#             return super().__getattribute__(name)
#         except AttributeError:
#             try:
#                 return self[name]
#             except KeyError as exc:
#                 raise AttributeError(str(exc))
# 
#     def __setattr__(self, name, value):
#         raise KeyError(f"You cannot modify attribute {name} of {self.__class__.__name__}")
# 
# def tree():
#     """
#     A tree object, which is effectively a recursive defaultdict that
#     adds tree as members.
# 
#     Usage:
#         x = tree()
#         x['a']['b']['c'] = 1
# 
#     Returns:
#         A tree.
#     """
#     return collections.defaultdict(tree)


import unittest
import os
from monty.collections import frozendict, Namespace, AttrDict, FrozenAttrDict, tree
    def test_namespace_dict(self):
        d = Namespace(foo="bar")
        d["hello"] = "world"
        self.assertEqual(d["foo"], "bar")
        self.assertRaises(KeyError, d.__setitem__, "foo", "spam")

    def test_attr_dict(self):
        d = AttrDict(foo=1, bar=2)
        self.assertEqual(d.bar, 2)
        self.assertEqual(d["foo"], d.foo)
        d.bar = "hello"
        self.assertEqual(d["bar"], "hello")

    def test_frozen_attrdict(self):
        d = FrozenAttrDict({"hello": "world", 1: 2})
        self.assertEqual(d["hello"], "world")
        self.assertEqual(d.hello, "world")
        self.assertRaises(KeyError, d.update, {"updating": 2})
        with self.assertRaises(KeyError):
            d["foo"] = "bar"
        with self.assertRaises(KeyError):
            d.foo = "bar"
        with self.assertRaises(KeyError):
            d.hello = "new"


class TreeTest(unittest.TestCase):
    def test_tree(self):
        x = tree()
        x["a"]["b"]["c"]["d"] = 1

# Path: monty/collections.py
# class frozendict(dict):
#     """
#     A dictionary that does not permit changes. The naming
#     violates PEP8 to be consistent with standard Python's "frozenset" naming.
#     """
# 
#     def __init__(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         dict.__init__(self, *args, **kwargs)
# 
#     def __setitem__(self, key, val):
#         raise KeyError(f"Cannot overwrite existing key: {str(key)}")
# 
#     def update(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         raise KeyError(f"Cannot update a {self.__class__.__name__}")
# 
# class Namespace(dict):
#     """A dictionary that does not permit to redefine its keys."""
# 
#     def __init__(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         self.update(*args, **kwargs)
# 
#     def __setitem__(self, key, val):
#         if key in self:
#             raise KeyError(f"Cannot overwrite existent key: {str(key)}")
# 
#         dict.__setitem__(self, key, val)
# 
#     def update(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         for k, v in dict(*args, **kwargs).items():
#             self[k] = v
# 
# class AttrDict(dict):
#     """
#     Allows to access dict keys as obj.foo in addition
#     to the traditional way obj['foo']"
# 
#     Example:
#         >>> d = AttrDict(foo=1, bar=2)
#         >>> assert d["foo"] == d.foo
#         >>> d.bar = "hello"
#         >>> assert d.bar == "hello"
#     """
# 
#     def __init__(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         super().__init__(*args, **kwargs)
#         self.__dict__ = self
# 
#     def copy(self):
#         """
#         :return: Copy of AttrDict
#         """
#         newd = super().copy()
#         return self.__class__(**newd)
# 
# class FrozenAttrDict(frozendict):
#     """
#     A dictionary that:
#         * does not permit changes.
#         * Allows to access dict keys as obj.foo in addition
#           to the traditional way obj['foo']
#     """
# 
#     def __init__(self, *args, **kwargs):
#         """
#         :param args: Passthrough arguments for standard dict.
#         :param kwargs: Passthrough keyword arguments for standard dict.
#         """
#         super().__init__(*args, **kwargs)
# 
#     def __getattribute__(self, name):
#         try:
#             return super().__getattribute__(name)
#         except AttributeError:
#             try:
#                 return self[name]
#             except KeyError as exc:
#                 raise AttributeError(str(exc))
# 
#     def __setattr__(self, name, value):
#         raise KeyError(f"You cannot modify attribute {name} of {self.__class__.__name__}")
# 
# def tree():
#     """
#     A tree object, which is effectively a recursive defaultdict that
#     adds tree as members.
# 
#     Usage:
#         x = tree()
#         x['a']['b']['c'] = 1
# 
#     Returns:
#         A tree.
#     """
#     return collections.defaultdict(tree)


# Path: tests/test_collections.py
import unittest
import os
from monty.collections import frozendict, Namespace, AttrDict, FrozenAttrDict, tree

    def test_namespace_dict(self):
        d = Namespace(foo="bar")
        d["hello"] = "world"
        self.assertEqual(d["foo"], "bar")
        self.assertRaises(KeyError, d.__setitem__, "foo", "spam")

    def test_attr_dict(self):
        d = AttrDict(foo=1, bar=2)
        self.assertEqual(d.bar, 2)
        self.assertEqual(d["foo"], d.foo)
        d.bar = "hello"
        self.assertEqual(d["bar"], "hello")

    def test_frozen_attrdict(self):
        d = FrozenAttrDict({"hello": "world", 1: 2})
        self.assertEqual(d["hello"], "world")
        self.assertEqual(d.hello, "world")
        self.assertRaises(KeyError, d.update, {"updating": 2})
        with self.assertRaises(KeyError):
            d["foo"] = "bar"
        with self.assertRaises(KeyError):
            d.foo = "bar"
        with self.assertRaises(KeyError):
            d.hello = "new"


class TreeTest(unittest.TestCase):
    def test_tree(self):
        x = tree()
        x["a"]["b"]["c"]["d"] = 1

        self.assertIn("b", x["a"])