import shutil from copy import deepcopy from pathlib import Path def deep_update(original, updates): """ Recursively update `original` with values from `updates`. - Dicts are merged recursively. - Scalars replace existing values. - Lists are replaced entirely. """ if not isinstance(original, dict) or not isinstance(updates, dict): return deepcopy(updates) result = deepcopy(original) for key, value in updates.items(): if ( key in result and isinstance(result[key], dict) and isinstance(value, dict) ): result[key] = deep_update(result[key], value) else: result[key] = deepcopy(value) return result def copytree_no_copystat(src, dst): src = Path(src) dst = Path(dst) dst.mkdir(parents=True, exist_ok=True) for item in src.iterdir(): target = dst / item.name if item.is_dir(): copytree_no_copystat(item, target) else: shutil.copy2(item, target)