Coverage for /opt/hostedtoolcache/Python/3.10.17/x64/lib/python3.10/site-packages/vfx_seqtools/actions/seqmv.py: 87%

54 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-05-30 00:30 +0000

1import logging 

2import shutil 

3from typing import Annotated, Optional 

4 

5import fileseq 

6import typer 

7from rich.progress import ( 

8 BarColumn, 

9 MofNCompleteColumn, 

10 Progress, 

11 TaskProgressColumn, 

12 TextColumn, 

13 TimeRemainingColumn, 

14) 

15 

16from vfx_seqtools import common_options 

17from vfx_seqtools.decorators import attach_hook 

18from vfx_seqtools.parser import replace_hash_and_at_with_framenumber 

19 

20 

21def do_action(tupl: tuple) -> None: 

22 src, dst, frame, is_dryrun, be_verbose, be_interactive, be_strict, logger = tupl 

23 substituted_src = replace_hash_and_at_with_framenumber(src, frame) 

24 substituted_dst = replace_hash_and_at_with_framenumber(dst, frame) 

25 if is_dryrun: 

26 logger.info(f"dry-run: MOVE {substituted_src} {substituted_dst}") 

27 else: 

28 if be_verbose: 

29 logger.info(f"MOVE: {substituted_src} {substituted_dst}") 

30 try: 

31 if be_interactive: 

32 confirm = input(f"move {substituted_src} -> {substituted_dst}? (y/n): ") 

33 if confirm.lower() != "y": 

34 return 

35 shutil.move(substituted_src, substituted_dst) 

36 except Exception as e: 

37 if be_strict: 

38 raise 

39 logger.warning( 

40 f"Error moving file: {substituted_src} -> {substituted_dst}, skipping it. Use --strict to stop on errors. {e}" 

41 ) 

42 

43 

44@attach_hook(common_options.dry_run_option, hook_output_kwarg="is_dryrun") 

45@attach_hook(common_options.frame_range_options, hook_output_kwarg="frame_range") 

46@attach_hook(common_options.frame_seq_options, hook_output_kwarg="frame_seq") 

47@attach_hook(common_options.logging_options, hook_output_kwarg="logger") 

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 seqmv( 

53 src: Annotated[str, typer.Argument(help="The source name pattern for the frames.")], 

54 dst: Annotated[ 

55 str, typer.Argument(help="The destination name pattern for the frames.") 

56 ], 

57 logger: logging.Logger, 

58 be_verbose: Optional[bool] = False, 

59 be_strict: Optional[bool] = False, 

60 be_interactive: Optional[bool] = False, 

61 frame_range: tuple[int, int, int] = (0, 0, 0), 

62 frame_seq: str = "", 

63 is_dryrun: Optional[bool] = False, 

64 show_version: Optional[bool] = False, 

65) -> None: 

66 """ 

67 Move(rename) files from <SRC> to <DST>, using the provided framerange. 

68 """ 

69 if frame_seq: 

70 frames = fileseq.FrameSet(frame_seq) 

71 elif frame_range[0] != 0 or frame_range[1] != 0: 

72 frames = fileseq.FrameSet(f"{frame_range[0]}-{frame_range[1]}x{frame_range[2]}") 

73 else: 

74 frames = [] 

75 

76 if is_dryrun: 

77 for frame in frames: 

78 do_action( 

79 ( 

80 src, 

81 dst, 

82 frame, 

83 is_dryrun, 

84 be_verbose, 

85 be_interactive, 

86 be_strict, 

87 logger, 

88 ) 

89 ) 

90 else: 

91 # skip progress bar if interactive 

92 if be_interactive: 

93 for frame in frames: 

94 do_action( 

95 ( 

96 src, 

97 dst, 

98 frame, 

99 is_dryrun, 

100 be_verbose, 

101 be_interactive, 

102 be_strict, 

103 logger, 

104 ) 

105 ) 

106 else: 

107 from rich.logging import RichHandler 

108 

109 logging.basicConfig( 

110 level=logging.INFO, 

111 format="%(message)s", 

112 datefmt="[%X]", 

113 handlers=[RichHandler(rich_tracebacks=True)], 

114 ) 

115 logger = logging.getLogger("rich") 

116 progress = Progress( 

117 TextColumn("[progress.description]{task.description}"), 

118 MofNCompleteColumn(), 

119 BarColumn(), 

120 TaskProgressColumn(), 

121 TimeRemainingColumn(), 

122 ) 

123 with progress: 

124 for frame in progress.track(frames, description="Working..."): 

125 do_action( 

126 ( 

127 src, 

128 dst, 

129 frame, 

130 is_dryrun, 

131 be_verbose, 

132 be_interactive, 

133 be_strict, 

134 logger, 

135 ) 

136 )