Coverage for sources/mimeogram/create.py: 74%

68 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-02-17 22:34 +0000

1# vim: set filetype=python fileencoding=utf-8: 

2# -*- coding: utf-8 -*- 

3 

4#============================================================================# 

5# # 

6# Licensed under the Apache License, Version 2.0 (the "License"); # 

7# you may not use this file except in compliance with the License. # 

8# You may obtain a copy of the License at # 

9# # 

10# http://www.apache.org/licenses/LICENSE-2.0 # 

11# # 

12# Unless required by applicable law or agreed to in writing, software # 

13# distributed under the License is distributed on an "AS IS" BASIS, # 

14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

15# See the License for the specific language governing permissions and # 

16# limitations under the License. # 

17# # 

18#============================================================================# 

19 

20 

21''' Creation of mimeograms. ''' 

22# TODO? Use BSD sysexits. 

23 

24 

25from __future__ import annotations 

26 

27from . import __ 

28from . import interfaces as _interfaces 

29 

30 

31_scribe = __.produce_scribe( __name__ ) 

32 

33 

34class Command( 

35 _interfaces.CliCommand, 

36 decorators = ( __.standard_dataclass, __.standard_tyro_class ), 

37): 

38 ''' Creates mimeogram from filesystem locations or URLs. ''' 

39 

40 sources: __.typx.Annotated[ 

41 __.tyro.conf.Positional[ list[ str ] ], 

42 __.tyro.conf.arg( 

43 help = "Filesystem locations or URLs.", 

44 prefix_name = False ), 

45 ] 

46 clip: __.typx.Annotated[ 

47 __.typx.Optional[ bool ], 

48 __.tyro.conf.arg( 

49 aliases = ( '--clipboard', '--to-clipboard' ), 

50 help = "Copy mimeogram to clipboard." ), 

51 ] = None 

52 edit: __.typx.Annotated[ 

53 bool, 

54 __.tyro.conf.arg( 

55 aliases = ( '-e', '--edit-message' ), 

56 help = "Spawn editor to capture an introductory message." ), 

57 ] = False 

58 prepend_prompt: __.typx.Annotated[ 

59 bool, 

60 __.tyro.conf.arg( 

61 help = "Prepend mimeogram format instructions." ), 

62 ] = False 

63 recurse: __.typx.Annotated[ 

64 __.typx.Optional[ bool ], 

65 __.tyro.conf.arg( 

66 aliases = ( '-r', '--recurse-directories', '--recursive' ), 

67 help = "Recurse into directories." ), 

68 ] = None 

69 strict: __.typx.Annotated[ 

70 __.typx.Optional[ bool ], 

71 __.tyro.conf.arg( 

72 aliases = ( '--fail-on-invalid', ), 

73 help = "Fail on invalid contents? True, fail. False, skip." ), 

74 ] = None 

75 

76 async def __call__( self, auxdata: __.Globals ) -> None: 

77 ''' Executes command to create mimeogram. ''' 

78 await create( auxdata, self ) 

79 

80 def provide_configuration_edits( self ) -> __.DictionaryEdits: 

81 ''' Provides edits against configuration from options. ''' 

82 edits: list[ __.DictionaryEdit ] = [ ] 

83 if None is not self.clip: 

84 edits.append( __.SimpleDictionaryEdit( # pyright: ignore 

85 address = ( 'create', 'to-clipboard' ), value = self.clip ) ) 

86 if None is not self.recurse: 

87 edits.append( __.SimpleDictionaryEdit( # pyright: ignore 

88 address = ( 'acquire-parts', 'recurse-directories' ), 

89 value = self.recurse ) ) 

90 if None is not self.strict: 90 ↛ 91line 90 didn't jump to line 91 because the condition on line 90 was never true

91 edits.append( __.SimpleDictionaryEdit( # pyright: ignore 

92 address = ( 'acquire-parts', 'fail-on-invalid' ), 

93 value = self.strict ) ) 

94 return tuple( edits ) 

95 

96 

97async def _acquire_prompt( auxdata: __.Globals ) -> str: 

98 from .prompt import acquire_prompt 

99 return await acquire_prompt( auxdata ) 

100 

101 

102async def _copy_to_clipboard( mimeogram: str ) -> None: 

103 from pyperclip import copy 

104 try: copy( mimeogram ) 

105 except Exception as exc: 

106 _scribe.exception( "Could not copy mimeogram to clipboard." ) 

107 raise SystemExit( 1 ) from exc 

108 _scribe.info( "Copied mimeogram to clipboard." ) 

109 

110 

111async def _edit_message( ) -> str: 

112 from .edit import edit_content 

113 try: return edit_content( ) 

114 except Exception as exc: 

115 _scribe.exception( "Could not acquire user message." ) 

116 raise SystemExit( 1 ) from exc 

117 

118 

119async def create( # pylint: disable=too-complex,too-many-locals,too-many-statements 

120 auxdata: __.Globals, 

121 command: Command, *, 

122 editor: __.cabc.Callable[ 

123 [ ], __.cabc.Coroutine[ None, None, str ] ] = _edit_message, 

124 clipcopier: __.cabc.Callable[ 

125 [ str ], __.cabc.Coroutine[ None, None, None ] ] = _copy_to_clipboard, 

126 prompter: __.cabc.Callable[ 

127 [ __.Globals ], 

128 __.cabc.Coroutine[ None, None, str ] ] = _acquire_prompt, 

129) -> __.typx.Never: 

130 ''' Creates mimeogram. ''' 

131 from exceptiongroup import ExceptionGroup 

132 from .acquirers import acquire 

133 from .formatters import format_mimeogram 

134 if command.edit: 

135 try: message = await editor( ) 

136 except Exception as exc: 

137 _scribe.exception( "Could not acquire user message." ) 

138 raise SystemExit( 1 ) from exc 

139 else: message = None 

140 # TODO: Factor into '__.exceptions.report_eg_members'. 

141 try: parts = await acquire( auxdata, command.sources ) 

142 except ExceptionGroup as excg: # pyright: ignore 

143 for exc in excg.exceptions: # pyright: ignore 

144 _scribe.error( # noqa: TRY400 

145 "Could not acquire mimeogram parts.", 

146 exc_info = exc ) # pyright: ignore 

147 raise SystemExit( 1 ) from None 

148 except Exception as exc: 

149 _scribe.exception( "Could not acquire mimeogram parts." ) 

150 raise SystemExit( 1 ) from exc 

151 mimeogram = format_mimeogram( parts, message = message ) 

152 # TODO? Pass prompt to 'format_mimeogram'. 

153 if command.prepend_prompt: 

154 prompt = await prompter( auxdata ) 

155 mimeogram = f"{prompt}\n\n{mimeogram}" 

156 options = auxdata.configuration.get( 'create', { } ) 

157 if options.get( 'to-clipboard', False ): 

158 try: await clipcopier( mimeogram ) 

159 except Exception as exc: 

160 _scribe.exception( "Could not copy mimeogram to clipboard." ) 

161 raise SystemExit( 1 ) from exc 

162 else: print( mimeogram ) # TODO? Use output stream from configuration. 

163 raise SystemExit( 0 )