diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index fdda89c..be61197 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -56,4 +56,4 @@ jobs: echo "TAVILY_API_KEY=fake-api-key" >> $GITHUB_ENV - name: Run Pytest - run: poetry run pytest -vv + run: poetry run pytest -vv --cov=polymind --cov-config=pyproject.toml -vv tests diff --git a/poetry.lock b/poetry.lock index 5bf407d..de1b39d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -599,6 +599,73 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] development = ["black", "flake8", "mypy", "pytest", "types-colorama"] +[[package]] +name = "coverage" +version = "7.6.0" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd"}, + {file = "coverage-7.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb"}, + {file = "coverage-7.6.0-cp310-cp310-win32.whl", hash = "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c"}, + {file = "coverage-7.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169"}, + {file = "coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933"}, + {file = "coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63"}, + {file = "coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713"}, + {file = "coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1"}, + {file = "coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"}, + {file = "coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605"}, + {file = "coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da"}, + {file = "coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67"}, + {file = "coverage-7.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b"}, + {file = "coverage-7.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b"}, + {file = "coverage-7.6.0-cp38-cp38-win32.whl", hash = "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428"}, + {file = "coverage-7.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8"}, + {file = "coverage-7.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c"}, + {file = "coverage-7.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd"}, + {file = "coverage-7.6.0-cp39-cp39-win32.whl", hash = "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2"}, + {file = "coverage-7.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca"}, + {file = "coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6"}, + {file = "coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + [[package]] name = "cryptography" version = "42.0.7" @@ -2252,6 +2319,24 @@ pytest = ">=7.0.0,<9" docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -3242,4 +3327,4 @@ openai = ["openai"] [metadata] lock-version = "2.0" python-versions = ">=3.9, <3.13" -content-hash = "1c098ac48f0da4fac9c679f575ebd54613f838804048721ac8427da9599475c1" +content-hash = "181dc6e96227468b46e324535e100158e68ce26853291fca33428b537c11c313" diff --git a/polymind/core/logger.py b/polymind/core/logger.py index 0ee4841..9ad7911 100644 --- a/polymind/core/logger.py +++ b/polymind/core/logger.py @@ -2,7 +2,7 @@ import logging import os from enum import Enum -from typing import Optional +from typing import Optional, Union from colorama import Fore, ansi from dotenv import load_dotenv @@ -12,57 +12,66 @@ class Logger: _instance = None class LoggingLevel(Enum): - DEBUG = 1 - INFO = 2 - TOOL = 3 - TASK = 4 - THOUGHT_PROCESS = 5 - WARNING = 6 - ERROR = 7 - CRITICAL = 8 - - def __lt__(self, other): - return self.value < other.value - - def __ge__(self, other): - return self.value >= other.value - - def __le__(self, other): - return self.value <= other.value - - def __gt__(self, other): - return self.value > other.value - - def __str__(self) -> str: - return self.name - - def __repr__(self) -> str: - return self.name + DEBUG = logging.DEBUG + INFO = logging.INFO + TOOL = 25 + TASK = 26 + THOUGHT_PROCESS = 27 + WARNING = logging.WARNING + ERROR = logging.ERROR + CRITICAL = logging.CRITICAL + + @classmethod + def from_string(cls, level_string: str): + try: + return cls[level_string.upper()] + except KeyError: + raise ValueError(f"Invalid logging level: {level_string}") def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance - def __init__(self, logger_name: str, verbose: bool = True, level: Optional[LoggingLevel] = None): - if not hasattr(self, "logger"): - load_dotenv(override=True) - self.logging_level = level if level else Logger.LoggingLevel[os.getenv("LOGGING_LEVEL", "TOOL")] - self.logger = logging.getLogger(logger_name) - self.logger.setLevel(level=self.logging_level.value) - self.formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s (%(filename)s:%(lineno)d)") - self.console_handler = logging.StreamHandler() - self.console_handler.setLevel(level=self.logging_level.value) - self.console_handler.setFormatter(self.formatter) - self.logger.addHandler(self.console_handler) + def __init__( + self, + logger_name: str, + verbose: bool = True, + display_level: Optional[Union[LoggingLevel, str]] = None, + ): + load_dotenv(override=True) + + if display_level is None: + env_level = os.getenv("LOGGING_LEVEL", "INFO") + self.logging_level = self.LoggingLevel.from_string(env_level) + elif isinstance(display_level, str): + self.logging_level = self.LoggingLevel.from_string(display_level) + else: + self.logging_level = display_level + + self.logger = logging.getLogger(logger_name) + self.logger.setLevel(self.logging_level.value) + + if self.logger.hasHandlers(): + self.logger.handlers.clear() + + self.formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s (%(filename)s:%(lineno)d)") + self.console_handler = logging.StreamHandler() + self.console_handler.setLevel(self.logging_level.value) + self.console_handler.setFormatter(self.formatter) + self.logger.addHandler(self.console_handler) def log(self, message: str, level: LoggingLevel, color: str = ansi.Fore.GREEN) -> None: - if level >= self.logging_level: - caller_frame = inspect.stack()[2] - caller_name = caller_frame[3] - caller_line = caller_frame[2] + if level.value >= self.logging_level.value: + if len(inspect.stack()) >= 4: + caller_frame = inspect.stack()[3] + else: + caller_frame = inspect.stack()[2] + caller_name = caller_frame.function + caller_line = caller_frame.lineno message = f"{caller_name}({caller_line}): {message}" - self.logger.info(color + message + Fore.RESET) + log_message = color + message + Fore.RESET + self.logger.log(level.value, log_message) def debug(self, message: str) -> None: self.log(message, Logger.LoggingLevel.DEBUG, Fore.BLACK) diff --git a/pyproject.toml b/pyproject.toml index cdc91a4..8071bb3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "polymind" -version = "0.0.56" # Update this version before publishing to PyPI +version = "0.0.57" # Update this version before publishing to PyPI description = "PolyMind is a customizable collaborative multi-agent framework for collective intelligence and distributed problem solving." authors = ["TechTao"] license = "MIT License" @@ -24,6 +24,7 @@ pymilvus = { version = "2.3.7", optional = true } dspy-ai = "^2.4.9" rdflib = "^7.0.0" flake8 = "^7.1.0" +pytest-cov = "^5.0.0" [tool.poetry.group.dev.dependencies] black = "^24.2.0" @@ -34,6 +35,7 @@ pytest = "^8.1.1" pytest-asyncio = "^0.23.5.post1" vulture = "^2.11" flake8-pyproject = "^1.2.3" +coverage = "^7.6.0" [tool.poetry.extras] openai = ["openai"] @@ -54,3 +56,11 @@ ignore = ["Q000", "E203"] [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" + +[tool.pytest.ini_options] +minversion = "6.0" +addopts = [ + "--cov=your_module_name", + "--cov-fail-under=67" +] + diff --git a/tests/polymind/core/test_logger.py b/tests/polymind/core/test_logger.py new file mode 100644 index 0000000..e95e34e --- /dev/null +++ b/tests/polymind/core/test_logger.py @@ -0,0 +1,201 @@ +"""Run the tests with command: + poetry run pytest tests/polymind/core/test_logger.py -vv +""" + +import logging +from unittest.mock import MagicMock, patch + +import pytest +from colorama import Fore + +from polymind.core.logger import Logger + + +class TestLogger: + + @pytest.fixture(scope="function") + def setup_logger(self, tmp_path): + log_folder = tmp_path / "logs" + log_folder.mkdir() + logger = Logger(logger_name="test_logger", display_level="INFO") + return logger + + def test_initialization(self, setup_logger): + logger = setup_logger + assert ( + logger.logging_level == Logger.LoggingLevel.INFO + ), f"Logger level is incorrect: {logger.logging_level} != INFO" + assert logger.logger.level == logging.INFO, f"Logger level is not set correctly: {logger.logger.level} != INFO" + assert len(logger.logger.handlers) == 1, "Logger handlers are not initialized properly" + + def test_logging_levels(self, setup_logger): + logger = setup_logger + logger.info("Info message") + logger.warning("Warning message") + assert ( + logger.logging_level == Logger.LoggingLevel.INFO + ), f"Logger level is incorrect: {logger.logging_level} != INFO" + assert logger.logger.level == logging.INFO, f"Logger level is not set correctly: {logger.logger.level} != INFO" + + @patch("inspect.stack", return_value=[None, None, None, MagicMock(function="test_func", lineno=42)]) + def test_log_method(self, mock_stack, setup_logger): + logger = setup_logger + logger.log("Test log message", Logger.LoggingLevel.INFO, color=Fore.WHITE) + log_message = "test_func(42): Test log message" + log_output = f"{Fore.WHITE}{log_message}{Fore.RESET}" + formatted_message = logger.formatter.format( + logging.LogRecord( + name="test_logger", + level=logging.INFO, + pathname="", + lineno=42, + msg=log_output, + args=None, + exc_info=None, + ) + ) + assert log_message in formatted_message, "Log message is incorrect" + + def test_debug_log(self, setup_logger): + logger = setup_logger + logger.debug("Debug message") + log_message = "pytest_pyfunc_call(1): Debug message" + log_output = f"{Fore.BLACK}{log_message}{Fore.RESET}" + formatted_message = logger.formatter.format( + logging.LogRecord( + name="test_logger", + level=logging.DEBUG, + pathname="", + lineno=1, + msg=log_output, + args=None, + exc_info=None, + ) + ) + assert log_message in formatted_message, "Debug log message is incorrect" + + def test_info_log(self, setup_logger): + logger = setup_logger + logger.info("Info message") + log_message = "pytest_pyfunc_call(1): Info message" + log_output = f"{Fore.WHITE}{log_message}{Fore.RESET}" + formatted_message = logger.formatter.format( + logging.LogRecord( + name="test_logger", + level=logging.INFO, + pathname="", + lineno=1, + msg=log_output, + args=None, + exc_info=None, + ) + ) + assert log_message in formatted_message, "Info log message is incorrect" + + def test_tool_log(self, setup_logger): + logger = setup_logger + logger.tool_log("Tool log message") + log_message = "pytest_pyfunc_call(1): Tool log message" + log_output = f"{Fore.YELLOW}{log_message}{Fore.RESET}" + formatted_message = logger.formatter.format( + logging.LogRecord( + name="test_logger", + level=logging.INFO, + pathname="", + lineno=1, + msg=log_output, + args=None, + exc_info=None, + ) + ) + assert log_message in formatted_message, "Tool log message is incorrect" + + def test_task_log(self, setup_logger): + logger = setup_logger + logger.task_log("Task log message") + log_message = "pytest_pyfunc_call(1): Task log message" + log_output = f"{Fore.BLUE}{log_message}{Fore.RESET}" + formatted_message = logger.formatter.format( + logging.LogRecord( + name="test_logger", + level=logging.INFO, + pathname="", + lineno=1, + msg=log_output, + args=None, + exc_info=None, + ) + ) + assert log_message in formatted_message, "Task log message is incorrect" + + def test_thought_process_log(self, setup_logger): + logger = setup_logger + logger.thought_process_log("Thought process log message") + log_message = "pytest_pyfunc_call(1): Thought process log message" + log_output = f"{Fore.GREEN}{log_message}{Fore.RESET}" + formatted_message = logger.formatter.format( + logging.LogRecord( + name="test_logger", + level=logging.INFO, + pathname="", + lineno=1, + msg=log_output, + args=None, + exc_info=None, + ) + ) + assert log_message in formatted_message, "Thought process log message is incorrect" + + def test_warning_log(self, setup_logger): + logger = setup_logger + logger.warning("Warning message") + log_message = "pytest_pyfunc_call(1): Warning message" + log_output = f"{Fore.YELLOW}{log_message}{Fore.RESET}" + formatted_message = logger.formatter.format( + logging.LogRecord( + name="test_logger", + level=logging.WARNING, + pathname="", + lineno=1, + msg=log_output, + args=None, + exc_info=None, + ) + ) + assert log_message in formatted_message, "Warning log message is incorrect" + + def test_error_log(self, setup_logger): + logger = setup_logger + logger.error("Error message") + log_message = "pytest_pyfunc_call(1): Error message" + log_output = f"{Fore.RED}{log_message}{Fore.RESET}" + formatted_message = logger.formatter.format( + logging.LogRecord( + name="test_logger", + level=logging.ERROR, + pathname="", + lineno=1, + msg=log_output, + args=None, + exc_info=None, + ) + ) + assert log_message in formatted_message, "Error log message is incorrect" + + def test_critical_log(self, setup_logger): + logger = setup_logger + logger.critical("Critical message") + log_message = "pytest_pyfunc_call(1): Critical message" + log_output = f"{Fore.MAGENTA}{log_message}{Fore.RESET}" + formatted_message = logger.formatter.format( + logging.LogRecord( + name="test_logger", + level=logging.CRITICAL, + pathname="", + lineno=1, + msg=log_output, + args=None, + exc_info=None, + ) + ) + assert log_message in formatted_message, "Critical log message is incorrect"