HPI/my/core/tests/test_config.py
2024-08-25 20:49:56 +01:00

132 lines
3.5 KiB
Python

"""
Various tests that are checking behaviour of user config wrt to various things
"""
import sys
from pathlib import Path
import pytest
import pytz
from more_itertools import ilen
import my.config
from my.core import notnone
from my.demo import items, make_config
# run the same test multiple times to make sure there are not issues with import order etc
@pytest.mark.parametrize('run_id', ['1', '2'])
def test_override_config(tmp_path: Path, run_id: str) -> None:
class user_config:
username = f'user_{run_id}'
data_path = f'{tmp_path}/*.json'
my.config.demo = user_config # type: ignore[misc, assignment]
[item1, item2] = items()
assert item1.username == f'user_{run_id}'
assert item2.username == f'user_{run_id}'
@pytest.mark.skip(reason="won't work at the moment because of inheritance")
def test_dynamic_config_simplenamespace(tmp_path: Path) -> None:
from types import SimpleNamespace
user_config = SimpleNamespace(
username='user3',
data_path=f'{tmp_path}/*.json',
)
my.config.demo = user_config # type: ignore[misc, assignment]
cfg = make_config()
assert cfg.username == 'user3'
def test_mixin_attribute_handling(tmp_path: Path) -> None:
"""
Tests that arbitrary mixin attributes work with our config handling pattern
"""
nytz = pytz.timezone('America/New_York')
class user_config:
# check that override is taken into the account
timezone = nytz
irrelevant = 'hello'
username = 'UUU'
data_path = f'{tmp_path}/*.json'
my.config.demo = user_config # type: ignore[misc, assignment]
cfg = make_config()
assert cfg.username == 'UUU'
# mypy doesn't know about it, but the attribute is there
assert getattr(cfg, 'irrelevant') == 'hello'
# check that overridden default attribute is actually getting overridden
assert cfg.timezone == nytz
[item1, item2] = items()
assert item1.username == 'UUU'
assert notnone(item1.dt.tzinfo).zone == nytz.zone # type: ignore[attr-defined]
assert item2.username == 'UUU'
assert notnone(item2.dt.tzinfo).zone == nytz.zone # type: ignore[attr-defined]
# use multiple identical tests to make sure there are no issues with cached imports etc
@pytest.mark.parametrize('run_id', ['1', '2'])
def test_dynamic_module_import(tmp_path: Path, run_id: str) -> None:
"""
Test for dynamic hackery in config properties
e.g. importing some external modules
"""
ext = tmp_path / 'external'
ext.mkdir()
(ext / '__init__.py').write_text(
'''
def transform(x):
from .submodule import do_transform
return do_transform(x)
'''
)
(ext / 'submodule.py').write_text(
f'''
def do_transform(x):
return {{"total_{run_id}": sum(x.values())}}
'''
)
class user_config:
username = 'someuser'
data_path = f'{tmp_path}/*.json'
external = f'{ext}'
my.config.demo = user_config # type: ignore[misc, assignment]
[item1, item2] = items()
assert item1.raw == {f'total_{run_id}': 1 + 123}, item1
assert item2.raw == {f'total_{run_id}': 2 + 456}, item2
# need to reset these modules, otherwise they get cached
# kind of relevant to my.core.cfg.tmp_config
sys.modules.pop('external', None)
sys.modules.pop('external.submodule', None)
@pytest.fixture(autouse=True)
def prepare_data(tmp_path: Path):
(tmp_path / 'data.json').write_text(
'''
[
{"key": 1, "value": 123},
{"key": 2, "value": 456}
]
'''
)