def assign()

in libraries/botbuilder-dialogs/botbuilder/dialogs/object_path.py [0:0]


    def assign(start_object, overlay_object, default: Union[Callable, object] = None):
        """
        Creates a new object by overlaying values in start_object with non-null values from overlay_object.

        :param start_object: dict or typed object, the target object to set values on
        :param overlay_object: dict or typed object, the item to overlay values form
        :param default: Provides a default object if both source and overlay are None
        :return: A copy of start_object, with values from overlay_object
        """
        if start_object and overlay_object:
            merged = copy.deepcopy(start_object)

            def merge(target: dict, source: dict):
                key_set = set(target).union(set(source))

                for key in key_set:
                    target_value = target.get(key)
                    source_value = source.get(key)

                    # skip empty overlay items
                    if source_value:
                        if isinstance(source_value, dict):
                            # merge dictionaries
                            if not target_value:
                                target[key] = copy.deepcopy(source_value)
                            else:
                                merge(target_value, source_value)
                        elif not hasattr(source_value, "__dict__"):
                            # simple type.  just copy it.
                            target[key] = copy.copy(source_value)
                        elif not target_value:
                            # the target doesn't have the value, but
                            # the overlay does.  just copy it.
                            target[key] = copy.deepcopy(source_value)
                        else:
                            # recursive class copy
                            merge(target_value.__dict__, source_value.__dict__)

            target_dict = merged if isinstance(merged, dict) else merged.__dict__
            overlay_dict = (
                overlay_object
                if isinstance(overlay_object, dict)
                else overlay_object.__dict__
            )
            merge(target_dict, overlay_dict)

            return merged

        if overlay_object:
            return copy.deepcopy(overlay_object)

        if start_object:
            return start_object
        if default:
            return default() if callable(default) else copy.deepcopy(default)
        return None