Skip to content

Instantly share code, notes, and snippets.

@mahenzon
Created November 30, 2024 20:08
Show Gist options
  • Save mahenzon/dc2310699d793a814ea12a4050130862 to your computer and use it in GitHub Desktop.
Save mahenzon/dc2310699d793a814ea12a4050130862 to your computer and use it in GitHub Desktop.
Annotation for decorator creator in Python
import logging
# DEFAULT_LOG_FORMAT = "[%(asctime)s.%(msecs)03d] %(funcName)20s %(module)s:%(lineno)d %(levelname)-8s - %(message)s"
DEFAULT_LOG_FORMAT = (
"%(funcName)10s %(module)s:%(lineno)d %(levelname)-8s - %(message)s"
)
def configure_logging(level: int = logging.INFO) -> None:
logging.basicConfig(
level=level,
datefmt="%Y-%m-%d %H:%M:%S",
format=DEFAULT_LOG_FORMAT,
)
import logging
from dataclasses import dataclass
from functools import wraps
from typing import Callable, ParamSpec, TypeVar
from common import configure_logging
log = logging.getLogger(__name__)
P = ParamSpec("P")
T = TypeVar("T")
@dataclass
class Counts:
count: int = 0
def inc(self) -> None:
self.count += 1
def dec(self) -> None:
self.count -= 1
def trace(
*,
sep: str = "*",
size: int = 1,
) -> Callable[[Callable[P, T]], Callable[P, T]]:
def decorator(func: Callable[P, T]) -> Callable[P, T]:
count = Counts()
@wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
count.inc()
log.info(
"%s call %r with args %r and kwargs %r",
sep * count.count * size,
func.__name__,
args,
kwargs,
)
result = func(*args, **kwargs)
log.info(
"%s call %r result: %r",
sep * count.count * size,
func.__name__,
result,
)
count.dec()
return result
return wrapper
return decorator
@trace()
def fac(n: int) -> int:
if n <= 2:
return n
return n * fac(n - 1)
@trace(sep="|", size=2)
def fib(n: int) -> int:
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
def main() -> None:
configure_logging()
fac5 = fac(5)
log.info("fac(5) = %s", fac5)
log.warning("space")
fac7 = fac(7)
log.info("fac(7) = %s", fac7)
log.warning("space bigger")
fib3 = fib(3)
log.info("fib(3) = %s", fib3)
log.warning("space")
fib4 = fib(4)
log.info("fib(4) = %s", fib4)
if __name__ == "__main__":
main()
[tool.mypy]
strict = true
mypy==1.13.0
mypy-extensions==1.0.0
typing_extensions==4.12.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment