mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-10 17:47:23 +01:00
pin earned-time-v0.3.0 (registers the automation earner)
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (flutter, flutter-analyze, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint,flutter-analyze) (push) Has been cancelled
Tests / test (push) Has been cancelled
Tests / lock-popup-safety (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (0) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (1) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (2) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (3) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (4) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (5) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (6) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (7) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (8) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (9) (push) Has been cancelled
Tests / web-coverage (push) Has been cancelled
repo-contract / repo contract (push) Has been cancelled
Tests / flutter-coverage (push) Has been cancelled
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (flutter, flutter-analyze, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Has been cancelled
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint,flutter-analyze) (push) Has been cancelled
Tests / test (push) Has been cancelled
Tests / lock-popup-safety (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (0) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (1) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (2) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (3) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (4) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (5) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (6) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (7) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (8) (push) Has been cancelled
Tests / flutter test (shard ${{ matrix.shard }}) (9) (push) Has been cancelled
Tests / web-coverage (push) Has been cancelled
repo-contract / repo contract (push) Has been cancelled
Tests / flutter-coverage (push) Has been cancelled
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
218d327145
commit
ec7f4805f7
@ -134,7 +134,7 @@ repos:
|
||||
# than merely an old one.
|
||||
- gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.9.0#subdirectory=gatelock
|
||||
- crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.9.1#subdirectory=crdt-sync
|
||||
- earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.2.0#subdirectory=earned_time
|
||||
- earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.3.0#subdirectory=earned_time
|
||||
- freedays @ git+https://github.com/kuhyx/utils@freedays-v0.3.0#subdirectory=freedays
|
||||
- mcp>=2,<3
|
||||
- pydantic
|
||||
@ -155,7 +155,7 @@ repos:
|
||||
# than merely an old one.
|
||||
- gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.9.0#subdirectory=gatelock
|
||||
- crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.9.1#subdirectory=crdt-sync
|
||||
- earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.2.0#subdirectory=earned_time
|
||||
- earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.3.0#subdirectory=earned_time
|
||||
- freedays @ git+https://github.com/kuhyx/utils@freedays-v0.3.0#subdirectory=freedays
|
||||
- mcp>=2,<3
|
||||
- pydantic
|
||||
|
||||
@ -10,7 +10,7 @@ dependencies = [
|
||||
"gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.9.0#subdirectory=gatelock",
|
||||
"crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.9.1#subdirectory=crdt-sync",
|
||||
"freedays @ git+https://github.com/kuhyx/utils@freedays-v0.3.0#subdirectory=freedays",
|
||||
"earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.2.0#subdirectory=earned_time",
|
||||
"earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.3.0#subdirectory=earned_time",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@ -4,7 +4,7 @@ bandit==1.9.4
|
||||
codespell==2.4.3
|
||||
coverage==7.16.2
|
||||
crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.9.1#subdirectory=crdt-sync
|
||||
earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.2.0#subdirectory=earned_time
|
||||
earned-time @ git+https://github.com/kuhyx/utils@earned-time-v0.3.0#subdirectory=earned_time
|
||||
freedays @ git+https://github.com/kuhyx/utils@freedays-v0.3.0#subdirectory=freedays
|
||||
gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.9.0#subdirectory=gatelock
|
||||
mcp==2.3.0
|
||||
|
||||
@ -101,11 +101,9 @@ class TestLedgerFile:
|
||||
|
||||
class TestFlatEarners:
|
||||
def test_registry_order_without_the_counted_workout(self) -> None:
|
||||
assert flat_earners() == (
|
||||
earned_time.LEETCODE,
|
||||
earned_time.READING,
|
||||
earned_time.ANKI,
|
||||
)
|
||||
flat = tuple(e for e in earned_time.EARNERS if e.kind == "flat")
|
||||
assert flat_earners() == flat
|
||||
assert flat[:3] == (earned_time.LEETCODE, earned_time.READING, earned_time.ANKI)
|
||||
|
||||
def test_a_newly_registered_earner_is_picked_up(
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
@ -215,7 +213,8 @@ class TestCannotCheck:
|
||||
class TestFlatAnswers:
|
||||
def test_every_flat_earner_answers_by_name(self, key: Path) -> None:
|
||||
write_ledger(earned_time.LEETCODE, [credit(earned_time.LEETCODE)])
|
||||
assert flat_answers() == {"leetcode": True, "reading": False, "anki": False}
|
||||
nos = dict.fromkeys((e.name for e in flat_earners()), False)
|
||||
assert flat_answers() == {**nos, "leetcode": True}
|
||||
|
||||
def test_an_unknown_answer_is_none_and_warned(
|
||||
self,
|
||||
@ -225,19 +224,16 @@ class TestFlatAnswers:
|
||||
) -> None:
|
||||
monkeypatch.setattr(_earned, "HMAC_KEY_FILE", tmp_path / "no.key")
|
||||
with caplog.at_level(logging.WARNING):
|
||||
assert flat_answers() == {"leetcode": None, "reading": None, "anki": None}
|
||||
assert "LeetCode state could not be checked" in caplog.text
|
||||
assert "reading state could not be checked" in caplog.text
|
||||
assert "Anki state could not be checked" in caplog.text
|
||||
assert flat_answers() == dict.fromkeys(e.name for e in flat_earners())
|
||||
for earner in flat_earners():
|
||||
assert f"{earner.label} state could not be checked" in caplog.text
|
||||
|
||||
def test_a_no_is_not_warned(
|
||||
self, key: Path, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
write_ledger(earned_time.LEETCODE, [])
|
||||
with caplog.at_level(logging.WARNING):
|
||||
assert flat_answers() == {
|
||||
"leetcode": False,
|
||||
"reading": False,
|
||||
"anki": False,
|
||||
}
|
||||
assert flat_answers() == dict.fromkeys(
|
||||
(e.name for e in flat_earners()), False
|
||||
)
|
||||
assert "could not be checked" not in caplog.text
|
||||
|
||||
@ -180,8 +180,11 @@ class TestProjectionFollowsTheCut:
|
||||
def test_next_week_preview_includes_a_cut_dated_after_today(
|
||||
self, tmp_path: Path
|
||||
) -> None:
|
||||
"""On Mon 2026-10-05, Anki's cut from Tue already shows; next week has it."""
|
||||
"""On Mon 2026-10-05, the cuts from Tue already show; next week has them."""
|
||||
shutdown = self._shutdown(tmp_path, datetime(2026, 10, 5, 12, 0, tzinfo=UTC))
|
||||
lowered = 19 * 60 - earned_time.ANKI.shutdown_minutes
|
||||
tuesday = date(2026, 10, 6)
|
||||
lowered = 19 * 60 - sum(
|
||||
e.shutdown_minutes for e in earned_time.EARNERS if e.penalty_from == tuesday
|
||||
)
|
||||
assert [d.minutes for d in shutdown.rest_of_week] == [19 * 60] + [lowered] * 6
|
||||
assert [d.minutes for d in shutdown.next_week_preview] == [lowered] * 7
|
||||
|
||||
@ -18,7 +18,7 @@ import pytest
|
||||
|
||||
from screen_locker import _shutdown_base
|
||||
from screen_locker._day import today_str
|
||||
from screen_locker._earned import hhmm
|
||||
from screen_locker._earned import flat_earners, hhmm
|
||||
from screen_locker._shutdown_base import (
|
||||
_apply_flat_bonus,
|
||||
apply_flat_bonuses_if_new,
|
||||
@ -31,6 +31,9 @@ if TYPE_CHECKING:
|
||||
from collections.abc import Iterator
|
||||
from pathlib import Path
|
||||
|
||||
# Terms the reset log spells out by hand; every later earner follows them.
|
||||
_NAMED = frozenset({"leetcode", "reading"})
|
||||
|
||||
|
||||
def _mixin(*, adjust_ok: bool = True) -> MagicMock:
|
||||
mixin = MagicMock()
|
||||
@ -62,8 +65,14 @@ class TestBaseHour:
|
||||
assert base_minutes(date(2026, 10, 1)) == 19 * 60
|
||||
|
||||
def test_long_after_the_cut_stays_lowered(self) -> None:
|
||||
"""No drift back to 20:00; Anki's cut (from 2026-10-06) holds too."""
|
||||
later_cuts = earned_time.ANKI.shutdown_minutes
|
||||
"""No drift back to 20:00; every later earner's cut holds too."""
|
||||
cut = earned_time.READING.penalty_from
|
||||
assert cut is not None
|
||||
later_cuts = sum(
|
||||
e.shutdown_minutes
|
||||
for e in earned_time.EARNERS
|
||||
if e.penalty_from is not None and e.penalty_from > cut
|
||||
)
|
||||
assert base_minutes(date(2030, 1, 1)) == 19 * 60 - later_cuts
|
||||
|
||||
def test_default_is_the_local_today(self) -> None:
|
||||
@ -148,9 +157,12 @@ class TestResetIncludesReading:
|
||||
with caplog.at_level("INFO"):
|
||||
reset_to_base_if_new_day(tmp_path / "state.json", _mixin())
|
||||
base = base_minutes()
|
||||
later = "".join(
|
||||
f" + 0h {e.label}" for e in flat_earners() if e.name not in _NAMED
|
||||
)
|
||||
assert (
|
||||
f"Daily base reset: {hhmm(base + 60)} (base {hhmm(base)} + 0h workout + "
|
||||
"0h LeetCode + 1h reading + 0h Anki already earned today)."
|
||||
f"0h LeetCode + 1h reading{later} already earned today)."
|
||||
) in caplog.text
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user