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