Coverage for src / license_checker.py: 100%
24 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-19 22:28 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-19 22:28 +0000
1import os
2from datetime import datetime, timedelta
4from playsound import playsound
6LICENSE_FILE = "license.txt"
7LICENSE_DURATION_DAYS = 365 # 1 year
10def check_license(
11 license_file: str = LICENSE_FILE,
12 license_duration_days: int = LICENSE_DURATION_DAYS,
13) -> bool:
14 """
15 Check whether the current license is expired.
17 Reads the installation date (YYYY-MM-DD) from *license_file* and compares
18 it against today's date. When the license has expired the function:
19 1. Prints an expiry message to stdout.
20 2. Plays an alert sound **twice** via playsound.
21 3. Returns False.
23 :param license_file: Path to the file that stores the installation date.
24 :param license_duration_days: Number of days the license remains valid
25 (default: 365).
26 :return: True if the license is still valid, False if it has expired.
27 :raises FileNotFoundError: When *license_file* does not exist.
28 :raises ValueError: When the date stored in the file cannot be parsed.
29 """
30 if not os.path.exists(license_file):
31 raise FileNotFoundError(
32 f"License file '{license_file}' not found. "
33 "Please reinstall the application."
34 )
36 with open(license_file, "r") as fh:
37 raw = fh.read().strip()
39 try:
40 installed_date = datetime.strptime(raw, "%Y-%m-%d")
41 except ValueError as exc:
42 raise ValueError(
43 f"Invalid date format in license file (expected YYYY-MM-DD): '{raw}'"
44 ) from exc
46 expiry_date = installed_date + timedelta(days=license_duration_days)
47 today = datetime.today()
49 if today > expiry_date:
50 print(
51 f"⚠ License expired on {expiry_date.strftime('%Y-%m-%d')}. "
52 "Please renew your license."
53 )
54 playsound("alert.wav")
55 playsound("alert.wav")
56 return False
58 days_left = (expiry_date - today).days
59 print(f"✔ License is valid. Expires on {expiry_date.strftime('%Y-%m-%d')} "
60 f"({days_left} day(s) remaining).")
61 return True