Skip to content

Commit

Permalink
feat: support .env file configuration loading
Browse files Browse the repository at this point in the history
  • Loading branch information
joamag committed Apr 22, 2024
1 parent 9327683 commit 7b0e677
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

*
* Support for `.env` file loading

### Changed

Expand Down
48 changes: 48 additions & 0 deletions src/netius/base/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ def load(names = (FILE_NAME,), path = None, encoding = "utf-8", ctx = None):
for path in paths:
for name in names:
load_file(name = name, path = path, encoding = encoding, ctx = ctx)
load_dot_env(ctx=ctx)
load_env(ctx = ctx)

def load_file(name = FILE_NAME, path = None, encoding = "utf-8", ctx = None):
Expand Down Expand Up @@ -210,6 +211,53 @@ def load_file(name = FILE_NAME, path = None, encoding = "utf-8", ctx = None):
if not _is_valid(key): continue
configs[key] = value

def load_dot_env(name=".env", encoding="utf-8", ctx=None):
configs = ctx["configs"] if ctx else CONFIGS
config_f = ctx["config_f"] if ctx else CONFIG_F

file_path = os.path.abspath(name)
file_path = os.path.normpath(file_path)

exists = os.path.exists(file_path)
if not exists:
return

exists = file_path in config_f
if exists:
config_f.remove(file_path)
config_f.append(file_path)

file = open(file_path, "rb")
try:
data = file.read()
finally:
file.close()
if not data:
return

data = data.decode(encoding)
data = data.strip()
lines = data.splitlines()
lines = [line.strip() for line in lines]

for line in lines:
line = line.strip()
if not line:
continue
if line.startswith("#"):
continue
key, value = line.split("=", 1)
key = key.strip()
value = value.strip()
if (
value.startswith('"')
and value.endswith('"')
or value.startswith("'")
and value.endswith("'")
):
value = value[1:-1].replace('\\"', '"')
configs[key] = value

def load_env(ctx = None):
configs = ctx["configs"] if ctx else CONFIGS

Expand Down
36 changes: 36 additions & 0 deletions src/netius/test/base/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@

import netius

try:
import unittest.mock as mock
except ImportError:
mock = None

class ConfigTest(unittest.TestCase):

def test_basic(self):
Expand Down Expand Up @@ -88,3 +93,34 @@ def test_none(self):
result = netius.conf("HEIGHT", cast = int)

self.assertEqual(result, None)

def test_load_dot_env(self):
if mock == None:
self.skipTest("Skipping test: mock unavailable")

mock_data = mock.mock_open(
read_data=b"#This is a comment\nAGE=10\nNAME=colony\n"
)

with mock.patch("os.path.exists", return_value=True), mock.patch(
"builtins.open", mock_data, create=True
) as mock_open:
ctx = dict(configs={}, config_f=[])

netius.config.load_dot_env(".env", "utf-8", ctx)

result = netius.conf("AGE", cast=int)
self.assertEqual(type(result), int)
self.assertEqual(result, 10)

result = netius.conf("AGE", cast=str)

self.assertEqual(result, "10")
self.assertEqual(type(result), str)

result = netius.conf("HEIGHT", cast=int)
self.assertEqual(result, None)

self.assertEqual(len(ctx["configs"]), 2)

self.assertEqual(mock_open.return_value.close.call_count, 1)

0 comments on commit 7b0e677

Please sign in to comment.