diff --git a/cliconfig/__init__.py b/cliconfig/__init__.py index a49433e..cde79bd 100644 --- a/cliconfig/__init__.py +++ b/cliconfig/__init__.py @@ -12,8 +12,8 @@ .. include:: ../DOCUMENTATION.md """ - from cliconfig import ( + _logger, base, cli_parser, config_routines, @@ -22,6 +22,7 @@ processing, tag_routines, ) +from cliconfig._logger import create_logger from cliconfig._version import __version__, __version_tuple__ from cliconfig.base import Config from cliconfig.config_routines import ( @@ -46,9 +47,13 @@ create_processing_value, ) +_CLICONFIG_LOGGER = create_logger() + __all__ = [ "__version__", "__version_tuple__", + "_CLICONFIG_LOGGER", + "_logger", "Config", "DefaultProcessings", "Processing", diff --git a/cliconfig/_logger.py b/cliconfig/_logger.py new file mode 100644 index 0000000..04312d6 --- /dev/null +++ b/cliconfig/_logger.py @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Valentin Goldite. All Rights Reserved. +"""Logging functions for cliconfig.""" +import logging +import sys +from logging import Logger + + +def create_logger() -> Logger: + """Create cliconfig logger.""" + logger = logging.getLogger(__name__) + logger.setLevel(logging.INFO) + handler = logging.StreamHandler(sys.stdout) + formatter = logging.Formatter("%(levelname)s - %(message)s") + handler.setFormatter(formatter) + logger.addHandler(handler) + return logger diff --git a/cliconfig/config_routines.py b/cliconfig/config_routines.py index 25abd53..2270636 100644 --- a/cliconfig/config_routines.py +++ b/cliconfig/config_routines.py @@ -1,10 +1,10 @@ # Copyright (c) 2023 Valentin Goldite. All Rights Reserved. """Low-level and high-level functions to manipulate config.""" -import logging import sys from copy import deepcopy from typing import Any, Dict, List, Optional, Union +import cliconfig from cliconfig.base import Config from cliconfig.cli_parser import parse_cli from cliconfig.dict_routines import flatten, show_dict, unflatten @@ -84,6 +84,7 @@ def make_config( does NOT raise an error but only a warning. This ensures the compatibility with other CLI usage (e.g notebook, argparse, etc.) """ + logger = cliconfig._CLICONFIG_LOGGER # pylint: disable=W0212 # Create the processing list process_list_: List[Processing] = [] if process_list is None else process_list if add_default_processing: @@ -124,23 +125,21 @@ def make_config( if new_keys: new_keys_message = " - " + "\n - ".join(new_keys) message = ( - "[CONFIG] Warning: New keys found in CLI parameters " + "[CONFIG] New keys found in CLI parameters " f"that will not be merged:\n{new_keys_message}" ) - logging.warning(message) - print(message) + logger.warning(message) # Merge CLI parameters cli_params_config = Config(cli_params_dict, []) config = merge_flat_processing( config, cli_params_config, allow_new_keys=False, preprocess_first=False ) message = ( - f"[CONFIG] Info: Merged {len(default_config_paths)} default config(s), " + f"[CONFIG] Merged {len(default_config_paths)} default config(s), " f"{len(additional_config_paths)} additional config(s) and " f"{len(cli_params_dict)} CLI parameter(s)." ) - logging.info(message) - print(message) + logger.info(message) config = end_build_processing(config) config.dict = unflatten(config.dict) return config diff --git a/tests/unit/test_config_routines.py b/tests/unit/test_config_routines.py index 1fc8151..2cb61a8 100644 --- a/tests/unit/test_config_routines.py +++ b/tests/unit/test_config_routines.py @@ -22,7 +22,10 @@ from cliconfig.processing.builtin import ProcessCopy -def test_make_config(capsys: pytest.CaptureFixture, process_add1: Processing) -> None: +def test_make_config( + caplog: pytest.LogCaptureFixture, + process_add1: Processing, +) -> None: """Test make_config.""" sys_argv = sys.argv.copy() sys.argv = [ @@ -33,15 +36,13 @@ def test_make_config(capsys: pytest.CaptureFixture, process_add1: Processing) -> "--param2@add1=6", "--unknown2=8", # check that not error but a warning in console ] - capsys.readouterr() # Clear stdout and stderr + caplog.clear() config = make_config( "tests/configs/default1.yaml", "tests/configs/default2.yaml", process_list=[process_add1], fallback="tests/configs/fallback.yaml", ) - captured = capsys.readouterr() - out = captured.out expected_config = { "param1": 4, "param2": 7, @@ -54,15 +55,18 @@ def test_make_config(capsys: pytest.CaptureFixture, process_add1: Processing) -> }, "processing name": "ProcessAdd1", } - expected_out = ( - "[CONFIG] Warning: New keys found in CLI parameters that will not be merged:\n" + expected_out1 = ( + "[CONFIG] New keys found in CLI parameters that will not be merged:\n" " - unknown\n" " - unknown2\n" - "[CONFIG] Info: Merged 2 default config(s), " - "2 additional config(s) and 1 CLI parameter(s).\n" + ) + expected_out2 = ( + "[CONFIG] Merged 2 default config(s), 2 additional config(s) " + "and 1 CLI parameter(s)." ) check.equal(config.dict, expected_config) - check.equal(out, expected_out) + check.is_in(expected_out1, caplog.text) + check.is_in(expected_out2, caplog.text) # No additional configs and fallback sys.argv = [ diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py new file mode 100644 index 0000000..edf56ad --- /dev/null +++ b/tests/unit/test_logger.py @@ -0,0 +1,22 @@ +# Copyright (c) 2023 Valentin Goldite. All Rights Reserved. +"""Tests for dict routines.""" +import pytest +import pytest_check as check + +from cliconfig._logger import create_logger + + +def test_create_logger( + caplog: pytest.CaptureFixture, + capsys: pytest.CaptureFixture, +) -> None: + """Test create_logger.""" + logger = create_logger() + logger.info("This is an info message.") + check.is_true("INFO cliconfig._logger:test_logger.py:" in caplog.text) + check.is_true(" This is an info message." in caplog.text) + check.is_true("INFO - This is an info message." in capsys.readouterr().out) + logger.warning("This is a warning message.") + check.is_true("WARNING cliconfig._logger:test_logger.py:" in caplog.text) + check.is_true(" This is a warning message." in caplog.text) + check.is_true("WARNING - This is a warning message." in capsys.readouterr().out)