Skip to content

Commit

Permalink
feat: loader conditionals (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
maxb2 authored May 25, 2023
1 parent edadf7c commit 4bb82de
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 8 deletions.
17 changes: 15 additions & 2 deletions tests/test_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,13 @@ def main(
(str(HERE.joinpath("config.env")), typer_config.dotenv_conf_callback),
(
str(HERE.joinpath("config.ini")),
# Have to make one dynamically because of the required INI section
typer_config.conf_callback_factory(
typer_config.loaders.subpath_loader(
typer_config.loaders.ini_loader, ["simple_app"]
typer_config.loaders.loader_transformer(
typer_config.loaders.subpath_loader(
typer_config.loaders.ini_loader, ["simple_app"]
),
loader_conditional=lambda param_value: param_value,
)
),
),
Expand All @@ -55,6 +59,11 @@ def test_simple_example(simple_app, confs):
conf, callback = confs
_app = simple_app(callback)

result = RUNNER.invoke(_app, ["--help"])
assert (
result.exit_code == 0
), f"Couldn't get to `--help` for {conf}\n\n{result.stdout}"

result = RUNNER.invoke(_app, ["--config", conf])
assert result.exit_code == 0, f"Loading failed for {conf}\n\n{result.stdout}"
assert (
Expand Down Expand Up @@ -90,6 +99,10 @@ def test_pyproject_example_deprecated(simple_app):

_app = simple_app(pyproject_callback)

result = RUNNER.invoke(_app, ["--help"])

assert result.exit_code == 0, f"{result.stdout}"

result = RUNNER.invoke(_app)

assert result.exit_code == 0, f"{result.stdout}"
Expand Down
26 changes: 21 additions & 5 deletions typer_config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
from typer import BadParameter, CallbackParam, Context

from .__typing import ConfigLoader, ConfigParameterCallback, TyperParameterValue
from .loaders import dotenv_loader, json_loader, toml_loader, yaml_loader
from .loaders import (
dotenv_loader,
json_loader,
toml_loader,
yaml_loader,
loader_transformer,
)


def conf_callback_factory(loader: ConfigLoader) -> ConfigParameterCallback:
Expand Down Expand Up @@ -48,7 +54,9 @@ def _callback(
return _callback


yaml_conf_callback: ConfigParameterCallback = conf_callback_factory(yaml_loader)
yaml_conf_callback: ConfigParameterCallback = conf_callback_factory(
loader_transformer(yaml_loader, loader_conditional=lambda param_value: param_value)
)
"""YAML typer config parameter callback.
Args:
Expand All @@ -64,7 +72,9 @@ def _callback(
TyperParameterValue: must return back the given parameter
"""

json_conf_callback: ConfigParameterCallback = conf_callback_factory(json_loader)
json_conf_callback: ConfigParameterCallback = conf_callback_factory(
loader_transformer(json_loader, loader_conditional=lambda param_value: param_value)
)
"""JSON typer config parameter callback.
Args:
Expand All @@ -81,7 +91,9 @@ def _callback(
"""


toml_conf_callback: ConfigParameterCallback = conf_callback_factory(toml_loader)
toml_conf_callback: ConfigParameterCallback = conf_callback_factory(
loader_transformer(toml_loader, loader_conditional=lambda param_value: param_value)
)
"""TOML typer config parameter callback.
Args:
Expand All @@ -97,7 +109,11 @@ def _callback(
TyperParameterValue: must return back the given parameter
"""

dotenv_conf_callback: ConfigParameterCallback = conf_callback_factory(dotenv_loader)
dotenv_conf_callback: ConfigParameterCallback = conf_callback_factory(
loader_transformer(
dotenv_loader, loader_conditional=lambda param_value: param_value
)
)
"""Dotenv typer config parameter callback.
Args:
Expand Down
3 changes: 3 additions & 0 deletions typer_config/__typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
ConfigLoader: TypeAlias = Callable[[TyperParameterValue], ConfigDict]
"""Configuration loader function."""

ConfigLoaderConditional: TypeAlias = Callable[[TyperParameterValue], bool]
"""Configuration loader conditional function."""

ConfigParameterCallback: TypeAlias = Callable[
[Context, CallbackParam, TyperParameterValue], TyperParameterValue
]
Expand Down
13 changes: 12 additions & 1 deletion typer_config/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
ConfigDictAccessorPath,
ConfigDictTransformer,
ConfigLoader,
ConfigLoaderConditional,
NoArgCallable,
TyperParameterValue,
TyperParameterValueTransformer,
Expand Down Expand Up @@ -58,6 +59,7 @@

def loader_transformer(
loader: ConfigLoader,
loader_conditional: Optional[ConfigLoaderConditional] = None,
param_transformer: Optional[TyperParameterValueTransformer] = None,
config_transformer: Optional[ConfigDictTransformer] = None,
) -> ConfigLoader:
Expand Down Expand Up @@ -94,6 +96,8 @@ def loader_transformer(
Args:
loader (ConfigLoader): Loader to transform.
loader_condtional (Optional[ConfigLoaderConditional], optional): Function
to determine whether to execute loader. Defaults to None (no-op).
param_transformer (Optional[TyperParameterValueTransformer], optional): Typer
parameter transformer. Defaults to None (no-op).
config_transformer (Optional[ConfigDictTransformer], optional): Config
Expand All @@ -104,11 +108,18 @@ def loader_transformer(
"""

def _loader(param_value: TyperParameterValue) -> ConfigDict:
# Transform input
if param_transformer is not None:
param_value = param_transformer(param_value)

conf: ConfigDict = loader(param_value)
# Decide whether to execute loader
# NOTE: bad things can happen when `param_value=''`
# such as `--help` not working
conf: ConfigDict = {}
if loader_conditional is None or loader_conditional(param_value):
conf = loader(param_value)

# Transform output
if config_transformer is not None:
conf = config_transformer(conf)

Expand Down

0 comments on commit 4bb82de

Please sign in to comment.