-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #401 from juaml/enh/config_manager
[ENH]: Introduce `ConfigManager`
- Loading branch information
Showing
19 changed files
with
204 additions
and
27 deletions.
There are no files selected for viewing
This file contains 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 @@ | ||
Introduce :class:`junifer.utils.ConfigManager` singleton class to manage global configuration by `Fede Raimondo`_ |
This file contains 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 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 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 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 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 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 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 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 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 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 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 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 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 |
---|---|---|
@@ -1,15 +1,18 @@ | ||
__all__ = [ | ||
"make_executable", | ||
"configure_logging", | ||
"config", | ||
"logger", | ||
"raise_error", | ||
"warn_with_log", | ||
"run_ext_cmd", | ||
"deep_update", | ||
"yaml", | ||
"ConfigManager", | ||
] | ||
|
||
from .fs import make_executable | ||
from .logging import configure_logging, logger, raise_error, warn_with_log | ||
from ._config import config, ConfigManager | ||
from .helpers import run_ext_cmd, deep_update | ||
from ._yaml import yaml |
This file contains 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,110 @@ | ||
"""Provide junifer global configuration.""" | ||
|
||
# Authors: Federico Raimondo <[email protected]> | ||
# Synchon Mandal <[email protected]> | ||
# License: AGPL | ||
|
||
import os | ||
from typing import Optional | ||
|
||
from ..typing import ConfigVal | ||
from .logging import logger | ||
from .singleton import Singleton | ||
|
||
|
||
__all__ = ["ConfigManager", "config"] | ||
|
||
|
||
class ConfigManager(metaclass=Singleton): | ||
"""Manage configuration parameters. | ||
Attributes | ||
---------- | ||
_config : dict | ||
Configuration parameters. | ||
""" | ||
|
||
def __init__(self) -> None: | ||
"""Initialize the class.""" | ||
self._config = {} | ||
# Initial setup from process env | ||
self._reload() | ||
|
||
def _reload(self) -> None: | ||
"""Reload env vars.""" | ||
for t_var in os.environ: | ||
if t_var.startswith("JUNIFER_"): | ||
# Set correct type | ||
var_value = os.environ[t_var] | ||
# bool | ||
if var_value.lower() == "true": | ||
var_value = True | ||
elif var_value.lower() == "false": | ||
var_value = False | ||
# numeric | ||
else: | ||
try: | ||
var_value = int(var_value) | ||
except ValueError: | ||
try: | ||
var_value = float(var_value) | ||
except ValueError: | ||
pass | ||
# Set value | ||
var_name = ( | ||
t_var.replace("JUNIFER_", "").lower().replace("_", ".") | ||
) | ||
logger.debug( | ||
f"Setting `{var_name}` from environment to " | ||
f"`{var_value}` (type: {type(var_value)})" | ||
) | ||
self._config[var_name] = var_value | ||
|
||
def get(self, key: str, default: Optional[ConfigVal] = None) -> ConfigVal: | ||
"""Get configuration parameter. | ||
Parameters | ||
---------- | ||
key : str | ||
The configuration key to get. | ||
default : bool or int or float or None, optional | ||
The default value to return if the key is not found (default None). | ||
Returns | ||
------- | ||
bool or int or float | ||
The configuration value. | ||
""" | ||
return self._config.get(key, default) | ||
|
||
def set(self, key: str, val: ConfigVal) -> None: | ||
"""Set configuration parameter. | ||
Parameters | ||
---------- | ||
key : str | ||
The configuration key to set. | ||
val : bool or int or float | ||
The value to set ``key`` to. | ||
""" | ||
logger.debug(f"Setting `{key}` to `{val}` (type: {type(val)})") | ||
self._config[key] = val | ||
|
||
def delete(self, key: str) -> None: | ||
"""Delete configuration parameter. | ||
Parameters | ||
---------- | ||
key : str | ||
The configuration key to delete. | ||
""" | ||
logger.debug(f"Deleting `{key}` from config") | ||
_ = self._config.pop(key) | ||
|
||
|
||
# Initialize here to access from anywhere | ||
config = ConfigManager() |
This file contains 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 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 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 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,59 @@ | ||
"""Provide tests for ConfigManager.""" | ||
|
||
# Authors: Federico Raimondo <[email protected]> | ||
# Synchon Mandal <[email protected]> | ||
# License: AGPL | ||
|
||
import os | ||
|
||
import pytest | ||
|
||
from junifer.typing import ConfigVal | ||
from junifer.utils import config | ||
from junifer.utils._config import ConfigManager | ||
|
||
|
||
def test_config_manager_singleton() -> None: | ||
"""Test that ConfigManager is a singleton.""" | ||
config_mgr_1 = ConfigManager() | ||
config_mgr_2 = ConfigManager() | ||
assert id(config_mgr_1) == id(config_mgr_2) | ||
|
||
|
||
def test_config_manager() -> None: | ||
"""Test config operations for ConfigManager.""" | ||
# Get non-existing with default | ||
assert config.get(key="scooby") is None | ||
# Set | ||
config.set(key="scooby", val=True) | ||
# Get existing | ||
assert config.get("scooby") | ||
# Delete | ||
config.delete("scooby") | ||
# Get non-existing with default | ||
assert config.get(key="scooby") is None | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"val, expected_val", | ||
[("TRUE", True), ("FALSE", False), ("1", 1), ("0.0", 0.0)], | ||
) | ||
def test_config_manager_env_reload(val: str, expected_val: ConfigVal) -> None: | ||
"""Test config parsing from env reload. | ||
Parameters | ||
---------- | ||
val : str | ||
The parametrized values. | ||
expected_val : bool or int or float | ||
The parametrized expected value. | ||
""" | ||
# Set env var | ||
os.environ["JUNIFER_TESTME"] = val | ||
# Check | ||
config._reload() | ||
assert config.get("testme") == expected_val | ||
# Cleanup | ||
del os.environ["JUNIFER_TESTME"] | ||
config.delete("testme") |