mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 22:07:15 +01:00
freedays 0.3.0: WORKDAYS (Tue/Wed/Thu) as the one weekly-workday definition for every gate app
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0af237af3d
commit
4bd6bce0df
@ -52,6 +52,15 @@ app launch.
|
||||
| **Releasing refunds only the future** | Give back a day that has not arrived and it returns to the pool. Give back today, and it does not: those hours were already unguarded. |
|
||||
| **Silent** | No notification, no low-budget warning, no prompt when a gate fires. You find out by asking. |
|
||||
|
||||
## Weekly workdays
|
||||
|
||||
`freedays.WORKDAYS` (`{1, 2, 3}`, Tue/Wed/Thu in `date.weekday()` numbering),
|
||||
`NON_WORKDAYS` and `is_workday(day=None)` are the one definition of the weekly
|
||||
workdays every gate app reads — screen-locker's relaxed days, leetcode-guard's
|
||||
cheap days, wake-alarm's ramp hold and workday stick. Import it; never write
|
||||
the set out again. Dart/Kotlin code that cannot import it keeps a literal copy
|
||||
guarded by a drift test against this package.
|
||||
|
||||
## Free days are not sick days
|
||||
|
||||
screen-locker's sick days stay exactly where they are, with their rolling
|
||||
|
||||
@ -52,9 +52,12 @@ from freedays._errors import (
|
||||
from freedays._model import FreeDay
|
||||
from freedays._paths import Paths
|
||||
from freedays._sync import SyncUnavailableError, sync, sync_quietly
|
||||
from freedays._workdays import NON_WORKDAYS, WORKDAYS, is_workday
|
||||
|
||||
__all__ = [
|
||||
"DEFAULT_ANNUAL_BUDGET",
|
||||
"NON_WORKDAYS",
|
||||
"WORKDAYS",
|
||||
"AlreadyFreeError",
|
||||
"BudgetExhaustedError",
|
||||
"FreeDay",
|
||||
@ -68,6 +71,7 @@ __all__ = [
|
||||
"free_days_in_year",
|
||||
"is_exhausted",
|
||||
"is_free_day",
|
||||
"is_workday",
|
||||
"load",
|
||||
"lookup",
|
||||
"mark",
|
||||
|
||||
38
freedays/freedays/_workdays.py
Normal file
38
freedays/freedays/_workdays.py
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright (c) 2026 Krzysztof Rudnicki
|
||||
"""The weekly workdays: Tuesday, Wednesday and Thursday.
|
||||
|
||||
The one definition every gate app reads, so "which days are workdays" cannot
|
||||
drift between them. Consumers each give it their own meaning: screen-locker
|
||||
relaxes the lock, leetcode-guard charges the cheap price, wake-alarm's ramp
|
||||
holds the wake time instead of stepping it earlier, and a missed workday
|
||||
morning costs tomorrow its leniency.
|
||||
|
||||
Languages that cannot import this package (the Dart and Kotlin sides of the
|
||||
phone apps) keep a literal copy and a test that fails when it drifts from
|
||||
this one.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from typing import Final
|
||||
|
||||
from freedays._day import today
|
||||
|
||||
#: Python ``date.weekday()`` numbering: Mon=0 ... Sun=6.
|
||||
WORKDAYS: Final[frozenset[int]] = frozenset({1, 2, 3})
|
||||
|
||||
#: The complement: Monday, Friday, Saturday and Sunday.
|
||||
NON_WORKDAYS: Final[frozenset[int]] = frozenset(range(7)) - WORKDAYS
|
||||
|
||||
|
||||
def is_workday(day: date | None = None) -> bool:
|
||||
"""Return whether *day* (default: today, local) is a weekly workday.
|
||||
|
||||
Args:
|
||||
day: The date to classify; ``None`` means today.
|
||||
|
||||
Returns:
|
||||
True on Tuesday, Wednesday and Thursday.
|
||||
"""
|
||||
return today(day).weekday() in WORKDAYS
|
||||
39
freedays/freedays/tests/test_workdays.py
Normal file
39
freedays/freedays/tests/test_workdays.py
Normal file
@ -0,0 +1,39 @@
|
||||
# Copyright (c) 2026 Krzysztof Rudnicki
|
||||
"""The weekly workdays: the one Tue/Wed/Thu definition every app reads."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
|
||||
import pytest
|
||||
|
||||
import freedays
|
||||
|
||||
|
||||
def test_workdays_are_tuesday_to_thursday() -> None:
|
||||
assert freedays.WORKDAYS == frozenset({1, 2, 3})
|
||||
|
||||
|
||||
def test_non_workdays_are_the_complement() -> None:
|
||||
assert freedays.NON_WORKDAYS == frozenset({0, 4, 5, 6})
|
||||
assert not freedays.WORKDAYS & freedays.NON_WORKDAYS
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("day", "expected"),
|
||||
[
|
||||
(date(2026, 9, 28), False), # Monday
|
||||
(date(2026, 9, 29), True), # Tuesday
|
||||
(date(2026, 9, 30), True), # Wednesday
|
||||
(date(2026, 10, 1), True), # Thursday
|
||||
(date(2026, 10, 2), False), # Friday
|
||||
(date(2026, 10, 3), False), # Saturday
|
||||
(date(2026, 10, 4), False), # Sunday
|
||||
],
|
||||
)
|
||||
def test_is_workday(day: date, expected: bool) -> None:
|
||||
assert freedays.is_workday(day) is expected
|
||||
|
||||
|
||||
def test_is_workday_defaults_to_today() -> None:
|
||||
assert freedays.is_workday() is (date.today().weekday() in {1, 2, 3})
|
||||
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "freedays"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
description = "Shared pre-declared free-day pool: one global list of days on which every gate app stands down"
|
||||
requires-python = ">=3.14"
|
||||
# Deliberately NOT gatelock. Its __init__ imports tkinter for the lock-window
|
||||
|
||||
Loading…
Reference in New Issue
Block a user