Skip to content
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

✨ Improve cliconfig logging #80

Merged
merged 4 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion cliconfig/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

.. include:: ../DOCUMENTATION.md
"""

from cliconfig import (
_logger,
base,
cli_parser,
config_routines,
Expand All @@ -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 (
Expand All @@ -46,9 +47,13 @@
create_processing_value,
)

_CLICONFIG_LOGGER = create_logger()

__all__ = [
"__version__",
"__version_tuple__",
"_CLICONFIG_LOGGER",
"_logger",
"Config",
"DefaultProcessings",
"Processing",
Expand Down
16 changes: 16 additions & 0 deletions cliconfig/_logger.py
Original file line number Diff line number Diff line change
@@ -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
13 changes: 6 additions & 7 deletions cliconfig/config_routines.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
22 changes: 13 additions & 9 deletions tests/unit/test_config_routines.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -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,
Expand All @@ -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 = [
Expand Down
22 changes: 22 additions & 0 deletions tests/unit/test_logger.py
Original file line number Diff line number Diff line change
@@ -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)
Loading