studentpybox 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Talha_main
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,61 @@
1
+ Metadata-Version: 2.4
2
+ Name: studentpybox
3
+ Version: 0.1.0
4
+ Summary: A simple Python toolkit for university students: GPA tools and study planning helpers.
5
+ Author-email: Talha_main <450talhatahir@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/YOUR_GITHUB_USERNAME/studentpybox
8
+ Keywords: gpa,student,university,study,pomodoro,education
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Intended Audience :: Education
12
+ Classifier: Topic :: Education
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Dynamic: license-file
17
+
18
+ # studentpybox
19
+
20
+ A simple Python toolkit for university students, with two modules: **GPA tools** and **study planning helpers**.
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pip install studentpybox
26
+ ```
27
+
28
+ ## Modules & Functions
29
+
30
+ ### `studentpybox.gpa`
31
+
32
+ | Function | Description |
33
+ |---|---|
34
+ | `calculate_gpa(grades, credits)` | Credit-weighted GPA from a list of grade points and credit hours. |
35
+ | `percentage_to_grade(percentage)` | Convert a percentage score into a letter grade. |
36
+ | `cgpa_predictor(current_cgpa, completed_credits, target_cgpa, upcoming_credits)` | GPA needed in upcoming courses to hit a target CGPA. |
37
+ | `attendance_needed(attended, total, target_percentage=75.0)` | Classes still needed (or classes that can be skipped) to meet an attendance target. |
38
+
39
+ ### `studentpybox.study`
40
+
41
+ | Function | Description |
42
+ |---|---|
43
+ | `pomodoro_timer_text(work_minutes=25, break_minutes=5, sessions=4)` | Printable Pomodoro study schedule. |
44
+ | `random_motivation()` | A random short motivational line. |
45
+ | `study_hours_left(total_hours_needed, hours_completed)` | Remaining study hours and progress percentage. |
46
+ | `exam_countdown(exam_date, date_format="%Y-%m-%d")` | Days left until an exam date. |
47
+
48
+ ## Usage
49
+
50
+ ```python
51
+ from studentpybox import calculate_gpa, percentage_to_grade, random_motivation, exam_countdown
52
+
53
+ print(calculate_gpa([4.0, 3.3, 3.7], [3, 4, 3])) # 3.63
54
+ print(percentage_to_grade(82)) # B+
55
+ print(random_motivation()) # a random study quote
56
+ print(exam_countdown("2026-07-15")) # {'days_left': ..., 'status': 'upcoming'}
57
+ ```
58
+
59
+ ## License
60
+
61
+ MIT
@@ -0,0 +1,44 @@
1
+ # studentpybox
2
+
3
+ A simple Python toolkit for university students, with two modules: **GPA tools** and **study planning helpers**.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install studentpybox
9
+ ```
10
+
11
+ ## Modules & Functions
12
+
13
+ ### `studentpybox.gpa`
14
+
15
+ | Function | Description |
16
+ |---|---|
17
+ | `calculate_gpa(grades, credits)` | Credit-weighted GPA from a list of grade points and credit hours. |
18
+ | `percentage_to_grade(percentage)` | Convert a percentage score into a letter grade. |
19
+ | `cgpa_predictor(current_cgpa, completed_credits, target_cgpa, upcoming_credits)` | GPA needed in upcoming courses to hit a target CGPA. |
20
+ | `attendance_needed(attended, total, target_percentage=75.0)` | Classes still needed (or classes that can be skipped) to meet an attendance target. |
21
+
22
+ ### `studentpybox.study`
23
+
24
+ | Function | Description |
25
+ |---|---|
26
+ | `pomodoro_timer_text(work_minutes=25, break_minutes=5, sessions=4)` | Printable Pomodoro study schedule. |
27
+ | `random_motivation()` | A random short motivational line. |
28
+ | `study_hours_left(total_hours_needed, hours_completed)` | Remaining study hours and progress percentage. |
29
+ | `exam_countdown(exam_date, date_format="%Y-%m-%d")` | Days left until an exam date. |
30
+
31
+ ## Usage
32
+
33
+ ```python
34
+ from studentpybox import calculate_gpa, percentage_to_grade, random_motivation, exam_countdown
35
+
36
+ print(calculate_gpa([4.0, 3.3, 3.7], [3, 4, 3])) # 3.63
37
+ print(percentage_to_grade(82)) # B+
38
+ print(random_motivation()) # a random study quote
39
+ print(exam_countdown("2026-07-15")) # {'days_left': ..., 'status': 'upcoming'}
40
+ ```
41
+
42
+ ## License
43
+
44
+ MIT
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "studentpybox"
7
+ version = "0.1.0"
8
+ description = "A simple Python toolkit for university students: GPA tools and study planning helpers."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [
14
+ { name = "Talha_main", email = "450talhatahir@gmail.com" }
15
+ ]
16
+ keywords = ["gpa", "student", "university", "study", "pomodoro", "education"]
17
+ classifiers = [
18
+ "Programming Language :: Python :: 3",
19
+ "Operating System :: OS Independent",
20
+ "Intended Audience :: Education",
21
+ "Topic :: Education",
22
+ ]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/YOUR_GITHUB_USERNAME/studentpybox"
26
+
27
+ [tool.setuptools.packages.find]
28
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,36 @@
1
+ """
2
+ studentpybox - A simple Python toolkit for university students.
3
+
4
+ Modules:
5
+ gpa - GPA calculation, grading, and attendance helpers.
6
+ study - Study planning and motivation helpers.
7
+
8
+ All functions are also importable directly from the top-level package, e.g.:
9
+ from studentpybox import calculate_gpa, random_motivation
10
+ """
11
+
12
+ from .gpa import (
13
+ calculate_gpa,
14
+ percentage_to_grade,
15
+ cgpa_predictor,
16
+ attendance_needed,
17
+ )
18
+ from .study import (
19
+ pomodoro_timer_text,
20
+ random_motivation,
21
+ study_hours_left,
22
+ exam_countdown,
23
+ )
24
+
25
+ __version__ = "0.1.0"
26
+
27
+ __all__ = [
28
+ "calculate_gpa",
29
+ "percentage_to_grade",
30
+ "cgpa_predictor",
31
+ "attendance_needed",
32
+ "pomodoro_timer_text",
33
+ "random_motivation",
34
+ "study_hours_left",
35
+ "exam_countdown",
36
+ ]
@@ -0,0 +1,166 @@
1
+ """
2
+ gpa.py - GPA, grading, and attendance helpers for university students.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ # Standard 4.0-scale grade boundaries used by percentage_to_grade().
8
+ # Each tuple is (minimum percentage, letter grade, grade point).
9
+ _GRADE_TABLE = [
10
+ (90, "A", 4.0),
11
+ (85, "A-", 3.7),
12
+ (80, "B+", 3.3),
13
+ (75, "B", 3.0),
14
+ (70, "B-", 2.7),
15
+ (65, "C+", 2.3),
16
+ (60, "C", 2.0),
17
+ (55, "C-", 1.7),
18
+ (50, "D", 1.0),
19
+ (0, "F", 0.0),
20
+ ]
21
+
22
+
23
+ def calculate_gpa(grades: list[float], credits: list[float]) -> float:
24
+ """
25
+ Calculate a credit-weighted GPA.
26
+
27
+ Args:
28
+ grades: Grade points earned per course (e.g. [4.0, 3.3, 3.7]).
29
+ credits: Credit hours for each course, same order as grades.
30
+
31
+ Returns:
32
+ The weighted GPA rounded to 2 decimal places.
33
+
34
+ Example:
35
+ >>> calculate_gpa([4.0, 3.3, 3.7], [3, 4, 3])
36
+ 3.63
37
+ """
38
+ if not grades or not credits:
39
+ raise ValueError("grades and credits cannot be empty")
40
+ if len(grades) != len(credits):
41
+ raise ValueError("grades and credits must have the same length")
42
+ if any(c <= 0 for c in credits):
43
+ raise ValueError("credits must be positive numbers")
44
+
45
+ total_points = sum(g * c for g, c in zip(grades, credits))
46
+ total_credits = sum(credits)
47
+ return round(total_points / total_credits, 2)
48
+
49
+
50
+ def percentage_to_grade(percentage: float) -> str:
51
+ """
52
+ Convert a percentage score into a letter grade.
53
+
54
+ Args:
55
+ percentage: Score between 0 and 100.
56
+
57
+ Returns:
58
+ A letter grade, e.g. "A", "B+", "C-", "F".
59
+
60
+ Example:
61
+ >>> percentage_to_grade(82)
62
+ 'B+'
63
+ """
64
+ if not 0 <= percentage <= 100:
65
+ raise ValueError("percentage must be between 0 and 100")
66
+
67
+ for minimum, letter, _ in _GRADE_TABLE:
68
+ if percentage >= minimum:
69
+ return letter
70
+ return "F" # unreachable, but keeps type-checkers happy
71
+
72
+
73
+ def cgpa_predictor(
74
+ current_cgpa: float,
75
+ completed_credits: float,
76
+ target_cgpa: float,
77
+ upcoming_credits: float,
78
+ ) -> float:
79
+ """
80
+ Estimate the GPA needed in upcoming courses to reach a target CGPA.
81
+
82
+ Args:
83
+ current_cgpa: CGPA earned so far.
84
+ completed_credits: Total credit hours completed so far.
85
+ target_cgpa: The CGPA the student wants to reach.
86
+ upcoming_credits: Credit hours still to be taken.
87
+
88
+ Returns:
89
+ The GPA required in the upcoming credits, rounded to 2 decimals.
90
+ Can exceed 4.0 (or whatever your scale's max is) if the target
91
+ is no longer mathematically reachable -- the caller should
92
+ compare the result against their grading scale's maximum.
93
+
94
+ Example:
95
+ >>> cgpa_predictor(3.2, 60, 3.5, 20)
96
+ 4.4
97
+ """
98
+ if completed_credits <= 0 or upcoming_credits <= 0:
99
+ raise ValueError("credits must be positive numbers")
100
+
101
+ total_credits = completed_credits + upcoming_credits
102
+ required_total_points = target_cgpa * total_credits
103
+ current_points = current_cgpa * completed_credits
104
+ required_gpa = (required_total_points - current_points) / upcoming_credits
105
+ return round(required_gpa, 2)
106
+
107
+
108
+ def attendance_needed(
109
+ attended: int, total: int, target_percentage: float = 75.0
110
+ ) -> dict:
111
+ """
112
+ Work out attendance status against a target percentage.
113
+
114
+ Args:
115
+ attended: Classes attended so far.
116
+ total: Total classes held so far.
117
+ target_percentage: Required attendance percentage (default 75%).
118
+
119
+ Returns:
120
+ A dict with keys:
121
+ "current_percentage": current attendance percentage,
122
+ "status": "safe" or "short",
123
+ "classes_to_attend": consecutive classes still needed to
124
+ reach the target (0 if already met),
125
+ "classes_can_skip": consecutive classes that can still be
126
+ missed while staying at/above the target (0 if short).
127
+
128
+ Example:
129
+ >>> attendance_needed(28, 40, 75)
130
+ {'current_percentage': 70.0, 'status': 'short', 'classes_to_attend': 8, 'classes_can_skip': 0}
131
+ """
132
+ if total <= 0:
133
+ raise ValueError("total must be greater than 0")
134
+ if attended < 0 or attended > total:
135
+ raise ValueError("attended must be between 0 and total")
136
+ if not 0 < target_percentage <= 100:
137
+ raise ValueError("target_percentage must be between 0 and 100")
138
+
139
+ current_percentage = round((attended / total) * 100, 2)
140
+
141
+ if current_percentage >= target_percentage:
142
+ # How many more classes (all missed) could the student skip
143
+ # before dropping below the target?
144
+ can_skip = 0
145
+ while (attended) / (total + can_skip + 1) * 100 >= target_percentage:
146
+ can_skip += 1
147
+ return {
148
+ "current_percentage": current_percentage,
149
+ "status": "safe",
150
+ "classes_to_attend": 0,
151
+ "classes_can_skip": can_skip,
152
+ }
153
+ else:
154
+ # How many more classes (all attended) are needed to reach target?
155
+ need = 0
156
+ a, t = attended, total
157
+ while (a / t) * 100 < target_percentage:
158
+ a += 1
159
+ t += 1
160
+ need += 1
161
+ return {
162
+ "current_percentage": current_percentage,
163
+ "status": "short",
164
+ "classes_to_attend": need,
165
+ "classes_can_skip": 0,
166
+ }
@@ -0,0 +1,143 @@
1
+ """
2
+ study.py - Study planning and motivation helpers for university students.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import random
8
+ from datetime import datetime, date
9
+
10
+
11
+ # Original, short motivational lines (no external/copyrighted quotes).
12
+ _MOTIVATION_LINES = [
13
+ "Small steps every day add up to big results. Open the book.",
14
+ "You don't need to feel motivated to start -- starting creates the motivation.",
15
+ "Future you is counting on the work you put in right now.",
16
+ "Progress, not perfection. One page at a time.",
17
+ "The hardest part is opening the laptop. You've already done it.",
18
+ "Tired brains still learn -- just take it slow and keep going.",
19
+ "Every concept you understand today is one less thing to fear at exam time.",
20
+ "You've survived 100% of your hard days so far. This one's no different.",
21
+ "Done is better than perfect. Submit the draft, polish later.",
22
+ "Your only competition is who you were yesterday.",
23
+ ]
24
+
25
+
26
+ def pomodoro_timer_text(
27
+ work_minutes: int = 25, break_minutes: int = 5, sessions: int = 4
28
+ ) -> str:
29
+ """
30
+ Generate a printable Pomodoro study schedule.
31
+
32
+ Args:
33
+ work_minutes: Length of each focused work block (default 25).
34
+ break_minutes: Length of each short break (default 5).
35
+ sessions: Number of work/break cycles (default 4).
36
+
37
+ Returns:
38
+ A formatted multi-line schedule string, e.g.:
39
+ "Session 1: Study 25 min -> Break 5 min
40
+ Session 2: Study 25 min -> Break 5 min
41
+ ...
42
+ Total focused study time: 100 min"
43
+
44
+ Example:
45
+ >>> print(pomodoro_timer_text(25, 5, 2))
46
+ Session 1: Study 25 min -> Break 5 min
47
+ Session 2: Study 25 min -> Break 5 min
48
+ Total focused study time: 50 min
49
+ """
50
+ if work_minutes <= 0 or break_minutes <= 0 or sessions <= 0:
51
+ raise ValueError("work_minutes, break_minutes, and sessions must be positive")
52
+
53
+ lines = [
54
+ f"Session {i}: Study {work_minutes} min -> Break {break_minutes} min"
55
+ for i in range(1, sessions + 1)
56
+ ]
57
+ lines.append(f"Total focused study time: {work_minutes * sessions} min")
58
+ return "\n".join(lines)
59
+
60
+
61
+ def random_motivation() -> str:
62
+ """
63
+ Return a random, short motivational line for studying.
64
+
65
+ Returns:
66
+ A motivational sentence as a string.
67
+
68
+ Example:
69
+ >>> isinstance(random_motivation(), str)
70
+ True
71
+ """
72
+ return random.choice(_MOTIVATION_LINES)
73
+
74
+
75
+ def study_hours_left(total_hours_needed: float, hours_completed: float) -> dict:
76
+ """
77
+ Track remaining study hours against a goal.
78
+
79
+ Args:
80
+ total_hours_needed: Total hours planned for a subject/exam.
81
+ hours_completed: Hours already studied.
82
+
83
+ Returns:
84
+ A dict with keys:
85
+ "hours_remaining": hours still left (never negative),
86
+ "percent_complete": progress percentage, rounded to 1 decimal,
87
+ "status": "done" if the goal is met, otherwise "in_progress".
88
+
89
+ Example:
90
+ >>> study_hours_left(20, 8)
91
+ {'hours_remaining': 12, 'percent_complete': 40.0, 'status': 'in_progress'}
92
+ """
93
+ if total_hours_needed <= 0:
94
+ raise ValueError("total_hours_needed must be greater than 0")
95
+ if hours_completed < 0:
96
+ raise ValueError("hours_completed cannot be negative")
97
+
98
+ remaining = max(total_hours_needed - hours_completed, 0)
99
+ percent = round(min(hours_completed / total_hours_needed, 1) * 100, 1)
100
+ status = "done" if remaining == 0 else "in_progress"
101
+
102
+ return {
103
+ "hours_remaining": remaining,
104
+ "percent_complete": percent,
105
+ "status": status,
106
+ }
107
+
108
+
109
+ def exam_countdown(exam_date: str, date_format: str = "%Y-%m-%d") -> dict:
110
+ """
111
+ Calculate how much time is left until an exam.
112
+
113
+ Args:
114
+ exam_date: The exam date as a string, e.g. "2026-07-15".
115
+ date_format: The format exam_date is given in (default "%Y-%m-%d").
116
+
117
+ Returns:
118
+ A dict with keys:
119
+ "days_left": full days remaining (0 if today, negative if past),
120
+ "status": "upcoming", "today", or "past".
121
+
122
+ Example:
123
+ >>> exam_countdown("2099-01-01") # doctest: +SKIP
124
+ {'days_left': ..., 'status': 'upcoming'}
125
+ """
126
+ try:
127
+ target = datetime.strptime(exam_date, date_format).date()
128
+ except ValueError as exc:
129
+ raise ValueError(
130
+ f"exam_date '{exam_date}' does not match format '{date_format}'"
131
+ ) from exc
132
+
133
+ today = date.today()
134
+ days_left = (target - today).days
135
+
136
+ if days_left > 0:
137
+ status = "upcoming"
138
+ elif days_left == 0:
139
+ status = "today"
140
+ else:
141
+ status = "past"
142
+
143
+ return {"days_left": days_left, "status": status}
@@ -0,0 +1,61 @@
1
+ Metadata-Version: 2.4
2
+ Name: studentpybox
3
+ Version: 0.1.0
4
+ Summary: A simple Python toolkit for university students: GPA tools and study planning helpers.
5
+ Author-email: Talha_main <450talhatahir@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/YOUR_GITHUB_USERNAME/studentpybox
8
+ Keywords: gpa,student,university,study,pomodoro,education
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Intended Audience :: Education
12
+ Classifier: Topic :: Education
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Dynamic: license-file
17
+
18
+ # studentpybox
19
+
20
+ A simple Python toolkit for university students, with two modules: **GPA tools** and **study planning helpers**.
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pip install studentpybox
26
+ ```
27
+
28
+ ## Modules & Functions
29
+
30
+ ### `studentpybox.gpa`
31
+
32
+ | Function | Description |
33
+ |---|---|
34
+ | `calculate_gpa(grades, credits)` | Credit-weighted GPA from a list of grade points and credit hours. |
35
+ | `percentage_to_grade(percentage)` | Convert a percentage score into a letter grade. |
36
+ | `cgpa_predictor(current_cgpa, completed_credits, target_cgpa, upcoming_credits)` | GPA needed in upcoming courses to hit a target CGPA. |
37
+ | `attendance_needed(attended, total, target_percentage=75.0)` | Classes still needed (or classes that can be skipped) to meet an attendance target. |
38
+
39
+ ### `studentpybox.study`
40
+
41
+ | Function | Description |
42
+ |---|---|
43
+ | `pomodoro_timer_text(work_minutes=25, break_minutes=5, sessions=4)` | Printable Pomodoro study schedule. |
44
+ | `random_motivation()` | A random short motivational line. |
45
+ | `study_hours_left(total_hours_needed, hours_completed)` | Remaining study hours and progress percentage. |
46
+ | `exam_countdown(exam_date, date_format="%Y-%m-%d")` | Days left until an exam date. |
47
+
48
+ ## Usage
49
+
50
+ ```python
51
+ from studentpybox import calculate_gpa, percentage_to_grade, random_motivation, exam_countdown
52
+
53
+ print(calculate_gpa([4.0, 3.3, 3.7], [3, 4, 3])) # 3.63
54
+ print(percentage_to_grade(82)) # B+
55
+ print(random_motivation()) # a random study quote
56
+ print(exam_countdown("2026-07-15")) # {'days_left': ..., 'status': 'upcoming'}
57
+ ```
58
+
59
+ ## License
60
+
61
+ MIT
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/studentpybox/__init__.py
5
+ src/studentpybox/gpa.py
6
+ src/studentpybox/study.py
7
+ src/studentpybox.egg-info/PKG-INFO
8
+ src/studentpybox.egg-info/SOURCES.txt
9
+ src/studentpybox.egg-info/dependency_links.txt
10
+ src/studentpybox.egg-info/top_level.txt
11
+ tests/test_studentpybox.py
@@ -0,0 +1 @@
1
+ studentpybox
@@ -0,0 +1,60 @@
1
+ from studentpybox import (
2
+ calculate_gpa,
3
+ percentage_to_grade,
4
+ cgpa_predictor,
5
+ attendance_needed,
6
+ pomodoro_timer_text,
7
+ random_motivation,
8
+ study_hours_left,
9
+ exam_countdown,
10
+ )
11
+
12
+
13
+ def test_calculate_gpa():
14
+ assert calculate_gpa([4.0, 3.3, 3.7], [3, 4, 3]) == 3.63
15
+
16
+
17
+ def test_percentage_to_grade():
18
+ assert percentage_to_grade(95) == "A"
19
+ assert percentage_to_grade(82) == "B+"
20
+ assert percentage_to_grade(40) == "F"
21
+
22
+
23
+ def test_cgpa_predictor():
24
+ assert cgpa_predictor(3.2, 60, 3.5, 20) == 4.4
25
+
26
+
27
+ def test_attendance_needed_short():
28
+ result = attendance_needed(28, 40, 75)
29
+ assert result["status"] == "short"
30
+ assert result["classes_to_attend"] == 8
31
+
32
+
33
+ def test_attendance_needed_safe():
34
+ result = attendance_needed(38, 40, 75)
35
+ assert result["status"] == "safe"
36
+ assert result["classes_to_attend"] == 0
37
+
38
+
39
+ def test_pomodoro_timer_text():
40
+ text = pomodoro_timer_text(25, 5, 2)
41
+ assert "Session 1" in text
42
+ assert "Total focused study time: 50 min" in text
43
+
44
+
45
+ def test_random_motivation():
46
+ assert isinstance(random_motivation(), str)
47
+ assert len(random_motivation()) > 0
48
+
49
+
50
+ def test_study_hours_left():
51
+ result = study_hours_left(20, 8)
52
+ assert result["hours_remaining"] == 12
53
+ assert result["percent_complete"] == 40.0
54
+ assert result["status"] == "in_progress"
55
+
56
+
57
+ def test_exam_countdown_upcoming():
58
+ result = exam_countdown("2099-01-01")
59
+ assert result["status"] == "upcoming"
60
+ assert result["days_left"] > 0