team-10/venv/Lib/site-packages/watchdog/utils/echo.py
2025-08-02 02:00:33 +02:00

68 lines
2.2 KiB
Python

# echo.py: Tracing function calls using Python decorators.
#
# Written by Thomas Guest <tag@wordaligned.org>
# Please see http://wordaligned.org/articles/echo
#
# Place into the public domain.
"""Echo calls made to functions in a module.
"Echoing" a function call means printing out the name of the function
and the values of its arguments before making the call (which is more
commonly referred to as "tracing", but Python already has a trace module).
Alternatively, echo.echo can be used to decorate functions. Calls to the
decorated function will be echoed.
Example:
-------
@echo.echo
def my_function(args):
pass
"""
from __future__ import annotations
import functools
import sys
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Any, Callable
def format_arg_value(arg_val: tuple[str, tuple[Any, ...]]) -> str:
"""Return a string representing a (name, value) pair."""
arg, val = arg_val
return f"{arg}={val!r}"
def echo(fn: Callable, write: Callable[[str], int | None] = sys.stdout.write) -> Callable:
"""Echo calls to a function.
Returns a decorated version of the input function which "echoes" calls
made to it by writing out the function's name and the arguments it was
called with.
"""
# Unpack function's arg count, arg names, arg defaults
code = fn.__code__
argcount = code.co_argcount
argnames = code.co_varnames[:argcount]
fn_defaults: tuple[Any] = fn.__defaults__ or ()
argdefs = dict(list(zip(argnames[-len(fn_defaults) :], fn_defaults)))
@functools.wraps(fn)
def wrapped(*v: Any, **k: Any) -> Callable:
# Collect function arguments by chaining together positional,
# defaulted, extra positional and keyword arguments.
positional = list(map(format_arg_value, list(zip(argnames, v))))
defaulted = [format_arg_value((a, argdefs[a])) for a in argnames[len(v) :] if a not in k]
nameless = list(map(repr, v[argcount:]))
keyword = list(map(format_arg_value, list(k.items())))
args = positional + defaulted + nameless + keyword
write(f"{fn.__name__}({', '.join(args)})\n")
return fn(*v, **k)
return wrapped