import inspect import logging import os import re from functools import wraps from pathlib import Path from pprint import pformat from textwrap import dedent, indent from typing import Any, Callable from uuid import uuid4 current_directory = Path(__file__).resolve().parent logger = logging.getLogger("test-classifier") logger.setLevel(level=logging.DEBUG) # create console handler and set level to debug console_handler = logging.StreamHandler() console_handler.setLevel(logging.DEBUG) # formatter for console handler console_formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s: %(message)s" ) console_handler.setFormatter(console_formatter) # add console handler to logger logger.addHandler(console_handler) run_name_prompt = """ Create a random name that sounds german or dutch The parts should be separated by underscores and contain only lowercase. Only return the name without any text before or after.""".strip() RUNS_DIR = current_directory / "runs" def initialize_run_directory(model: Callable): response, usage = model(None, run_name_prompt, chat=True) run_name_match = re.search(r"^\w+$", response, re.MULTILINE) existing_run_names = os.listdir(RUNS_DIR) if run_name_match is None or run_name_match.group(0) in existing_run_names: run_name = uuid4().hex else: run_name = run_name_match.group(0) run_directory = RUNS_DIR / run_name run_directory.mkdir(parents=True, exist_ok=False) # create file handler and set level to debug file_handler = logging.FileHandler(run_directory / "output.log") file_handler.setLevel(logging.DEBUG) formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s") file_handler.setFormatter(formatter) # add file handler to logger logger.addHandler(file_handler) logger.info(f"Hello my name is {run_name} and I live in {run_directory}") return run_directory class log_calls: description: str prolog = dedent( """ ---------------------------------------- {description} {func_name}: \tArguments: {arguments} """ ) epilog = dedent( """\tResult: {result} ---------------------------------------- """ ) def __init__(self, description: str, level: int = logging.DEBUG): self.description = description self.level = level def __call__(self, func): @wraps(func) def wrapper(*args, **kwargs): arguments = self._get_named_arguments(func, *args, **kwargs) logger.log( self.level, self.prolog.format( description=self.description, func_name=func.__name__, arguments=indent(pformat(arguments), "\t"), ), ) result = func(*args, **kwargs) logger.log( self.level, self.epilog.format( result=indent(pformat(result), "\t"), ), ) return result return wrapper def _get_named_arguments(self, func: Callable[..., Any], *args, **kwargs): signature = inspect.signature(func) arguments = {} for argument_index, (argument_name, argument) in enumerate( signature.parameters.items() ): if argument_index < len(args): # argument_name is from args value = args[argument_index] elif argument_name in kwargs: # argument_name is from kwargs value = kwargs[argument_name] else: # argument_name is from defaults value = argument.default arguments[argument_name] = value return arguments