Coverage for /opt/hostedtoolcache/Python/3.10.17/x64/lib/python3.10/site-packages/vfx_seqtools/actions/seqrm.py: 87%
54 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-05-30 00:30 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-05-30 00:30 +0000
1import logging
2import pathlib
3from typing import Annotated, Optional
5import fileseq
6import typer
7from rich.progress import (
8 BarColumn,
9 MofNCompleteColumn,
10 Progress,
11 TaskProgressColumn,
12 TextColumn,
13 TimeRemainingColumn,
14)
16from vfx_seqtools import common_options
17from vfx_seqtools.decorators import attach_hook
18from vfx_seqtools.parser import replace_hash_and_at_with_framenumber
21def do_action(tupl: tuple) -> None:
22 src, frame, is_dryrun, be_verbose, be_interactive, be_strict, logger = tupl
23 substituted_src = replace_hash_and_at_with_framenumber(src, frame)
24 if is_dryrun:
25 logger.info(f"dry-run: DELETE {substituted_src}")
26 else:
27 if be_verbose:
28 logger.info(f"DELETE: {substituted_src}")
29 try:
30 if be_interactive:
31 confirm = input(f"delete {substituted_src}? (y/n): ")
32 if confirm.lower() != "y":
33 return
34 pathlib.Path.unlink(pathlib.Path(substituted_src))
35 except Exception as e:
36 if be_strict:
37 raise
38 logger.warning(
39 f"Error deleting file: {substituted_src}, skipping it. Use --strict to stop on errors. {e}"
40 )
43@attach_hook(common_options.dry_run_option, hook_output_kwarg="is_dryrun")
44@attach_hook(common_options.frame_range_options, hook_output_kwarg="frame_range")
45@attach_hook(common_options.frame_seq_options, hook_output_kwarg="frame_seq")
46@attach_hook(common_options.logging_options, hook_output_kwarg="logger")
47@attach_hook(common_options.threading_option, hook_output_kwarg="thread_count")
48@attach_hook(common_options.interactive_option, hook_output_kwarg="be_interactive")
49@attach_hook(common_options.verbose_option, hook_output_kwarg="be_verbose")
50@attach_hook(common_options.strict_option, hook_output_kwarg="be_strict")
51@attach_hook(common_options.version_option, hook_output_kwarg="show_version")
52def seqrm(
53 src: Annotated[str, typer.Argument(help="The files to remove.")],
54 logger: logging.Logger,
55 be_verbose: Optional[bool] = False,
56 be_strict: Optional[bool] = False,
57 be_interactive: Optional[bool] = False,
58 frame_range: tuple[int, int, int] = (0, 0, 0),
59 frame_seq: str = "",
60 is_dryrun: Optional[bool] = False,
61 show_version: Optional[bool] = False,
62 thread_count: Optional[int] = 0,
63) -> None:
64 """
65 Remove files with pattern <SRC>, using the provided framerange.
67 Use 'seqrm file.####.exr -f 1-5' to remove file.0001.exr through file.0005.exr.
69 """
70 if frame_seq:
71 frames = fileseq.FrameSet(frame_seq)
72 elif frame_range[0] != 0 or frame_range[1] != 0:
73 frames = fileseq.FrameSet(f"{frame_range[0]}-{frame_range[1]}x{frame_range[2]}")
74 else:
75 frames = []
77 if is_dryrun:
78 for frame in frames:
79 do_action(
80 (src, frame, is_dryrun, be_verbose, be_interactive, be_strict, logger)
81 )
82 else:
83 # skip progress bar if interactive
84 if be_interactive:
85 for frame in frames:
86 do_action(
87 (
88 src,
89 frame,
90 is_dryrun,
91 be_verbose,
92 be_interactive,
93 be_strict,
94 logger,
95 )
96 )
97 else:
98 from rich.logging import RichHandler
100 logging.basicConfig(
101 level=logging.INFO,
102 format="%(message)s",
103 datefmt="[%X]",
104 handlers=[RichHandler(rich_tracebacks=True)],
105 )
106 logger = logging.getLogger("rich")
107 progress = Progress(
108 TextColumn("[progress.description]{task.description}"),
109 MofNCompleteColumn(),
110 BarColumn(),
111 TaskProgressColumn(),
112 TimeRemainingColumn(),
113 )
114 with progress:
115 for frame in progress.track(frames, description="Working..."):
116 do_action(
117 (
118 src,
119 frame,
120 is_dryrun,
121 be_verbose,
122 be_interactive,
123 be_strict,
124 logger,
125 )
126 )