diff --git a/my/body/weight.py b/my/body/weight.py index 1135cdc..28688b6 100644 --- a/my/body/weight.py +++ b/my/body/weight.py @@ -47,6 +47,7 @@ def from_orgmode() -> Iterator[Result]: continue # FIXME use timezone provider created = config.default_timezone.localize(created) + assert created is not None #??? somehow mypy wasn't happy? yield Entry( dt=created, value=w, diff --git a/my/cfg.py b/my/cfg.py index aafa8a1..62be0d0 100644 --- a/my/cfg.py +++ b/my/cfg.py @@ -11,23 +11,9 @@ After that, you can set config attributes: export_path = '/path/to/twitter/exports' config.twitter = user_config """ +# TODO do I really need it? + # todo why do we bring this into scope? don't remember.. import my.config as config - -from pathlib import Path -from typing import Union -def set_repo(name: str, repo: Union[Path, str]) -> None: - from .core.init import assign_module - from . common import import_from - - r = Path(repo) - module = import_from(r.parent, name) - assign_module('my.config.repos', name, module) - - -# TODO set_repo is still useful, but perhaps move this thing away to core? - -# TODO ok, I need to get rid of this, better to rely on regular imports - from .core import __NOT_HPI_MODULE__ diff --git a/my/config.py b/my/config.py index 52841a9..0b30d9a 100644 --- a/my/config.py +++ b/my/config.py @@ -63,3 +63,6 @@ class time: class tz: pass + +class orgmode: + paths: Paths diff --git a/my/core/cfg.py b/my/core/cfg.py index c20ed7d..75ae1ea 100644 --- a/my/core/cfg.py +++ b/my/core/cfg.py @@ -8,14 +8,19 @@ C = TypeVar('C') # but short enough to change later # TODO document why it's necessary? def make_config(cls: Type[C], migration: Callable[[Attrs], Attrs]=lambda x: x) -> C: - props = dict(vars(cls.__base__)) - props = migration(props) + user_config = cls.__base__ + old_props = { + # NOTE: deliberately use gettatr to 'force' lcass properties here + k: getattr(user_config, k) for k in vars(user_config) + } + new_props = migration(old_props) from dataclasses import fields params = { k: v - for k, v in props.items() + for k, v in new_props.items() if k in {f.name for f in fields(cls)} } + # todo maybe return type here? return cls(**params) # type: ignore[call-arg] diff --git a/my/orgmode.py b/my/orgmode.py index 4860a4e..869b124 100644 --- a/my/orgmode.py +++ b/my/orgmode.py @@ -42,6 +42,7 @@ def _created(n: orgparse.OrgNode) -> Tuple[Optional[datetime], str]: createds = m.group(0) # could be None if createds is None: return (None, heading) + assert isinstance(createds, str) [odt] = orgparse.date.OrgDate.list_from_str(createds) dt = odt.start # todo a bit hacky.. diff --git a/tests/config.py b/tests/config.py index 995190f..2496002 100644 --- a/tests/config.py +++ b/tests/config.py @@ -12,7 +12,7 @@ def setup_notes_path(notes: Path) -> None: import pytz class user_config_2: default_timezone = pytz.timezone('Europe/London') - config.weight = user_config_2 # type: ignore[misc,assignment] + config.weight = user_config_2 # type: ignore[attr-defined,assignment] def test_dynamic_configuration(notes: Path) -> None: @@ -33,33 +33,6 @@ def test_dynamic_configuration(notes: Path) -> None: import pytest # type: ignore -# TODO doublt I need it anymore.. keeping for now just for the sake of demonstration -def _test_set_repo(tmp_path: Path) -> None: - from my.cfg import config - class user_config: - export_path = 'whatever', - config.hypothesis = user_config # type: ignore[misc,assignment] - - # precondition: - # should fail because can't find hypexport - with pytest.raises(ModuleNotFoundError): - import my.hypothesis - - fake_hypexport = tmp_path / 'hypexport' - fake_hypexport.mkdir() - (fake_hypexport / 'dal.py').write_text(''' -Highlight = None -Page = None -DAL = None - ''') - - from my.cfg import set_repo - set_repo('hypexport', fake_hypexport) - - # should succeed now! - import my.hypothesis - - def test_environment_variable(tmp_path: Path) -> None: cfg_dir = tmp_path / 'my' cfg_file = cfg_dir / 'config.py' @@ -76,6 +49,39 @@ class feedly: import my.rss.feedly +from dataclasses import dataclass + + +def test_user_config() -> None: + from my.core.common import classproperty + class user_config: + param1 = 'abacaba' + # TOOD fuck. properties don't work here??? + @classproperty + def param2(cls) -> int: + return 456 + + extra = 'extra!' + + @dataclass + class test_config(user_config): + param1: str + param2: int # type: ignore[assignment] # TODO need to figure out how to trick mypy for @classproperty + param3: str = 'default' + + assert test_config.param1 == 'abacaba' + assert test_config.param2 == 456 + assert test_config.param3 == 'default' + assert test_config.extra == 'extra!' + + from my.core.cfg import make_config + c = make_config(test_config) + assert c.param1 == 'abacaba' + assert c.param2 == 456 + assert c.param3 == 'default' + assert c.extra == 'extra!' + + @pytest.fixture def notes(tmp_path: Path): ndir = tmp_path / 'notes' diff --git a/tests/reddit.py b/tests/reddit.py index 4f2c1bd..6a660ea 100644 --- a/tests/reddit.py +++ b/tests/reddit.py @@ -59,7 +59,7 @@ import pytest # type: ignore def prepare(): from my.common import get_files from my.config import reddit as config - files = get_files(config.export_dir) + files = get_files(config.export_path) # use less files for the test to make it faster # first bit is for 'test_unfavorite, the second is for test_disappearing files = files[300:330] + files[500:520]