@@ -23,14 +23,14 @@ def puts(s: str) -> None:
2323 print (s , file = sys .stderr )
2424
2525
26- def echo_newline (_ : CliContext ) -> None :
26+ def echo_newline (_ : CliContext ) -> str :
2727 """Outputs a new line"""
28- puts ( "" )
28+ return ""
2929
3030
31- def terminal_block (_ : CliContext ) -> None :
31+ def terminal_block (_ : CliContext ) -> str :
3232 """Outputs a couple of newlines and the current time"""
33- puts ( f"{ '\n ' * 8 } The time is now: { datetime .datetime .now ().isoformat (sep = ' ' )} \n " )
33+ return f"{ '\n ' * 8 } The time is now: { datetime .datetime .now ().isoformat (sep = ' ' )} \n "
3434
3535
3636def _name_for_coro (coro : Coroutine [Any , Any , Any ] | None ) -> str :
@@ -44,22 +44,22 @@ def _name_for_coro(coro: Coroutine[Any, Any, Any] | None) -> str:
4444 return "(unknown)"
4545
4646
47- def debug_info (clictx : CliContext ) -> None :
47+ def debug_info (clictx : CliContext ) -> str :
4848 """Prints debugging information on tasks and CliContext"""
49- puts ( "*** BEGIN DEBUG INFO: ***" )
50- puts ( "Tasks:" )
49+ ret = "*** BEGIN DEBUG INFO: ***\n "
50+ ret += "Tasks:\n "
5151 for i , task in enumerate (asyncio .all_tasks (asyncio .get_event_loop ()), 1 ):
5252 coro = task .get_coro ()
53- puts (
53+ ret += (
5454 f" { i :02n} { task .get_name ():32s} "
5555 f"state={ task ._state .lower ():8s} "
56- f"coro={ _name_for_coro (coro )} "
56+ f"coro={ _name_for_coro (coro )} \n "
5757 )
58- puts ( "CliContext:" )
58+ ret += "CliContext:\n "
5959 maxlen = max ([len (k ) for k in clictx .__dict__ .keys ()])
6060 for attr , value in clictx .__dict__ .items ():
61- puts ( f" { attr :>{maxlen }s} = { value !r} " )
62- puts ( "*** END DEBUG INFO: ***" )
61+ ret += f" { attr :>{maxlen }s} = { value !r} \n "
62+ return ret + "*** END DEBUG INFO: ***"
6363
6464
6565_LOGLEVELS = {
@@ -71,33 +71,33 @@ def debug_info(clictx: CliContext) -> None:
7171}
7272
7373
74- def adjust_loglevel (_ : CliContext , change : int ) -> None :
74+ def adjust_loglevel (_ : CliContext , change : int ) -> str | None :
7575 """Adjusts the log level"""
7676 rootlogger = logging .getLogger ()
7777 newlevel = rootlogger .getEffectiveLevel () + change
7878 if newlevel < logging .DEBUG or newlevel > logging .CRITICAL :
79- return
79+ return None
8080
8181 rootlogger .setLevel (newlevel )
82- puts ( f"Log level now at { _LOGLEVELS [logger .getEffectiveLevel ()]} " )
82+ return f"Log level now at { _LOGLEVELS [logger .getEffectiveLevel ()]} "
8383
8484
8585@dataclass
8686class KeyAndFunc [ContextT : CliContext ]:
8787 key : str
88- func : Callable [[ContextT ], None ]
88+ func : Callable [[ContextT ], str | None ]
8989
9090
9191type KeyCmdMapType [ContextT : CliContext ] = dict [int , KeyAndFunc [ContextT ]]
9292
9393
9494def print_help [ContextT : CliContext ](
9595 _ : ContextT , key_to_cmd : KeyCmdMapType [ContextT ]
96- ) -> None :
97- puts ( "Keys I know about for debugging:" )
96+ ) -> str :
97+ ret = "Keys I know about for debugging:\n "
9898 for keyfunc in key_to_cmd .values ():
99- puts ( f" { keyfunc .key :5s} { keyfunc .func .__doc__ } " )
100- puts ( " ? Print this message" )
99+ ret += f" { keyfunc .key :5s} { keyfunc .func .__doc__ } \n "
100+ return ret + " ? Print this message"
101101
102102
103103try :
@@ -106,7 +106,10 @@ def print_help[ContextT: CliContext](
106106 import tty
107107
108108 async def _monitor_stdin [ContextT : CliContext ]( # pyright: ignore[reportRedeclaration]
109- clictx : ContextT , key_to_cmd : KeyCmdMapType [ContextT ]
109+ clictx : ContextT ,
110+ key_to_cmd : KeyCmdMapType [ContextT ],
111+ * ,
112+ puts : Callable [[str ], Any ] = puts ,
110113 ) -> None :
111114 fd = sys .stdin .fileno ()
112115 termios_saved = termios .tcgetattr (fd )
@@ -125,12 +128,13 @@ async def _monitor_stdin[ContextT: CliContext]( # pyright: ignore[reportRedecla
125128 continue
126129
127130 if (key := ord (ch )) == 0x3F :
128- print_help (clictx , key_to_cmd )
131+ puts ( print_help (clictx , key_to_cmd ) )
129132
130133 elif (keyfunc := key_to_cmd .get (key )) is not None and callable (
131134 keyfunc .func
132135 ):
133- keyfunc .func (clictx )
136+ if (ret := keyfunc .func (clictx )) is not None :
137+ puts (ret )
134138
135139 else :
136140 logger .debug (f"Ignoring character 0x{ key :02x} on stdin" )
@@ -143,16 +147,22 @@ async def _monitor_stdin[ContextT: CliContext]( # pyright: ignore[reportRedecla
143147except ImportError :
144148
145149 async def _monitor_stdin [ContextT : CliContext ](
146- clictx : ContextT , key_to_cmd : KeyCmdMapType [ContextT ]
150+ clictx : ContextT ,
151+ key_to_cmd : KeyCmdMapType [ContextT ],
152+ * ,
153+ puts : Callable [[str ], Any ] = puts ,
147154 ) -> None :
148- _ = clictx , key_to_cmd
155+ _ = clictx , key_to_cmd , puts
149156 logger .warning ("The 'debug' plugin does not work on this platform" )
150157 return None
151158
152159
153160@asynccontextmanager
154161async def monitor_stdin_for_debug_commands [ContextT : CliContext ](
155- clictx : CliContext , * , key_to_cmd : KeyCmdMapType [ContextT ] | None = None
162+ clictx : CliContext ,
163+ * ,
164+ key_to_cmd : KeyCmdMapType [ContextT ] | None = None ,
165+ puts : Callable [[str ], Any ] = puts ,
156166) -> PluginLifespan :
157167 key_to_cmd = key_to_cmd or {}
158168
@@ -169,7 +179,7 @@ async def monitor_stdin_for_debug_commands[ContextT: CliContext](
169179 0x2D : KeyAndFunc ("-" , decrease_loglevel ),
170180 ** key_to_cmd ,
171181 }
172- yield _monitor_stdin (clictx , map )
182+ yield _monitor_stdin (clictx , map , puts = puts )
173183
174184
175185@plugin
0 commit comments