Skip to content

Commit

Permalink
Support comments in .env files (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
tr11 authored Apr 24, 2024
1 parent b0fed03 commit d31a3f8
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from ._version import __version__, __version_tuple__ # noqa: F401
from .configuration import Configuration
from .configuration_set import ConfigurationSet
from .helpers import InterpolateEnumType, InterpolateType
from .helpers import InterpolateEnumType, InterpolateType, parse_env_line


def config(
Expand Down Expand Up @@ -586,9 +586,7 @@ def _reload(
data = data.read()
data = cast(str, data)
result: Dict[str, Any] = dict(
(y.strip() for y in x.split("=", 1)) # type: ignore
for x in data.splitlines()
if x
parse_env_line(x) for x in data.splitlines() if x and not x.startswith("#")
)

result = {
Expand All @@ -613,6 +611,8 @@ def config_from_dotenv(
) -> Configuration:
"""Create a [Configuration][config.configuration.Configuration] instance from a .env type file.
Lines starting with a # are ignored and treated as comments.
Params:
data: path to a .env type file or contents.
read_from_file: whether to read from a file path or to interpret.
Expand Down
9 changes: 9 additions & 0 deletions src/config/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,12 @@ def interpolate_object(
return [interpolate_object(attr, x, d, method) for x in obj]
else:
return obj


def parse_env_line(line: str) -> Tuple[str, str]:
"""Split an env line into variable and value."""
try:
key, value = tuple(y.strip() for y in line.split("=", 1))
except ValueError:
raise ValueError("Invalid line %s" % line) from None
return key.strip(), value.strip()
27 changes: 27 additions & 0 deletions tests/test_dotenv.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pytest
from config import config_from_dotenv, config_from_dict
import tempfile

Expand All @@ -17,6 +18,14 @@
PREFIX__KEY4__C = 3
"""

DOTENV_WITH_COMMENTS = """
# key 1
KEY1 = abc
# key 2
KEY2 = def
# key 3
KEY3 = 1.1
"""

DICT = {
"key1": "abc",
Expand Down Expand Up @@ -83,3 +92,21 @@ def test_load_dotenv(): # type: ignore
cfg = config_from_dotenv(DOTENV_WITH_PREFIXES, lowercase_keys=True, prefix="PREFIX")
print(cfg.as_dict())
assert cfg == config_from_dict(DICT_WITH_PREFIXES)


def test_load_dotenv_comments(): # type: ignore
cfg = config_from_dotenv(DOTENV_WITH_COMMENTS, lowercase_keys=True)
assert cfg == config_from_dict(dict((k, str(v)) for k, v in DICT.items()))


def test_load_dotenv_comments_invalid(): # type: ignore
invalid = """
# key 1
VALID=1
## key2
INVALID
"""
with pytest.raises(ValueError) as err:
config_from_dotenv(invalid, lowercase_keys=True)
assert 'Invalid line INVALID' in str(err)

10 changes: 10 additions & 0 deletions tests/test_issues.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import pytest
from config import (
Configuration,
ConfigurationSet,
EnvConfiguration,
config,
config_from_dict,
config_from_dotenv,
)


Expand Down Expand Up @@ -78,3 +80,11 @@ def test_issue_79(): # type: ignore
conf.update(data)

assert conf["abc.def"] == "ghi"


def test_issue_100(): # type: ignore
invalid = """# key 1\nVALID=1\n## key2\nINVALID\n"""
with pytest.raises(ValueError) as err:
config_from_dotenv(invalid, lowercase_keys=True)
assert 'Invalid line INVALID' in str(err)

0 comments on commit d31a3f8

Please sign in to comment.