# Path: sacred/utils.py
# def join_paths(*parts):
#     """Join different parts together to a valid dotted path."""
#     return ".".join(str(p).strip(".") for p in parts if p)
# 
# class SacredError(Exception):
#     def __init__(
#         self,
#         message,
#         print_traceback=True,
#         filter_traceback="default",
#         print_usage=False,
#     ):
#         super().__init__(message)
#         self.print_traceback = print_traceback
#         if filter_traceback not in ["always", "default", "never"]:
#             raise ValueError(
#                 "filter_traceback must be one of 'always', "
#                 "'default' or 'never', not " + filter_traceback
#             )
#         self.filter_traceback = filter_traceback
#         self.print_usage = print_usage


import copy
import sacred.optional as opt
from sacred.utils import join_paths, SacredError
    from sacred.optional import np
            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


# Path: sacred/utils.py
# def join_paths(*parts):
#     """Join different parts together to a valid dotted path."""
#     return ".".join(str(p).strip(".") for p in parts if p)
# 
# class SacredError(Exception):
#     def __init__(
#         self,
#         message,
#         print_traceback=True,
#         filter_traceback="default",
#         print_usage=False,
#     ):
#         super().__init__(message)
#         self.print_traceback = print_traceback
#         if filter_traceback not in ["always", "default", "never"]:
#             raise ValueError(
#                 "filter_traceback must be one of 'always', "
#                 "'default' or 'never', not " + filter_traceback
#             )
#         self.filter_traceback = filter_traceback
#         self.print_usage = print_usage


# Path: sacred/config/custom_containers.py
import copy
import sacred.optional as opt
from sacred.utils import join_paths, SacredError
    from sacred.optional import np

            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}