Move
Move files or entire folder structures from source to destination.
Move
Processing
Moves files or entire folder structures from a source location to a destination.
Inputs
- source
- Path or list of paths to the files or directories to move.
- destination
- Path to the destination directory where files or directories will be moved.
Inputs Types
Input | Types |
---|---|
source |
Str , Path , List |
destination |
Str , DirectoryPath |
You can check the list of supported types here: Available Type Hints.
Outputs
- moved items
- List of paths to files or directories successfully moved.
- skipped items
- List of paths to files or directories skipped during the move operation (e.g., due to overwrite settings).
- errors
- List of error messages for any files or directories that could not be moved.
Outputs Types
Output | Types |
---|---|
moved items |
List |
skipped items |
List |
errors |
List |
You can check the list of supported types here: Available Type Hints.
Options
The Move brick contains some changeable options:
- Overwrite
- If enabled, overwrites existing files or directories at the destination. Defaults to False.
- Verbose
- If enabled, logs detailed messages about the move operation, including errors. Defaults to True.
import logging
import errno
import shutil
from coded_flows.types import Str, Path, DirectoryPath, Tuple, Union, List
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def _validate_source_input(src):
"""Validate that source input contains only strings and Path objects."""
if isinstance(src, (str, Path)):
return True
elif isinstance(src, list):
return all((isinstance(item, (str, Path)) for item in src))
return False
def _move_single_file(
src_file, dst_file, result, overwrite, verbose, brick_display_name
):
"""Move a single file and return True if successful."""
try:
if dst_file.exists() and (not overwrite):
result["skipped_items"].append(str(src_file))
verbose and logger.warning(
f"[{brick_display_name}] '{src_file}' was skipped because it already exists."
)
return
dst_file.parent.mkdir(parents=True, exist_ok=True)
shutil.move(src_file, dst_file)
result["moved_items"].append(str(dst_file))
verbose and logger.info(
f"[{brick_display_name}] '{src_file}' was moved to '{dst_file}'."
)
except OSError as e:
if e.errno == errno.EROFS:
verbose and logger.error(
f"[{brick_display_name}] Failed to move file '{src_file}': File system is read-only."
)
result["errors"].append(f"Failed to move file '{src_file}': {e}")
else:
verbose and logger.error(
f"[{brick_display_name}] Failed to move file '{src_file}'."
)
result["errors"].append(f"Failed to move file '{src_file}': {e}")
except PermissionError as e:
verbose and logger.error(
f"[{brick_display_name}] Failed to move file '{src_file}': Permission denied."
)
result["errors"].append(f"Failed to move file '{src_file}': {e}")
except Exception as e:
verbose and logger.error(
f"[{brick_display_name}] Failed to move file '{src_file}'."
)
result["errors"].append(f"Failed to move file '{src_file}': {e}")
def _move_directory(src_dir, dst_dir, result, overwrite, verbose, brick_display_name):
"""Move entire directory structure."""
try:
if dst_dir.exists() and (not overwrite):
result["skipped_items"].append(str(src_dir))
verbose and logger.warning(
f"[{brick_display_name}] '{src_dir}' was skipped because it already exists."
)
return
if dst_dir.exists() and overwrite:
shutil.rmtree(dst_dir)
shutil.move(src_dir, dst_dir)
result["moved_items"].append(str(dst_dir))
verbose and logger.info(
f"[{brick_display_name}] '{src_dir}' was moved to '{dst_dir}'."
)
except OSError as e:
if e.errno == errno.EROFS:
verbose and logger.error(
f"[{brick_display_name}] Failed to move directory '{src_dir}': File system is read-only."
)
result["errors"].append(f"Failed to move directory '{src_dir}': {e}")
else:
verbose and logger.error(
f"[{brick_display_name}] Failed to move directory '{src_dir}'."
)
result["errors"].append(f"Failed to move directory '{src_dir}': {e}")
except PermissionError as e:
verbose and logger.error(
f"[{brick_display_name}] Failed to move directory '{src_dir}': Permission denied."
)
result["errors"].append(f"Failed to move directory '{src_dir}': {e}")
except Exception as e:
verbose and logger.error(
f"[{brick_display_name}] Failed to move directory '{src_dir}'."
)
result["errors"].append(f"Failed to move directory '{src_dir}': {e}")
def move_files(
source: Union[Str, Path, List], destination: Union[Str, DirectoryPath], options=None
) -> Tuple[List, List, List]:
brick_display_name = "Move"
options = options or {}
verbose = options.get("verbose", True)
overwrite = options.get("overwrite", True)
result = {"moved_items": [], "skipped_items": [], "errors": []}
if not _validate_source_input(source):
verbose and logger.error(
f"[{brick_display_name}] Invalid source input. Must be Str, Path, or list of Str/Path objects."
)
raise ValueError(
"Invalid source input. Must be Str, Path, or list of Str/Path objects."
)
if isinstance(source, (str, Path)):
source_paths = [Path(source)]
else:
source_paths = source
destination_path = Path(destination)
try:
destination_path.mkdir(parents=True, exist_ok=True)
except PermissionError as e:
verbose and logger.error(
f"[{brick_display_name}] Failed to create destination directory '{destination_path}': Permission denied."
)
raise PermissionError(
f"Failed to create destination directory '{destination_path}': Permission denied."
)
except Exception as e:
verbose and logger.error(
f"[{brick_display_name}] Failed to create destination directory."
)
raise OSError(f"Failed to create destination directory: {e}")
for source_item in source_paths:
src_path = Path(source_item)
if not src_path.exists():
result["errors"].append(f"Source path does not exist: '{source_item}'.")
verbose and logger.error(
f"[{brick_display_name}] Source path does not exist: '{source_item}'."
)
continue
dst_path = destination_path / src_path.name
if src_path.is_file():
_move_single_file(
src_path, dst_path, result, overwrite, verbose, brick_display_name
)
elif src_path.is_dir():
_move_directory(
src_path, dst_path, result, overwrite, verbose, brick_display_name
)
else:
verbose and logger.error(
f"[{brick_display_name}] Unknown file type: '{source_item}'."
)
result["errors"].append(f"Unknown file type: '{source_item}'.")
moved_items = result["moved_items"]
skipped_items = result["skipped_items"]
errors = result["errors"]
return (moved_items, skipped_items, errors)
Brick Info
version
v0.1.4
python
3.10,
3.11,
3.12,
3.13
requirements
-
-