mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-07-04 11:43:09 +02:00
- Refactor RunnerUp verification: extract RunnerUpDbMixin (_runnerup_db.py), split _scan_and_fill_week_runnerup into a helper _try_fill_runnerup_for_date to keep cyclomatic complexity ≤10 - Generalise TCX lookup to any date in the ISO week (was today-only); all gap days Mon→today auto-filled on every startup and 08:30 timer firing - Add _adjust_shutdown_time_by(): +1h per extra workout beyond the 4-workout minimum, capped at midnight (hour=24) - Add _shutdown_base.py: daily reset of shutdown config to a stored base so the bonus doesn't silently accumulate across days - Add _extra_benefits.py: streak tracking, skip credits (earn (n-4) credits for 5+ workout weeks), early-bird extension to 09:00 for eligible weeks - Add --status mode (_status.py): non-locking CLI view showing per-day breakdown (✓/✗), RunnerUp auto-scan, bonus status, shutdown time, streak, skip credits, and early-bird status - Hook carrot into _check_non_verify_exits: bonus applied whenever auto-fill pushes weekly count above the minimum - Pass all pre-commit hooks (ruff, mypy, pylint, bandit, shellcheck, codespell, max-file-length); 508 tests at 100% branch coverage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017auyHmf2ZwQcDAwXaSo7KX
170 lines
4.0 KiB
TOML
170 lines
4.0 KiB
TOML
[project]
|
|
name = "screen-locker"
|
|
version = "1.0.0"
|
|
description = "Tkinter/systemd screen locker with workout tracking, sick-day management, and wake-alarm integration"
|
|
requires-python = ">=3.10"
|
|
# gatelock: shared lock-window/HMAC backend, also used by diet_guard and wake_alarm
|
|
dependencies = [
|
|
"gatelock @ git+https://github.com/kuhyx/gatelock@v0.1.0",
|
|
]
|
|
|
|
[tool.setuptools.packages.find]
|
|
# This repo also holds stronglift_replacement/ (an unrelated Flutter app, not
|
|
# a Python package); without this, setuptools' automatic flat-layout
|
|
# discovery sees two top-level directories and refuses to guess which is the
|
|
# installable package.
|
|
include = ["screen_locker*"]
|
|
|
|
[tool.ruff]
|
|
target-version = "py310"
|
|
include = ["*.py", "**/*.py"]
|
|
exclude = [".git", ".venv", "__pycache__", "build", "dist", ".eggs"]
|
|
|
|
[tool.ruff.lint]
|
|
select = ["ALL"]
|
|
ignore = [
|
|
"D203",
|
|
"D213",
|
|
"COM812",
|
|
"ISC001",
|
|
"S603",
|
|
]
|
|
fixable = ["ALL"]
|
|
unfixable = []
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"**/tests/**/*.py" = [
|
|
"ANN", "ARG", "D", "DTZ011", "E501", "FBT",
|
|
"PLC0415", "PLR2004", "PTH", "RUF003", "S101", "SLF001",
|
|
]
|
|
"**/test_*.py" = [
|
|
"ANN", "ARG", "D", "DTZ011", "E501", "FBT",
|
|
"PLC0415", "PLR2004", "PTH", "RUF003", "S101", "SLF001",
|
|
]
|
|
"screen_locker/_runnerup_verification.py" = ["S314"]
|
|
"screen_locker/_shutdown_base.py" = ["SLF001"]
|
|
"screen_locker/_status.py" = ["PLR0915", "SLF001", "T201"]
|
|
"scripts/check_file_length.py" = ["PTH123"]
|
|
|
|
[tool.ruff.lint.pydocstyle]
|
|
convention = "google"
|
|
|
|
[tool.ruff.lint.isort]
|
|
force-single-line = false
|
|
force-sort-within-sections = true
|
|
known-first-party = ["screen_locker"]
|
|
|
|
[tool.ruff.lint.flake8-quotes]
|
|
docstring-quotes = "double"
|
|
inline-quotes = "double"
|
|
|
|
[tool.ruff.lint.flake8-tidy-imports]
|
|
ban-relative-imports = "all"
|
|
|
|
[tool.ruff.format]
|
|
quote-style = "double"
|
|
indent-style = "space"
|
|
skip-magic-trailing-comma = false
|
|
line-ending = "auto"
|
|
docstring-code-format = true
|
|
|
|
[tool.mypy]
|
|
python_version = "3.10"
|
|
strict = true
|
|
warn_return_any = true
|
|
warn_unused_configs = true
|
|
disallow_untyped_defs = true
|
|
disallow_incomplete_defs = true
|
|
check_untyped_defs = true
|
|
disallow_untyped_decorators = true
|
|
no_implicit_optional = true
|
|
warn_redundant_casts = true
|
|
warn_unused_ignores = true
|
|
warn_no_return = true
|
|
warn_unreachable = true
|
|
disallow_any_unimported = true
|
|
disallow_any_explicit = false
|
|
disallow_any_generics = true
|
|
disallow_subclassing_any = true
|
|
strict_equality = true
|
|
extra_checks = true
|
|
ignore_missing_imports = true
|
|
show_error_codes = true
|
|
color_output = true
|
|
exclude = [".venv/"]
|
|
|
|
[tool.pylint.main]
|
|
analyse-fallback-blocks = true
|
|
persistent = true
|
|
jobs = 0
|
|
py-version = "3.10"
|
|
ignore = [".venv", "__pycache__"]
|
|
ignore-patterns = [".*\\.pyi$"]
|
|
|
|
[tool.pylint.messages_control]
|
|
enable = "all"
|
|
disable = []
|
|
|
|
[tool.pylint.design]
|
|
min-public-methods = 0
|
|
max-module-lines = 1000
|
|
max-attributes = 10
|
|
|
|
[tool.pylint.typecheck]
|
|
generated-members = [
|
|
".*\\.assert_called_once_with",
|
|
".*\\.assert_called_once",
|
|
".*\\.assert_called",
|
|
".*\\.assert_not_called",
|
|
".*\\.assert_any_call",
|
|
".*\\.call_args",
|
|
".*\\.call_args_list",
|
|
".*\\.call_count",
|
|
]
|
|
|
|
[tool.bandit]
|
|
exclude_dirs = ["tests", ".venv"]
|
|
|
|
[tool.pytest.ini_options]
|
|
testpaths = ["screen_locker/tests"]
|
|
python_files = ["test_*.py", "*_test.py"]
|
|
python_classes = ["Test*"]
|
|
python_functions = ["test_*"]
|
|
addopts = [
|
|
"-v",
|
|
"--strict-markers",
|
|
"--strict-config",
|
|
"-ra",
|
|
"--cov=screen_locker",
|
|
"--cov-branch",
|
|
"--cov-report=term-missing",
|
|
"--cov-report=lcov",
|
|
]
|
|
filterwarnings = [
|
|
"error",
|
|
"ignore::DeprecationWarning",
|
|
"default::pytest.PytestUnraisableExceptionWarning",
|
|
]
|
|
|
|
[tool.coverage.run]
|
|
source = ["screen_locker"]
|
|
branch = true
|
|
omit = [
|
|
"*/__pycache__/*",
|
|
"*/tests/*",
|
|
"*/.venv/*",
|
|
]
|
|
|
|
[tool.coverage.report]
|
|
fail_under = 100
|
|
show_missing = true
|
|
skip_covered = false
|
|
exclude_lines = [
|
|
"pragma: no cover",
|
|
"raise NotImplementedError",
|
|
"raise AssertionError",
|
|
"if TYPE_CHECKING:",
|
|
'if __name__ == "__main__":',
|
|
]
|
|
partial_branches = ["pragma: no branch"]
|