tests: move remaining tests from tests/ to my.tests, cleanup corresponding modules

This commit is contained in:
Dima Gerasimov 2024-08-26 03:34:45 +01:00 committed by karlicoss
parent a5643206a0
commit b87d1c970a
9 changed files with 120 additions and 134 deletions

View file

@ -2,21 +2,29 @@
Weight data (manually logged) Weight data (manually logged)
''' '''
from dataclasses import dataclass
from datetime import datetime from datetime import datetime
from typing import NamedTuple, Iterator from typing import Any, Iterator
from ..core import LazyLogger from my.core import make_logger
from ..core.error import Res, set_error_datetime, extract_error_datetime from my.core.error import Res, extract_error_datetime, set_error_datetime
from .. import orgmode from my import orgmode
from my.config import weight as config # type: ignore[attr-defined] config = Any
log = LazyLogger('my.body.weight') def make_config() -> config:
from my.config import weight as user_config # type: ignore[attr-defined]
return user_config()
class Entry(NamedTuple): log = make_logger(__name__)
@dataclass
class Entry:
dt: datetime dt: datetime
value: float value: float
# TODO comment?? # TODO comment??
@ -26,6 +34,8 @@ Result = Res[Entry]
def from_orgmode() -> Iterator[Result]: def from_orgmode() -> Iterator[Result]:
cfg = make_config()
orgs = orgmode.query() orgs = orgmode.query()
for o in orgmode.query().all(): for o in orgmode.query().all():
if 'weight' not in o.tags: if 'weight' not in o.tags:
@ -46,8 +56,8 @@ def from_orgmode() -> Iterator[Result]:
yield e yield e
continue continue
# FIXME use timezone provider # FIXME use timezone provider
created = config.default_timezone.localize(created) created = cfg.default_timezone.localize(created)
assert created is not None #??? somehow mypy wasn't happy? assert created is not None # ??? somehow mypy wasn't happy?
yield Entry( yield Entry(
dt=created, dt=created,
value=w, value=w,
@ -57,19 +67,21 @@ def from_orgmode() -> Iterator[Result]:
def make_dataframe(data: Iterator[Result]): def make_dataframe(data: Iterator[Result]):
import pandas as pd import pandas as pd
def it(): def it():
for e in data: for e in data:
if isinstance(e, Exception): if isinstance(e, Exception):
dt = extract_error_datetime(e) dt = extract_error_datetime(e)
yield { yield {
'dt' : dt, 'dt': dt,
'error': str(e), 'error': str(e),
} }
else: else:
yield { yield {
'dt' : e.dt, 'dt': e.dt,
'weight': e.value, 'weight': e.value,
} }
df = pd.DataFrame(it()) df = pd.DataFrame(it())
df.set_index('dt', inplace=True) df.set_index('dt', inplace=True)
# TODO not sure about UTC?? # TODO not sure about UTC??
@ -81,6 +93,7 @@ def dataframe():
entries = from_orgmode() entries = from_orgmode()
return make_dataframe(entries) return make_dataframe(entries)
# TODO move to a submodule? e.g. my.body.weight.orgmode? # TODO move to a submodule? e.g. my.body.weight.orgmode?
# so there could be more sources # so there could be more sources
# not sure about my.body thing though # not sure about my.body thing though

View file

@ -6,18 +6,28 @@ REQUIRES = [
'orgparse', 'orgparse',
] ]
import re
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
import re from typing import Iterable, List, NamedTuple, Optional, Sequence, Tuple
from typing import List, Sequence, Iterable, NamedTuple, Optional, Tuple
from my.core import get_files import orgparse
from my.core import Paths, Stats, get_files, stat
from my.core.cachew import cache_dir, mcachew from my.core.cachew import cache_dir, mcachew
from my.core.orgmode import collect from my.core.orgmode import collect
from my.config import orgmode as user_config
import orgparse class config:
paths: Paths
def make_config() -> config:
from my.config import orgmode as user_config
class combined_config(user_config, config): ...
return combined_config()
# temporary? hack to cache org-mode notes # temporary? hack to cache org-mode notes
@ -28,10 +38,13 @@ class OrgNote(NamedTuple):
def inputs() -> Sequence[Path]: def inputs() -> Sequence[Path]:
return get_files(user_config.paths) cfg = make_config()
return get_files(cfg.paths)
_rgx = re.compile(orgparse.date.gene_timestamp_regex(brtype='inactive'), re.VERBOSE) _rgx = re.compile(orgparse.date.gene_timestamp_regex(brtype='inactive'), re.VERBOSE)
def _created(n: orgparse.OrgNode) -> Tuple[Optional[datetime], str]: def _created(n: orgparse.OrgNode) -> Tuple[Optional[datetime], str]:
heading = n.heading heading = n.heading
# meh.. support in orgparse? # meh.. support in orgparse?
@ -41,7 +54,7 @@ def _created(n: orgparse.OrgNode) -> Tuple[Optional[datetime], str]:
# try to guess from heading # try to guess from heading
m = _rgx.search(heading) m = _rgx.search(heading)
if m is not None: if m is not None:
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) assert isinstance(createds, str)
@ -67,7 +80,7 @@ def to_note(x: orgparse.OrgNode) -> OrgNote:
created = None created = None
return OrgNote( return OrgNote(
created=created, created=created,
heading=heading, # todo include the body? heading=heading, # todo include the body?
tags=list(x.tags), tags=list(x.tags),
) )
@ -84,14 +97,15 @@ def _cachew_cache_path(_self, f: Path) -> Path:
def _cachew_depends_on(_self, f: Path): def _cachew_depends_on(_self, f: Path):
return (f, f.stat().st_mtime) return (f, f.stat().st_mtime)
class Query: class Query:
def __init__(self, files: Sequence[Path]) -> None: def __init__(self, files: Sequence[Path]) -> None:
self.files = files self.files = files
# TODO yield errors? # TODO yield errors?
@mcachew( @mcachew(
cache_path=_cachew_cache_path, force_file=True, cache_path=_cachew_cache_path,
force_file=True,
depends_on=_cachew_depends_on, depends_on=_cachew_depends_on,
) )
def _iterate(self, f: Path) -> Iterable[OrgNote]: def _iterate(self, f: Path) -> Iterable[OrgNote]:
@ -114,8 +128,8 @@ def query() -> Query:
return Query(files=inputs()) return Query(files=inputs())
from my.core import Stats, stat
def stats() -> Stats: def stats() -> Stats:
def outlines(): def outlines():
return query().all() return query().all()
return stat(outlines) return stat(outlines)

View file

@ -10,7 +10,7 @@ REQUIRES = [
import time import time
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Iterator, List, NamedTuple, Optional, Protocol, Sequence from typing import Iterator, List, NamedTuple, Optional, Protocol, Sequence, TYPE_CHECKING
import pdfannots import pdfannots
from more_itertools import bucket from more_itertools import bucket
@ -185,8 +185,6 @@ def stats() -> Stats:
### legacy/misc stuff ### legacy/misc stuff
iter_annotations = annotations # for backwards compatibility if not TYPE_CHECKING:
iter_annotations = annotations
### ###
# can use 'hpi query my.pdfs.annotations -o pprint' to test
#

View file

@ -1,12 +1,12 @@
from pathlib import Path
from typing import Iterator from typing import Iterator
import pytest
from more_itertools import one from more_itertools import one
import pytest from my.bluemaestro import Measurement, measurements
from my.core.cfg import tmp_config
from .common import testdata
from my.bluemaestro import measurements, Measurement
def ok_measurements() -> Iterator[Measurement]: def ok_measurements() -> Iterator[Measurement]:
@ -26,7 +26,7 @@ def test() -> None:
# check that timezone is set properly # check that timezone is set properly
assert dts == '20200824 22' assert dts == '20200824 22'
assert len(tp) == 1 # should be unique assert len(tp) == 1 # should be unique
# 2.5 K + 4 K datapoints, somewhat overlapping # 2.5 K + 4 K datapoints, somewhat overlapping
assert len(res2020) < 6000 assert len(res2020) < 6000
@ -46,14 +46,12 @@ def test_old_db() -> None:
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def prepare(): def prepare():
from my.tests.common import testdata
bmdata = testdata() / 'hpi-testdata' / 'bluemaestro' bmdata = testdata() / 'hpi-testdata' / 'bluemaestro'
assert bmdata.exists(), bmdata assert bmdata.exists(), bmdata
class bluemaestro: class bluemaestro:
export_path = bmdata export_path = bmdata
from my.core.cfg import tmp_config
with tmp_config() as config: with tmp_config() as config:
config.bluemaestro = bluemaestro config.bluemaestro = bluemaestro
yield yield

57
my/tests/body/weight.py Normal file
View file

@ -0,0 +1,57 @@
from pathlib import Path
import pytz
from my.core.cfg import tmp_config
import pytest
from my.body.weight import from_orgmode
def test_body_weight() -> None:
weights = [0.0 if isinstance(x, Exception) else x.value for x in from_orgmode()]
assert weights == [
0.0,
62.0,
0.0,
61.0,
62.0,
0.0,
]
@pytest.fixture(autouse=True)
def prepare(tmp_path: Path):
ndir = tmp_path / 'notes'
ndir.mkdir()
logs = ndir / 'logs.org'
logs.write_text(
'''
#+TITLE: Stuff I'm logging
* Weight (org-capture) :weight:
** [2020-05-01 Fri 09:00] 62
** 63
this should be ignored, got no timestamp
** [2020-05-03 Sun 08:00] 61
** [2020-05-04 Mon 10:00] 62
'''
)
misc = ndir / 'misc.org'
misc.write_text(
'''
Some misc stuff
* unrelated note :weight:whatever:
'''
)
class orgmode:
paths = [ndir]
class weight:
# TODO ugh. this belongs to tz provider or global config or something
default_timezone = pytz.timezone('Europe/London')
with tmp_config() as cfg:
cfg.orgmode = orgmode
cfg.weight = weight
yield

View file

@ -5,9 +5,8 @@ import pytest
from more_itertools import ilen from more_itertools import ilen
from my.core.cfg import tmp_config from my.core.cfg import tmp_config
from my.tests.common import testdata
from my.pdfs import annotated_pdfs, annotations, get_annots from my.pdfs import annotated_pdfs, annotations, get_annots
from my.tests.common import testdata
def test_module(with_config) -> None: def test_module(with_config) -> None:

View file

@ -1,15 +1,16 @@
import pytest
from more_itertools import consume
from my.core.cfg import tmp_config from my.core.cfg import tmp_config
from my.core.utils.itertools import ensure_unique from my.core.utils.itertools import ensure_unique
# todo ugh, it's discovered as a test???
from .common import testdata from .common import testdata
from more_itertools import consume
import pytest
# deliberately use mixed style imports on the top level and inside the methods to test tmp_config stuff # deliberately use mixed style imports on the top level and inside the methods to test tmp_config stuff
import my.reddit.rexport as my_reddit_rexport # todo won't really be necessary once we migrate to lazy user config
import my.reddit.all as my_reddit_all import my.reddit.all as my_reddit_all
import my.reddit.rexport as my_reddit_rexport
def test_basic_1() -> None: def test_basic_1() -> None:

View file

@ -1,89 +0,0 @@
from pathlib import Path
# TODO move this somewhere else -- there are more specific tests covering this now
def test_dynamic_configuration(notes: Path) -> None:
import pytz
from types import SimpleNamespace as NS
from my.core.cfg import tmp_config
with tmp_config() as C:
C.orgmode = NS(paths=[notes])
# TODO ugh. this belongs to tz provider or global config or something
C.weight = NS(default_timezone=pytz.timezone('Europe/London'))
from my.body.weight import from_orgmode
weights = [0.0 if isinstance(x, Exception) else x.value for x in from_orgmode()]
assert weights == [
0.0,
62.0,
0.0,
61.0,
62.0,
0.0,
]
import pytest
from dataclasses import dataclass
# TODO this test should probs be deprecated? it's more of a documentation?
def test_user_config() -> None:
from my.core.common import classproperty
class user_config:
param1 = 'abacaba'
# TODO 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'
ndir.mkdir()
logs = ndir / 'logs.org'
logs.write_text('''
#+TITLE: Stuff I'm logging
* Weight (org-capture) :weight:
** [2020-05-01 Fri 09:00] 62
** 63
this should be ignored, got no timestamp
** [2020-05-03 Sun 08:00] 61
** [2020-05-04 Mon 10:00] 62
''')
misc = ndir / 'misc.org'
misc.write_text('''
Some misc stuff
* unrelated note :weight:whatever:
''')
try:
yield ndir
finally:
pass

View file

@ -86,11 +86,6 @@ commands =
--pyargs {[testenv]package_name}.core {[testenv]package_name}.tests \ --pyargs {[testenv]package_name}.core {[testenv]package_name}.tests \
{posargs} {posargs}
{envpython} -m pytest tests \
# ignore some tests which might take a while to run on ci..
--ignore tests/extra/polar.py
{posargs}
[testenv:demo] [testenv:demo]
commands = commands =