Skip to content

Commit

Permalink
feat: dotenv (#15)
Browse files Browse the repository at this point in the history
* deps: add python-dotenv

* feat: dotenv support
  • Loading branch information
maxb2 authored May 17, 2023
1 parent 394f286 commit 28f5e61
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 13 deletions.
2 changes: 1 addition & 1 deletion docs/examples/simple_yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ $ python simple_app.py --config config.yml --opt1 people
people nothing stuff
```

> **Note**: this package also provides `json_conf_callback` and `toml_conf_callback` for those file formats.
> **Note**: this package also provides `json_conf_callback`, `toml_conf_callback`, and `dotenv_conf_callback` for those file formats.
2 changes: 2 additions & 0 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ $ pip install typer-config[yaml] # includes pyyaml

$ pip install typer-config[toml] # includes toml

$ pip install typer-config[python-dotenv] # includes python-dotenv

$ pip install typer-config[all] # includes all optional dependencies
```
34 changes: 25 additions & 9 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ keywords = [
"yaml",
"toml",
"json",
"dotenv",
"cli"
]
classifiers = [
Expand Down Expand Up @@ -44,11 +45,13 @@ python = "^3.8"
typer = "^0"
toml = {version = "^0.10.2", optional = true}
pyyaml = {version = "^6.0", optional = true}
python-dotenv = {version = "*", optional = true}

[tool.poetry.extras]
python-dotenv = ["python-dotenv"]
toml = ["toml"]
yaml = ["pyyaml"]
all = ["toml", "pyyaml"]
all = ["toml", "pyyaml", "python-dotenv"]

[tool.poetry.group.dev.dependencies]
ruff = "^0.0.263"
Expand Down
3 changes: 3 additions & 0 deletions tests/config.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
arg1=stuff
opt1="things"
opt2='nothing'
3 changes: 2 additions & 1 deletion tests/test_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def test_simple_example(simple_app):
(str(HERE.joinpath("config.yml")), typer_config.yaml_conf_callback),
(str(HERE.joinpath("config.json")), typer_config.json_conf_callback),
(str(HERE.joinpath("config.toml")), typer_config.toml_conf_callback),
(str(HERE.joinpath("config.env")), typer_config.dotenv_conf_callback),
]

# Test all the combinations of formats and extra parameters
Expand Down Expand Up @@ -68,7 +69,7 @@ def test_simple_example(simple_app):
assert (
result.exit_code != 0
), f"Should have failed for {conf}\n\n{result.stdout}"
assert "No such file" in result.stdout
assert "No such file" in result.stdout, f"Wrong error message for {conf}"


def test_pyproject_example(simple_app):
Expand Down
25 changes: 24 additions & 1 deletion typer_config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typer import BadParameter, CallbackParam, Context

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


def conf_callback_factory(loader: ConfigLoader) -> ConfigParameterCallback:
Expand Down Expand Up @@ -127,3 +127,26 @@ def _callback(
typer.BadParameter
bad parameter value
"""

dotenv_conf_callback: ConfigParameterCallback = conf_callback_factory(dotenv_loader)
"""Dotenv configuration callback for a typer parameter.
Parameters
----------
ctx : typer.Context
typer context (automatically passed)
param : typer.CallbackParam
typer callback parameter (automatically passed)
param_value : TyperParameterValue
parameter value passed to typer (automatically passed)
Returns
-------
TyperParameterValue
must return back the given parameter
Raises
------
typer.BadParameter
bad parameter value
"""
33 changes: 33 additions & 0 deletions typer_config/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
USING_TOMLLIB = False
TOML_MISSING = True
YAML_MISSING = True
DOTENV_MISSING = True


if sys.version_info >= (3, 11): # pragma: no cover
Expand All @@ -42,6 +43,13 @@
except ImportError: # pragma: no cover
pass

try: # pragma: no cover
import dotenv

DOTENV_MISSING = False
except ImportError: # pragma: no cover
pass


def subpath_loader(
loader: ConfigLoader, dictpath: ConfigDictAccessorPath
Expand Down Expand Up @@ -173,3 +181,28 @@ def toml_loader(param_value: TyperParameterValue) -> ConfigDict:
conf = toml.load(_file) # type: ignore

return conf


def dotenv_loader(param_value: TyperParameterValue) -> ConfigDict:
"""Dotenv file loader
Parameters
----------
param_value : TyperParameterValue
path of YAML file
Returns
-------
ConfigDict
dictionary loaded from file
"""

if DOTENV_MISSING: # pragma: no cover
raise ModuleNotFoundError("Please install the python-dotenv library.")

with open(param_value, "r", encoding="utf-8") as _file:
# NOTE: I'm using a stream here so that the loader
# will raise an exception when the file doesn't exist.
conf: ConfigDict = dotenv.dotenv_values(stream=_file)

return conf

0 comments on commit 28f5e61

Please sign in to comment.