From 1b871df3d58c488c17c2d5d4c3a8836505087013 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Tue, 3 Mar 2026 22:10:38 +0100 Subject: [PATCH] Unset loglevel in `amici.sim.sundials._swig_wrappers` This way, that logger will inherit the log level from its parents, and users can set the log level with, e.g., `logging.getLogger("amici.sim.sundials").setLevel(logging.CRITICAL)` without exposing any private modules. Related to #3081. ` --- python/sdist/amici/logging.py | 20 ++++++++++--------- python/sdist/amici/sim/sundials/__init__.py | 5 +++++ .../amici/sim/sundials/_swig_wrappers.py | 2 +- python/tests/test_sbml_import.py | 16 +++++++++++++++ 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/python/sdist/amici/logging.py b/python/sdist/amici/logging.py index 32164003b6..06b2e52acc 100644 --- a/python/sdist/amici/logging.py +++ b/python/sdist/amici/logging.py @@ -118,7 +118,9 @@ def _setup_logger( return log -def set_log_level(logger: logging.Logger, log_level: int | bool) -> None: +def set_log_level( + logger: logging.Logger, log_level: int | bool | None +) -> None: if log_level is not None and log_level is not False: if isinstance(log_level, bool): log_level = logging.DEBUG @@ -139,33 +141,33 @@ def get_logger( **kwargs, ) -> logging.Logger: """ - Returns (if extistant) or creates an AMICI logger + Returns (if exists) or creates an AMICI logger If the AMICI base logger has already been set up, this method will return it or any of its descendant loggers without overriding the settings - i.e. any values supplied as kwargs will be ignored. :param logger_name: - Get a logger for a specific namespace, typically __name__ - for code outside of classes or self.__module__ inside a class + Get a logger for a specific namespace, typically ``__name__`` + for code outside of classes or ``self.__module__`` inside a class :param log_level: Override the default or preset log level for the requested logger. - None or False uses the default or preset value. True evaluates to - logging.DEBUG. Any integer is used directly. + ``None`` or ``False`` uses the default or preset value. ``True`` evaluates to + ``logging.DEBUG``. Any integer is used directly. :param console_output: - Set up a default console log handler if True (default). Only used when + Set up a default console log handler if ``True`` (default). Only used when the AMICI logger hasn't been set up yet. :param file_output: Supply a filename to copy all log output to that file, or set to - False to disable (default). Only used when the AMICI logger hasn't + ``False`` to disable (default). Only used when the AMICI logger hasn't been set up yet. :param capture_warnings: Capture warnings from Python's warnings module if True (default). - Only used when the AMICI logger hasn't been set up yet.. + Only used when the AMICI logger hasn't been set up yet. :return: A logging.Logger object with the requested name diff --git a/python/sdist/amici/sim/sundials/__init__.py b/python/sdist/amici/sim/sundials/__init__.py index 1d8e2209c4..81a5d98c09 100644 --- a/python/sdist/amici/sim/sundials/__init__.py +++ b/python/sdist/amici/sim/sundials/__init__.py @@ -6,6 +6,7 @@ for analyzing the simulation results. """ +import logging import os import warnings from types import ModuleType @@ -13,6 +14,10 @@ import amici from amici import amici_path, import_model_module +from amici.logging import get_logger + +logger = get_logger(__name__, log_level=logging.DEBUG) + #: boolean indicating if this is the full package with swig interface or # the raw package without extension diff --git a/python/sdist/amici/sim/sundials/_swig_wrappers.py b/python/sdist/amici/sim/sundials/_swig_wrappers.py index 6d834e6f0a..9473064c9b 100644 --- a/python/sdist/amici/sim/sundials/_swig_wrappers.py +++ b/python/sdist/amici/sim/sundials/_swig_wrappers.py @@ -30,7 +30,7 @@ from . import ReturnDataView -logger = get_logger(__name__, log_level=logging.DEBUG) +logger = get_logger(__name__, log_level=None) __all__ = [ diff --git a/python/tests/test_sbml_import.py b/python/tests/test_sbml_import.py index 7df760dbad..6918a77893 100644 --- a/python/tests/test_sbml_import.py +++ b/python/tests/test_sbml_import.py @@ -1,5 +1,6 @@ """Tests related to amici.importers.sbml""" +import logging import os import re import sys @@ -229,8 +230,23 @@ def test_logging_works(observable_dependent_error_model, caplog): rdata = run_simulation(model, solver) assert rdata.status != AMICI_SUCCESS + # this is a DEBUG level message and should be there by default assert "mxstep steps taken" in caplog.text + caplog.clear() + + # ensure that we can control amici.sim.sundials._swig_wrappers logging + # via the public amici.sim.sundials logger + logger = logging.getLogger("amici.sim.sundials") + old_lvl = logger.level + try: + logger.setLevel(logging.WARNING) + rdata = run_simulation(model, solver) + assert rdata.status != AMICI_SUCCESS + assert "mxstep steps taken" not in caplog.text + finally: + logger.setLevel(old_lvl) + @skip_on_valgrind def test_model_module_is_set(observable_dependent_error_model):