Add load_settings_toml
This commit is contained in:
parent
c23dc24bae
commit
5b94da4fc3
4 changed files with 204 additions and 0 deletions
5
pytest.ini
Normal file
5
pytest.ini
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# SPDX-FileCopyrightText: 2025 Justin Myers
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
[pytest]
|
||||
pythonpath = src
|
||||
1
setup.py
1
setup.py
|
|
@ -99,6 +99,7 @@ setup(
|
|||
"pyftdi>=0.40.0",
|
||||
"adafruit-circuitpython-typing",
|
||||
"sysv_ipc>=1.1.0;sys_platform=='linux' and platform_machine!='mips'",
|
||||
"toml>=0.10.2;python_version<'3.11'",
|
||||
]
|
||||
+ board_reqs,
|
||||
license="MIT",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,13 @@
|
|||
* Author(s): cefn
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
import tomllib
|
||||
except ImportError:
|
||||
import toml as tomllib
|
||||
|
||||
|
||||
class Enum:
|
||||
"""
|
||||
|
|
@ -74,6 +81,41 @@ class Lockable(ContextManaged):
|
|||
self._locked = False
|
||||
|
||||
|
||||
def load_settings_toml(*, return_toml=False):
|
||||
"""Load values from settings.toml into os.environ, so that os.getenv returns them."""
|
||||
if not os.path.isfile("settings.toml"):
|
||||
raise FileNotFoundError("settings.toml not cound in current directory.")
|
||||
|
||||
print("settings.toml found. Updating environment variables:")
|
||||
with open("settings.toml", "rb") as toml_file:
|
||||
try:
|
||||
settings = tomllib.load(toml_file)
|
||||
except tomllib.TOMLDecodeError as e:
|
||||
raise tomllib.TOMLDecodeError("Error with settings.toml file.") from e
|
||||
|
||||
invalid_types = set()
|
||||
for key, value in settings.items():
|
||||
if not isinstance(value, (bool, int, float, str)):
|
||||
invalid_types.add(type(value).__name__)
|
||||
if invalid_types:
|
||||
invalid_types_string = ", ".join(invalid_types)
|
||||
raise ValueError(
|
||||
f"The types: '{invalid_types_string}' are not supported in settings.toml."
|
||||
)
|
||||
|
||||
for key, value in settings.items():
|
||||
key = str(key)
|
||||
if key in os.environ:
|
||||
print(f" - {key} already exists in environment")
|
||||
continue
|
||||
os.environ[key] = str(value)
|
||||
print(f" - {key} added")
|
||||
|
||||
if return_toml:
|
||||
return settings
|
||||
return None
|
||||
|
||||
|
||||
def patch_system():
|
||||
"""Patch modules that may be different due to the platform."""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
|
|
|
|||
156
tests/test_load_settings_toml.py
Normal file
156
tests/test_load_settings_toml.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# SPDX-FileCopyrightText: 2025 Justin Myers
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
import os
|
||||
from unittest import mock
|
||||
import pytest
|
||||
from adafruit_blinka import load_settings_toml
|
||||
|
||||
try:
|
||||
import tomllib
|
||||
except ImportError:
|
||||
import toml as tomllib
|
||||
|
||||
# pylint: disable=no-self-use,unused-argument
|
||||
|
||||
CONVERTED_TOML = {
|
||||
"123": 123,
|
||||
"test": "test",
|
||||
"test-hyphen": "test-hyphen",
|
||||
"test_bool": True,
|
||||
"test_number": 123,
|
||||
"test_space": "test space",
|
||||
"test_underscore": "test_underscore",
|
||||
"true": False,
|
||||
}
|
||||
|
||||
|
||||
INVALID_TOML = b"""
|
||||
# strings
|
||||
test=test
|
||||
"""
|
||||
|
||||
|
||||
VALID_TOML = b"""
|
||||
# strings
|
||||
test="test"
|
||||
test_space="test space"
|
||||
test_underscore="test_underscore"
|
||||
test-hyphen="test-hyphen"
|
||||
# number
|
||||
test_number=123
|
||||
# bool
|
||||
test_bool=true
|
||||
# other
|
||||
123=123
|
||||
true=false
|
||||
"""
|
||||
|
||||
VALID_TOML_WITH_UNSUPPORTED_DATA_DICT = b"""
|
||||
# dict
|
||||
data = { key_1 = "value", key_2 = "value" }
|
||||
"""
|
||||
|
||||
VALID_TOML_WITH_UNSUPPORTED_DATA_LIST = b"""
|
||||
# list
|
||||
numbers = [ 1, 2, 3 ]
|
||||
"""
|
||||
|
||||
VALID_TOML_WITH_UNSUPPORTED_DATA_MANY = b"""
|
||||
# dict
|
||||
data = { key_1 = "value", key_2 = "value" }
|
||||
|
||||
# list
|
||||
numbers = [ 1, 2, 3 ]
|
||||
|
||||
[nested]
|
||||
test="test"
|
||||
"""
|
||||
|
||||
VALID_TOML_WITH_UNSUPPORTED_DATA_NESTED = b"""
|
||||
[nested]
|
||||
test="test"
|
||||
"""
|
||||
|
||||
|
||||
class TestLoadSettingsToml:
|
||||
@mock.patch("adafruit_blinka.os.path.isfile", mock.Mock(return_value=False))
|
||||
def test_raises_with_no_file(self):
|
||||
with pytest.raises(
|
||||
FileNotFoundError, match="settings.toml not cound in current directory."
|
||||
):
|
||||
load_settings_toml(return_toml=True)
|
||||
|
||||
@mock.patch("adafruit_blinka.os.path.isfile", mock.Mock(return_value=True))
|
||||
@mock.patch("builtins.open", mock.mock_open(read_data=INVALID_TOML))
|
||||
def test_raises_with_invalid_file(self):
|
||||
with pytest.raises(
|
||||
tomllib.TOMLDecodeError, match="Error with settings.toml file."
|
||||
):
|
||||
load_settings_toml(return_toml=True)
|
||||
|
||||
@mock.patch("adafruit_blinka.os.path.isfile", mock.Mock(return_value=True))
|
||||
@mock.patch(
|
||||
"builtins.open", mock.mock_open(read_data=VALID_TOML_WITH_UNSUPPORTED_DATA_DICT)
|
||||
)
|
||||
def test_raises_with_invalid_file_dict(self):
|
||||
with pytest.raises(
|
||||
ValueError, match="The types: 'dict' are not supported in settings.toml."
|
||||
):
|
||||
load_settings_toml(return_toml=True)
|
||||
|
||||
@mock.patch("adafruit_blinka.os.path.isfile", mock.Mock(return_value=True))
|
||||
@mock.patch(
|
||||
"builtins.open", mock.mock_open(read_data=VALID_TOML_WITH_UNSUPPORTED_DATA_LIST)
|
||||
)
|
||||
def test_raises_with_invalid_file_list(self):
|
||||
with pytest.raises(
|
||||
ValueError, match="The types: 'list' are not supported in settings.toml."
|
||||
):
|
||||
load_settings_toml(return_toml=True)
|
||||
|
||||
@mock.patch("adafruit_blinka.os.path.isfile", mock.Mock(return_value=True))
|
||||
@mock.patch(
|
||||
"builtins.open", mock.mock_open(read_data=VALID_TOML_WITH_UNSUPPORTED_DATA_MANY)
|
||||
)
|
||||
def test_raises_with_invalid_file_many(self):
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match="The types: 'dict, list' are not supported in settings.toml.",
|
||||
):
|
||||
load_settings_toml(return_toml=True)
|
||||
|
||||
@mock.patch("adafruit_blinka.os.path.isfile", mock.Mock(return_value=True))
|
||||
@mock.patch(
|
||||
"builtins.open",
|
||||
mock.mock_open(read_data=VALID_TOML_WITH_UNSUPPORTED_DATA_NESTED),
|
||||
)
|
||||
def test_raises_with_invalid_file_nested(self):
|
||||
with pytest.raises(
|
||||
ValueError, match="The types: 'dict' are not supported in settings.toml."
|
||||
):
|
||||
load_settings_toml(return_toml=True)
|
||||
|
||||
@mock.patch("adafruit_blinka.os.path.isfile", mock.Mock(return_value=True))
|
||||
@mock.patch("builtins.open", mock.mock_open(read_data=VALID_TOML))
|
||||
@mock.patch.dict(os.environ, {}, clear=True)
|
||||
def test_returns_data(self):
|
||||
for key in CONVERTED_TOML:
|
||||
assert os.getenv(key) is None
|
||||
|
||||
assert load_settings_toml() is None
|
||||
|
||||
for key, value in CONVERTED_TOML.items():
|
||||
assert os.getenv(key) == str(value)
|
||||
|
||||
@mock.patch("adafruit_blinka.os.path.isfile", mock.Mock(return_value=True))
|
||||
@mock.patch("builtins.open", mock.mock_open(read_data=VALID_TOML))
|
||||
@mock.patch.dict(os.environ, {}, clear=True)
|
||||
def test_returns_data_when_asked(self):
|
||||
for key in CONVERTED_TOML:
|
||||
assert os.getenv(key) is None
|
||||
|
||||
assert load_settings_toml(return_toml=True) == CONVERTED_TOML
|
||||
|
||||
for key, value in CONVERTED_TOML.items():
|
||||
assert os.getenv(key) == str(value)
|
||||
Loading…
Reference in a new issue