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
« 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 -*-
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#============================================================================#
21''' Creation of mimeograms. '''
22# TODO? Use BSD sysexits.
25from __future__ import annotations
27from . import __
28from . import interfaces as _interfaces
31_scribe = __.produce_scribe( __name__ )
34class Command(
35 _interfaces.CliCommand,
36 decorators = ( __.standard_dataclass, __.standard_tyro_class ),
37):
38 ''' Creates mimeogram from filesystem locations or URLs. '''
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
76 async def __call__( self, auxdata: __.Globals ) -> None:
77 ''' Executes command to create mimeogram. '''
78 await create( auxdata, self )
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 )
97async def _acquire_prompt( auxdata: __.Globals ) -> str:
98 from .prompt import acquire_prompt
99 return await acquire_prompt( auxdata )
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." )
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
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 )