# Path: sacred/config/custom_containers.py
# class DogmaticDict(dict):
#     def __init__(self, fixed=None, fallback=None):
#         super().__init__()
#         self.typechanges = {}
#         self.fallback_writes = []
#         self.modified = set()
#         self.fixed = fixed or {}
#         self._fallback = {}
#         if fallback:
#             self.fallback = fallback
# 
#     @property
#     def fallback(self):
#         return self._fallback
# 
#     @fallback.setter
#     def fallback(self, newval):
#         ffkeys = set(self.fixed.keys()).intersection(set(newval.keys()))
#         for k in ffkeys:
#             if isinstance(self.fixed[k], DogmaticDict):
#                 self.fixed[k].fallback = newval[k]
#             elif isinstance(self.fixed[k], dict):
#                 self.fixed[k] = DogmaticDict(self.fixed[k])
#                 self.fixed[k].fallback = newval[k]
# 
#         self._fallback = newval
# 
#     def _log_blocked_setitem(self, key, value, fixed_value):
#         if type_changed(value, fixed_value):
#             self.typechanges[key] = (type(value), type(fixed_value))
# 
#         if is_different(value, fixed_value):
#             self.modified.add(key)
# 
#         # if both are dicts recursively collect modified and typechanges
#         if isinstance(fixed_value, DogmaticDict) and isinstance(value, dict):
#             for k, val in fixed_value.typechanges.items():
#                 self.typechanges[join_paths(key, k)] = val
# 
#             self.modified |= {join_paths(key, m) for m in fixed_value.modified}
# 
#     def __setitem__(self, key, value):
#         if key not in self.fixed:
#             if key in self.fallback:
#                 self.fallback_writes.append(key)
#             return dict.__setitem__(self, key, value)
# 
#         fixed_value = self.fixed[key]
#         dict.__setitem__(self, key, fixed_value)
#         # if both are dicts do a recursive update
#         if isinstance(fixed_value, DogmaticDict) and isinstance(value, dict):
#             for k, val in value.items():
#                 fixed_value[k] = val
# 
#         self._log_blocked_setitem(key, value, fixed_value)
# 
#     def __getitem__(self, item):
#         if dict.__contains__(self, item):
#             return dict.__getitem__(self, item)
#         elif item in self.fallback:
#             if item in self.fixed:
#                 return self.fixed[item]
#             else:
#                 return self.fallback[item]
#         raise KeyError(item)
# 
#     def __contains__(self, item):
#         return dict.__contains__(self, item) or (item in self.fallback)
# 
#     def get(self, k, d=None):
#         if dict.__contains__(self, k):
#             return dict.__getitem__(self, k)
#         else:
#             return self.fallback.get(k, d)
# 
#     def has_key(self, item):
#         return self.__contains__(item)
# 
#     def __delitem__(self, key):
#         if key not in self.fixed:
#             dict.__delitem__(self, key)
# 
#     def update(self, iterable=None, **kwargs):
#         if iterable is not None:
#             if hasattr(iterable, "keys"):
#                 for key in iterable:
#                     self[key] = iterable[key]
#             else:
#                 for (key, value) in iterable:
#                     self[key] = value
#         for key in kwargs:
#             self[key] = kwargs[key]
# 
#     def revelation(self):
#         missing = set()
#         for key in self.fixed:
#             if not dict.__contains__(self, key):
#                 self[key] = self.fixed[key]
#                 missing.add(key)
# 
#             if isinstance(self[key], (DogmaticDict, DogmaticList)):
#                 missing |= {key + "." + k for k in self[key].revelation()}
#         return missing


import pytest
from sacred.config.custom_containers import DogmaticDict
    d = DogmaticDict(fallback={"a": 23})
    assert "a" in d
    assert d["a"] == 23
    assert d.get("a") == 23

    d = DogmaticDict()
    d.fallback = {"a": 23}
    assert "a" in d
    assert d["a"] == 23
    assert d.get("a") == 23


def test_fallback_not_iterated():
    d = DogmaticDict(fallback={"a": 23})
    d["b"] = 1234
    assert list(d.keys()) == ["b"]
    assert list(d.values()) == [1234]
    assert list(d.items()) == [("b", 1234)]


def test_overwrite_fallback():
    d = DogmaticDict(fallback={"a": 23})
    d["a"] = 0
    assert d["a"] == 0
    assert list(d.keys()) == ["a"]
    assert list(d.values()) == [0]
    assert list(d.items()) == [("a", 0)]


def test_fixed_has_precedence_over_fallback():

# Path: sacred/config/custom_containers.py
# class DogmaticDict(dict):
#     def __init__(self, fixed=None, fallback=None):
#         super().__init__()
#         self.typechanges = {}
#         self.fallback_writes = []
#         self.modified = set()
#         self.fixed = fixed or {}
#         self._fallback = {}
#         if fallback:
#             self.fallback = fallback
# 
#     @property
#     def fallback(self):
#         return self._fallback
# 
#     @fallback.setter
#     def fallback(self, newval):
#         ffkeys = set(self.fixed.keys()).intersection(set(newval.keys()))
#         for k in ffkeys:
#             if isinstance(self.fixed[k], DogmaticDict):
#                 self.fixed[k].fallback = newval[k]
#             elif isinstance(self.fixed[k], dict):
#                 self.fixed[k] = DogmaticDict(self.fixed[k])
#                 self.fixed[k].fallback = newval[k]
# 
#         self._fallback = newval
# 
#     def _log_blocked_setitem(self, key, value, fixed_value):
#         if type_changed(value, fixed_value):
#             self.typechanges[key] = (type(value), type(fixed_value))
# 
#         if is_different(value, fixed_value):
#             self.modified.add(key)
# 
#         # if both are dicts recursively collect modified and typechanges
#         if isinstance(fixed_value, DogmaticDict) and isinstance(value, dict):
#             for k, val in fixed_value.typechanges.items():
#                 self.typechanges[join_paths(key, k)] = val
# 
#             self.modified |= {join_paths(key, m) for m in fixed_value.modified}
# 
#     def __setitem__(self, key, value):
#         if key not in self.fixed:
#             if key in self.fallback:
#                 self.fallback_writes.append(key)
#             return dict.__setitem__(self, key, value)
# 
#         fixed_value = self.fixed[key]
#         dict.__setitem__(self, key, fixed_value)
#         # if both are dicts do a recursive update
#         if isinstance(fixed_value, DogmaticDict) and isinstance(value, dict):
#             for k, val in value.items():
#                 fixed_value[k] = val
# 
#         self._log_blocked_setitem(key, value, fixed_value)
# 
#     def __getitem__(self, item):
#         if dict.__contains__(self, item):
#             return dict.__getitem__(self, item)
#         elif item in self.fallback:
#             if item in self.fixed:
#                 return self.fixed[item]
#             else:
#                 return self.fallback[item]
#         raise KeyError(item)
# 
#     def __contains__(self, item):
#         return dict.__contains__(self, item) or (item in self.fallback)
# 
#     def get(self, k, d=None):
#         if dict.__contains__(self, k):
#             return dict.__getitem__(self, k)
#         else:
#             return self.fallback.get(k, d)
# 
#     def has_key(self, item):
#         return self.__contains__(item)
# 
#     def __delitem__(self, key):
#         if key not in self.fixed:
#             dict.__delitem__(self, key)
# 
#     def update(self, iterable=None, **kwargs):
#         if iterable is not None:
#             if hasattr(iterable, "keys"):
#                 for key in iterable:
#                     self[key] = iterable[key]
#             else:
#                 for (key, value) in iterable:
#                     self[key] = value
#         for key in kwargs:
#             self[key] = kwargs[key]
# 
#     def revelation(self):
#         missing = set()
#         for key in self.fixed:
#             if not dict.__contains__(self, key):
#                 self[key] = self.fixed[key]
#                 missing.add(key)
# 
#             if isinstance(self[key], (DogmaticDict, DogmaticList)):
#                 missing |= {key + "." + k for k in self[key].revelation()}
#         return missing


# Path: tests/test_config/test_dogmatic_dict.py
import pytest
from sacred.config.custom_containers import DogmaticDict

    d = DogmaticDict(fallback={"a": 23})
    assert "a" in d
    assert d["a"] == 23
    assert d.get("a") == 23

    d = DogmaticDict()
    d.fallback = {"a": 23}
    assert "a" in d
    assert d["a"] == 23
    assert d.get("a") == 23


def test_fallback_not_iterated():
    d = DogmaticDict(fallback={"a": 23})
    d["b"] = 1234
    assert list(d.keys()) == ["b"]
    assert list(d.values()) == [1234]
    assert list(d.items()) == [("b", 1234)]


def test_overwrite_fallback():
    d = DogmaticDict(fallback={"a": 23})
    d["a"] = 0
    assert d["a"] == 0
    assert list(d.keys()) == ["a"]
    assert list(d.values()) == [0]
    assert list(d.items()) == [("a", 0)]


def test_fixed_has_precedence_over_fallback():

    d = DogmaticDict(fixed={"a": 0}, fallback={"a": 23})