core: proprely resolve class properties in make_config + add test
This commit is contained in:
parent
dda628e866
commit
e81dddddf0
7 changed files with 50 additions and 48 deletions
|
@ -47,6 +47,7 @@ def from_orgmode() -> Iterator[Result]:
|
||||||
continue
|
continue
|
||||||
# FIXME use timezone provider
|
# FIXME use timezone provider
|
||||||
created = config.default_timezone.localize(created)
|
created = config.default_timezone.localize(created)
|
||||||
|
assert created is not None #??? somehow mypy wasn't happy?
|
||||||
yield Entry(
|
yield Entry(
|
||||||
dt=created,
|
dt=created,
|
||||||
value=w,
|
value=w,
|
||||||
|
|
18
my/cfg.py
18
my/cfg.py
|
@ -11,23 +11,9 @@ After that, you can set config attributes:
|
||||||
export_path = '/path/to/twitter/exports'
|
export_path = '/path/to/twitter/exports'
|
||||||
config.twitter = user_config
|
config.twitter = user_config
|
||||||
"""
|
"""
|
||||||
|
# TODO do I really need it?
|
||||||
|
|
||||||
# todo why do we bring this into scope? don't remember..
|
# todo why do we bring this into scope? don't remember..
|
||||||
import my.config as config
|
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__
|
from .core import __NOT_HPI_MODULE__
|
||||||
|
|
|
@ -63,3 +63,6 @@ class time:
|
||||||
class tz:
|
class tz:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class orgmode:
|
||||||
|
paths: Paths
|
||||||
|
|
|
@ -8,14 +8,19 @@ C = TypeVar('C')
|
||||||
# but short enough to change later
|
# but short enough to change later
|
||||||
# TODO document why it's necessary?
|
# TODO document why it's necessary?
|
||||||
def make_config(cls: Type[C], migration: Callable[[Attrs], Attrs]=lambda x: x) -> C:
|
def make_config(cls: Type[C], migration: Callable[[Attrs], Attrs]=lambda x: x) -> C:
|
||||||
props = dict(vars(cls.__base__))
|
user_config = cls.__base__
|
||||||
props = migration(props)
|
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
|
from dataclasses import fields
|
||||||
params = {
|
params = {
|
||||||
k: v
|
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)}
|
if k in {f.name for f in fields(cls)}
|
||||||
}
|
}
|
||||||
|
# todo maybe return type here?
|
||||||
return cls(**params) # type: ignore[call-arg]
|
return cls(**params) # type: ignore[call-arg]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ def _created(n: orgparse.OrgNode) -> Tuple[Optional[datetime], str]:
|
||||||
createds = m.group(0) # could be None
|
createds = m.group(0) # could be None
|
||||||
if createds is None:
|
if createds is None:
|
||||||
return (None, heading)
|
return (None, heading)
|
||||||
|
assert isinstance(createds, str)
|
||||||
[odt] = orgparse.date.OrgDate.list_from_str(createds)
|
[odt] = orgparse.date.OrgDate.list_from_str(createds)
|
||||||
dt = odt.start
|
dt = odt.start
|
||||||
# todo a bit hacky..
|
# todo a bit hacky..
|
||||||
|
|
|
@ -12,7 +12,7 @@ def setup_notes_path(notes: Path) -> None:
|
||||||
import pytz
|
import pytz
|
||||||
class user_config_2:
|
class user_config_2:
|
||||||
default_timezone = pytz.timezone('Europe/London')
|
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:
|
def test_dynamic_configuration(notes: Path) -> None:
|
||||||
|
@ -33,33 +33,6 @@ def test_dynamic_configuration(notes: Path) -> None:
|
||||||
import pytest # type: ignore
|
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:
|
def test_environment_variable(tmp_path: Path) -> None:
|
||||||
cfg_dir = tmp_path / 'my'
|
cfg_dir = tmp_path / 'my'
|
||||||
cfg_file = cfg_dir / 'config.py'
|
cfg_file = cfg_dir / 'config.py'
|
||||||
|
@ -76,6 +49,39 @@ class feedly:
|
||||||
import my.rss.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
|
@pytest.fixture
|
||||||
def notes(tmp_path: Path):
|
def notes(tmp_path: Path):
|
||||||
ndir = tmp_path / 'notes'
|
ndir = tmp_path / 'notes'
|
||||||
|
|
|
@ -59,7 +59,7 @@ import pytest # type: ignore
|
||||||
def prepare():
|
def prepare():
|
||||||
from my.common import get_files
|
from my.common import get_files
|
||||||
from my.config import reddit as config
|
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
|
# use less files for the test to make it faster
|
||||||
# first bit is for 'test_unfavorite, the second is for test_disappearing
|
# first bit is for 'test_unfavorite, the second is for test_disappearing
|
||||||
files = files[300:330] + files[500:520]
|
files = files[300:330] + files[500:520]
|
||||||
|
|
Loading…
Add table
Reference in a new issue