-
Notifications
You must be signed in to change notification settings - Fork 0
feat: specify reasong_effort to improve the time to generate a sentence
#27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
075005d
Add stopwatch decorator and corresponding tests for execution time lo…
hmasdev 7fd353a
Refactor stopwatch to use context manager and update tests for new fu…
hmasdev dfdc3de
Add stopwatch context for OpenAI agent invocation logging
hmasdev eb6a927
Specify reasoning effort parameter for OpenAI agent based on model type
hmasdev 9cc7b07
Merge remote-tracking branch 'origin/main' into feature/specify-reaso…
hmasdev 27bf5a4
Add DEBUG level logging import for enhanced logging capabilities
hmasdev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| import logging | ||
|
hmasdev marked this conversation as resolved.
|
||
| import time | ||
| from contextlib import contextmanager | ||
| from functools import wraps, partial | ||
| from logging import Logger, getLogger | ||
| from typing import Callable, Generator, TypeVar, ParamSpec | ||
|
|
||
| T = TypeVar("T") | ||
| P = ParamSpec("P") | ||
|
|
||
| logger: Logger = getLogger(__name__) | ||
|
|
||
|
|
||
| @contextmanager | ||
| def stopwatch( | ||
| level: int = logging.INFO, | ||
| prefix: str | None = None, | ||
| postfix: str = "", | ||
| logger: Logger = logger, | ||
| ) -> Generator[None, None, None]: | ||
| """Context manager to measure the execution time of a code block. | ||
|
|
||
| Args: | ||
| level (int, optional): log level. Defaults to logging.INFO. | ||
| Must be one of logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL. | ||
| prefix (str | None, optional): prefix of the log message. Defaults to None. | ||
| postfix (str, optional): postfix of the log message. Defaults to "". | ||
| logger (Logger, optional): logger. Defaults to logger. | ||
|
|
||
| Yields: | ||
| None: None | ||
| """ # noqa | ||
|
|
||
| # validation | ||
| if level not in { | ||
| logging.DEBUG, | ||
| logging.INFO, | ||
| logging.WARNING, | ||
| logging.ERROR, | ||
| logging.CRITICAL, | ||
| }: | ||
| raise ValueError( | ||
| f"Invalid log level: {level}. " | ||
| "Must be one of logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL.", # noqa | ||
| ) | ||
|
|
||
| # preparation | ||
| if prefix is None: | ||
| prefix = "Execution time" | ||
|
|
||
| log_msg_fmt: str = f"{prefix}: {{elapsed_time:.6f}} seconds{postfix}" | ||
|
|
||
| log_func = { | ||
| logging.DEBUG: logger.debug, | ||
| logging.INFO: logger.info, | ||
| logging.WARNING: logger.warning, | ||
| logging.ERROR: logger.error, | ||
| logging.CRITICAL: logger.critical, | ||
| }[level] | ||
|
|
||
| # execution | ||
| start_time = time.perf_counter() | ||
| try: | ||
| yield | ||
| finally: | ||
| end_time = time.perf_counter() | ||
| log_func(log_msg_fmt.format(elapsed_time=end_time - start_time)) | ||
|
|
||
|
|
||
| def stopwatch_deco( | ||
| func: Callable[P, T] | None = None, | ||
| *, | ||
| level: int = logging.INFO, | ||
| prefix: str | None = None, | ||
| postfix: str = "", | ||
| logger: Logger = logger, | ||
| ) -> Callable[P, T]: | ||
| """Decorator to measure the execution time of a function. | ||
|
|
||
| Args: | ||
| func (Callable[P, T], optional): function to be decorated. Defaults to None. | ||
| *, | ||
| level (int, optional): log level. Defaults to logging.INFO. | ||
| Must be one of logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL. | ||
| prefix (str | None, optional): prefix of the log message. Defaults to None. | ||
| postfix (str, optional): postfix of the log message. Defaults to "". | ||
| logger (Logger, optional): logger. Defaults to logger. | ||
|
|
||
| Returns: | ||
| Callable[P, T]: decorated function. | ||
|
|
||
| Note: | ||
| If func is None, return a decorator. Otherwise, return a wrapper. | ||
| """ # noqa | ||
|
|
||
| # if func is None, return a decorator | ||
| if func is None: | ||
| return partial( | ||
| stopwatch_deco, | ||
| level=level, | ||
| prefix=prefix, | ||
| postfix=postfix, | ||
| logger=logger, | ||
| ) | ||
|
|
||
| if prefix is None: | ||
| prefix = f"Execution time of {getattr(func, '__name__', str(func))}" | ||
|
|
||
| # if func is not None, return a wrapper | ||
| @wraps(func) | ||
| def wrapped(*args: P.args, **kwargs: P.kwargs) -> T: | ||
| with stopwatch( | ||
| level=level, | ||
| prefix=prefix, | ||
| postfix=postfix, | ||
| logger=logger, | ||
| ): | ||
| result = func(*args, **kwargs) | ||
| return result | ||
|
|
||
| return wrapped | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| import logging | ||
| import re | ||
|
|
||
| import pytest | ||
|
|
||
| from simple_typing_application.utils.stopwatch import stopwatch, stopwatch_deco | ||
|
|
||
|
|
||
| LOGGER_NAME = "simple_typing_application.utils.stopwatch" | ||
|
|
||
|
|
||
| def _latest_record(caplog): | ||
| assert caplog.records, "Expected stopwatch to emit a log record" | ||
| return caplog.records[-1] | ||
|
|
||
|
|
||
| def test_stopwatch_context_manager_logs_default_prefix(caplog): | ||
| caplog.set_level(logging.INFO, logger=LOGGER_NAME) | ||
|
|
||
| with stopwatch(): | ||
| sum(range(5)) | ||
|
|
||
| record = _latest_record(caplog) | ||
| assert record.levelno == logging.INFO | ||
| assert re.match(r"Execution time: \d+\.\d{6} seconds", record.message) | ||
|
|
||
|
|
||
| def test_stopwatch_context_manager_custom_prefix_postfix_and_level(caplog): | ||
| custom_logger = logging.getLogger("tests.utils.stopwatch.ctx") | ||
| caplog.set_level(logging.WARNING, logger=custom_logger.name) | ||
|
|
||
| with stopwatch( | ||
| level=logging.WARNING, | ||
| prefix="Block", | ||
| postfix=" !!!", | ||
| logger=custom_logger, | ||
| ): | ||
| sum(range(10)) | ||
|
|
||
| record = _latest_record(caplog) | ||
| assert record.levelno == logging.WARNING | ||
| assert record.message.startswith("Block: ") | ||
| assert record.message.endswith(" seconds !!!") | ||
|
|
||
|
|
||
| def test_stopwatch_context_manager_invalid_level_raises_value_error(): | ||
| with pytest.raises(ValueError): | ||
| with stopwatch(level=123): | ||
| pass | ||
|
|
||
|
|
||
| def test_stopwatch_decorator_without_parentheses_uses_func_name_in_prefix(caplog): | ||
| caplog.set_level(logging.INFO, logger=LOGGER_NAME) | ||
|
|
||
| @stopwatch_deco | ||
| def greet(name: str) -> str: | ||
| return f"hello {name}" | ||
|
|
||
| assert greet("world") == "hello world" | ||
| record = _latest_record(caplog) | ||
| assert record.levelno == logging.INFO | ||
| assert re.match(r"Execution time of greet: \d+\.\d{6} seconds", record.message) | ||
|
|
||
|
|
||
| def test_stopwatch_decorator_called_with_parentheses(caplog): | ||
| caplog.set_level(logging.INFO, logger=LOGGER_NAME) | ||
|
|
||
| @stopwatch_deco() | ||
| def add(a: int, b: int) -> int: | ||
| return a + b | ||
|
|
||
| assert add(1, 2) == 3 | ||
| record = _latest_record(caplog) | ||
| assert re.match(r"Execution time of add: \d+\.\d{6} seconds", record.message) | ||
|
|
||
|
|
||
| def test_stopwatch_decorator_custom_prefix_and_invalid_level(caplog): | ||
| caplog.set_level(logging.ERROR, logger=LOGGER_NAME) | ||
|
|
||
| @stopwatch_deco( | ||
| prefix="Manual", | ||
| postfix=" !!!", | ||
| level=logging.ERROR, | ||
| ) | ||
| def work() -> None: | ||
| return None | ||
|
|
||
| work() | ||
|
|
||
| record = _latest_record(caplog) | ||
| assert record.levelno == logging.ERROR | ||
| assert record.message.startswith("Manual: ") | ||
| assert record.message.endswith(" seconds !!!") | ||
|
|
||
| @stopwatch_deco(level=123) | ||
| def broken(): | ||
| return None | ||
|
|
||
| with pytest.raises(ValueError): | ||
| broken() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.