Skip to content

Commit 12471d1

Browse files
committed
Allow print function to be injected for debug messages
1 parent 750a9fb commit 12471d1

File tree

1 file changed

+37
-27
lines changed

1 file changed

+37
-27
lines changed

click_async_plugins/debug.py

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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

3636
def _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
8686
class KeyAndFunc[ContextT: CliContext]:
8787
key: str
88-
func: Callable[[ContextT], None]
88+
func: Callable[[ContextT], str | None]
8989

9090

9191
type KeyCmdMapType[ContextT: CliContext] = dict[int, KeyAndFunc[ContextT]]
9292

9393

9494
def 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

103103
try:
@@ -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
143147
except 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
154161
async 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

Comments
 (0)