mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-07-04 11:43:09 +02:00
chore: optimize pre-commit, remove tracked binaries, fix lint issues
- Move slow hooks (mypy, pylint, bandit, pytest, prettier) to pre-push stage - Remove redundant autoflake (ruff covers F401/F841) - Fix shellcheck OOM by batching files with xargs -n 40 - Remove tracked .o, .wav, .pyc binaries from git - Move pomodoro wav files to ../testsAndMisc_binaries/ with symlinks - Add *.o, *.so, *.a to .gitignore - Refactor hltb._pick_best_hltb_entry to fix C901/PLR0911/SIM102 - Fix SC2034 warnings in gif_to_square.sh and upgrade.sh - Add disk_cleanup_check.sh script - Various test and code improvements across screen_locker, steam_backlog_enforcer, word_frequency, moviepy_showcase
This commit is contained in:
parent
f71024e9f4
commit
9c409a32cd
@ -4,10 +4,8 @@
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SCREEN_LOCK_PATH="$SCRIPT_DIR/screen_lock.py"
|
||||
SERVICE_FILE="$SCRIPT_DIR/workout-locker.service"
|
||||
TIMER_FILE="$SCRIPT_DIR/workout-locker.timer"
|
||||
USER_SERVICE_DIR="$HOME/.config/systemd/user"
|
||||
SERVICE_NAME="workout-locker.service"
|
||||
TIMER_NAME="workout-locker.timer"
|
||||
|
||||
# Check if service is already installed
|
||||
if [ -f "$USER_SERVICE_DIR/$SERVICE_NAME" ]; then
|
||||
@ -26,9 +24,14 @@ fi
|
||||
# Create user systemd directory if it doesn't exist
|
||||
mkdir -p "$USER_SERVICE_DIR"
|
||||
|
||||
# Copy service and timer files to user systemd directory
|
||||
# Remove old timer if it was previously installed
|
||||
if systemctl --user is-active "workout-locker.timer" &>/dev/null; then
|
||||
systemctl --user disable --now "workout-locker.timer" 2>/dev/null || true
|
||||
fi
|
||||
rm -f "$USER_SERVICE_DIR/workout-locker.timer"
|
||||
|
||||
# Copy service file to user systemd directory
|
||||
cp "$SERVICE_FILE" "$USER_SERVICE_DIR/$SERVICE_NAME"
|
||||
cp "$TIMER_FILE" "$USER_SERVICE_DIR/$TIMER_NAME"
|
||||
|
||||
# Update paths in the service file to use absolute paths
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
@ -39,18 +42,16 @@ sed -i "s|ExecStart=/usr/bin/python3.*|ExecStart=/usr/bin/python3 -m python_pkg.
|
||||
# Reload systemd daemon
|
||||
systemctl --user daemon-reload
|
||||
|
||||
# Enable the service to start on login and the timer for periodic checks
|
||||
# Enable the service to start on login (one-shot, no periodic timer)
|
||||
systemctl --user enable "$SERVICE_NAME"
|
||||
systemctl --user enable --now "$TIMER_NAME"
|
||||
|
||||
echo "✓ Workout locker service installed"
|
||||
echo "✓ Service will start automatically on next login"
|
||||
echo ""
|
||||
echo "To start now: systemctl --user start workout-locker"
|
||||
echo "To check status: systemctl --user status workout-locker"
|
||||
echo "To check timer: systemctl --user list-timers workout-locker.timer"
|
||||
echo "To stop: systemctl --user stop workout-locker"
|
||||
echo "To disable autostart: systemctl --user disable workout-locker workout-locker.timer"
|
||||
echo "To disable autostart: systemctl --user disable workout-locker"
|
||||
|
||||
# Check autostart installation status
|
||||
echo ""
|
||||
|
||||
@ -50,6 +50,21 @@ __all__ = [
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _assert_not_under_pytest() -> None:
|
||||
"""Raise if the screen locker is being created inside a pytest run.
|
||||
|
||||
Defence-in-depth: prevents a real fullscreen Tk window from locking
|
||||
the user's screen when tests forget to mock ``tk.Tk``.
|
||||
The check is cheap (one dict lookup) and only fires during testing.
|
||||
"""
|
||||
if "pytest" in sys.modules and getattr(tk, "__name__", "") == "tkinter":
|
||||
msg = (
|
||||
"SAFETY: ScreenLocker.__init__ called under pytest with "
|
||||
"real tkinter — tk.Tk is not mocked"
|
||||
)
|
||||
raise RuntimeError(msg)
|
||||
|
||||
|
||||
class ScreenLocker(
|
||||
ShutdownMixin,
|
||||
PhoneVerificationMixin,
|
||||
@ -64,6 +79,7 @@ class ScreenLocker(
|
||||
verify_only: bool = False,
|
||||
) -> None:
|
||||
"""Initialize screen locker with optional demo mode."""
|
||||
_assert_not_under_pytest()
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
self.log_file = script_dir / "workout_log.json"
|
||||
self.verify_only = verify_only
|
||||
|
||||
@ -1,4 +1,12 @@
|
||||
"""Shared fixtures and helpers for screen_locker tests."""
|
||||
"""Shared fixtures and helpers for screen_locker tests.
|
||||
|
||||
Safety:
|
||||
``_block_real_tk_and_exit`` (autouse) replaces the **entire** ``tk``
|
||||
module reference inside ``screen_lock`` with a MagicMock and stubs
|
||||
``sys.exit``. This makes it physically impossible for any test to
|
||||
create a real Tk root window, go fullscreen, or grab input — even if
|
||||
the test forgets to request the explicit ``mock_tk`` fixture.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@ -12,7 +20,40 @@ import pytest
|
||||
from python_pkg.screen_locker.screen_lock import ScreenLocker
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Generator
|
||||
from collections.abc import Generator, Iterator
|
||||
|
||||
|
||||
def _make_mock_tk() -> MagicMock:
|
||||
"""Build a MagicMock that stands in for the ``tkinter`` module."""
|
||||
mock = MagicMock()
|
||||
mock_root = MagicMock()
|
||||
mock_root.winfo_screenwidth.return_value = 1920
|
||||
mock_root.winfo_screenheight.return_value = 1080
|
||||
mock.Tk.return_value = mock_root
|
||||
|
||||
mock_frame = MagicMock()
|
||||
mock_frame.winfo_children.return_value = []
|
||||
mock.Frame.return_value = mock_frame
|
||||
|
||||
# Keep real TclError so ``except tk.TclError`` still works.
|
||||
mock.TclError = tk.TclError
|
||||
return mock
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _block_real_tk_and_exit() -> Iterator[None]:
|
||||
"""Replace the whole ``tk`` module and ``sys.exit`` for every test.
|
||||
|
||||
Patching the entire module (not just ``tk.Tk``) ensures that
|
||||
**nothing** in tkinter can touch the real display server.
|
||||
"""
|
||||
mock = _make_mock_tk()
|
||||
|
||||
with (
|
||||
patch("python_pkg.screen_locker.screen_lock.tk", mock),
|
||||
patch("python_pkg.screen_locker.screen_lock.sys.exit"),
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@ -10,12 +10,29 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from python_pkg.screen_locker.screen_lock import _assert_not_under_pytest
|
||||
from python_pkg.screen_locker.tests.conftest import create_locker
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class TestAssertNotUnderPytest:
|
||||
"""Tests for the _assert_not_under_pytest runtime guard."""
|
||||
|
||||
def test_raises_when_tk_is_real(self) -> None:
|
||||
"""Guard fires if tk.Tk is the real tkinter class under pytest."""
|
||||
with (
|
||||
patch("python_pkg.screen_locker.screen_lock.tk", tk),
|
||||
pytest.raises(RuntimeError, match="SAFETY"),
|
||||
):
|
||||
_assert_not_under_pytest()
|
||||
|
||||
def test_silent_when_tk_is_mocked(self) -> None:
|
||||
"""Guard stays silent when tk is already mocked (normal test run)."""
|
||||
_assert_not_under_pytest()
|
||||
|
||||
|
||||
class TestScreenLockerInit:
|
||||
"""Tests for ScreenLocker initialization."""
|
||||
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
[Unit]
|
||||
Description=Periodically check if workout was done today
|
||||
|
||||
[Timer]
|
||||
OnBootSec=5s
|
||||
OnUnitActiveSec=15min
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
Loading…
Reference in New Issue
Block a user