PomCli 0.1.0__tar.gz → 0.2.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.
- pomcli-0.2.0/CHANGELOG.md +11 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/PKG-INFO +3 -1
- {pomcli-0.1.0 → pomcli-0.2.0}/README.md +1 -0
- pomcli-0.2.0/pomodoro_example.py +4 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/pyproject.toml +3 -1
- {pomcli-0.1.0 → pomcli-0.2.0}/src/pomcli/__about__.py +1 -2
- pomcli-0.2.0/src/pomcli/pomodoro.py +79 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/tests/test_pomodoro.py +30 -4
- pomcli-0.1.0/pomodoro_example.py +0 -5
- pomcli-0.1.0/src/pomcli/pomodoro.py +0 -43
- {pomcli-0.1.0 → pomcli-0.2.0}/.idea/.gitignore +0 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/.idea/.name +0 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/.idea/PomCli.iml +0 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/.idea/misc.xml +0 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/.idea/modules.xml +0 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/.idea/workspace.xml +0 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/LICENSE.txt +0 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/src/pomcli/__init__.py +0 -0
- {pomcli-0.1.0 → pomcli-0.2.0}/tests/__init__.py +0 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## [0.2.0] - 2025-06-28
|
4
|
+
### Added
|
5
|
+
- Support for multiple Pomodoro repetitions via the `--repetitions` CLI option.
|
6
|
+
- Optional progress bar display using `tqdm` with the `--tqdm` CLI flag.
|
7
|
+
|
8
|
+
## [0.1.0] - 2025-06-28
|
9
|
+
### Added
|
10
|
+
- Initial release: basic Pomodoro timer CLI with work and break durations.
|
11
|
+
lo
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: PomCli
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Summary: A simple Pomodoro timer CLI tool.
|
5
5
|
Project-URL: Documentation, https://github.com/YanivGrosskopf/PomCli#readme
|
6
6
|
Project-URL: Issues, https://github.com/YanivGrosskopf/PomCli/issues
|
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
18
18
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
19
19
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
20
20
|
Requires-Python: >=3.8
|
21
|
+
Requires-Dist: tqdm>=4.0.0
|
21
22
|
Description-Content-Type: text/markdown
|
22
23
|
|
23
24
|
# PomCli
|
@@ -49,6 +50,7 @@ pomcli --work 25 --break_time 5
|
|
49
50
|
|
50
51
|
- `--work`: Work duration in minutes (default: 25)
|
51
52
|
- `--break_time`: Break duration in minutes (default: 5)
|
53
|
+
- `--repetitions`: Number of repetitions (default: 1)
|
52
54
|
|
53
55
|
## License
|
54
56
|
|
@@ -24,7 +24,9 @@ classifiers = [
|
|
24
24
|
"Programming Language :: Python :: Implementation :: CPython",
|
25
25
|
"Programming Language :: Python :: Implementation :: PyPy",
|
26
26
|
]
|
27
|
-
dependencies = [
|
27
|
+
dependencies = [
|
28
|
+
"tqdm>=4.0.0"
|
29
|
+
]
|
28
30
|
|
29
31
|
[project.urls]
|
30
32
|
Documentation = "https://github.com/YanivGrosskopf/PomCli#readme"
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import logging
|
2
|
+
import time
|
3
|
+
|
4
|
+
|
5
|
+
class PomodoroTimer:
|
6
|
+
def __init__(self, work_minutes=25, break_minutes=5, repetitions=1, logger=None, use_tqdm=False):
|
7
|
+
"""
|
8
|
+
Initializes the Pomodoro timer.
|
9
|
+
:param work_minutes: Work duration in minutes.
|
10
|
+
:param break_minutes: Break duration in minutes.
|
11
|
+
:param repetitions: Number of Pomodoro repetitions.
|
12
|
+
:param logger: Logger instance for logging messages. If None, a default logger is created.
|
13
|
+
:param use_tqdm: Whether to use tqdm for progress bar display.
|
14
|
+
"""
|
15
|
+
self.work_minutes = work_minutes
|
16
|
+
self.break_minutes = break_minutes
|
17
|
+
self.repetitions = repetitions
|
18
|
+
self.is_running = False
|
19
|
+
if logger is None:
|
20
|
+
logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(message)s')
|
21
|
+
self.logger = logger or logging.getLogger(__name__)
|
22
|
+
|
23
|
+
self.use_tqdm = use_tqdm
|
24
|
+
|
25
|
+
def start(self):
|
26
|
+
"""
|
27
|
+
Starts the Pomodoro timer.
|
28
|
+
"""
|
29
|
+
self.is_running = True
|
30
|
+
for i in range(self.repetitions):
|
31
|
+
self.logger.info(f"Pomodoro round {i + 1} of {self.repetitions}")
|
32
|
+
self.logger.info(f"Starting Pomodoro: {self.work_minutes} minutes of work.")
|
33
|
+
self._countdown(self.work_minutes * 60, "Work")
|
34
|
+
if i < self.repetitions - 1:
|
35
|
+
self.logger.info(f"Time for a break: {self.break_minutes} minutes.")
|
36
|
+
self.logger.info("Pomodoro session complete!")
|
37
|
+
self.is_running = False
|
38
|
+
|
39
|
+
def _countdown(self, seconds, label):
|
40
|
+
if self.use_tqdm:
|
41
|
+
try:
|
42
|
+
from tqdm import tqdm
|
43
|
+
except ImportError:
|
44
|
+
self.logger.warning("tqdm is not installed. Progress bar will not be shown.")
|
45
|
+
tqdm = None
|
46
|
+
else:
|
47
|
+
tqdm = None
|
48
|
+
seconds = int(seconds)
|
49
|
+
iterator = tqdm(range(seconds), desc=f"{label} Timer",
|
50
|
+
ncols=70) if self.use_tqdm and 'tqdm' in locals() and tqdm else range(seconds)
|
51
|
+
for s in iterator:
|
52
|
+
if not self.is_running:
|
53
|
+
break
|
54
|
+
mins, secs = divmod(int(seconds - s - 1), 60)
|
55
|
+
timeformat = f'{mins:02d}:{secs:02d}'
|
56
|
+
self.logger.debug(f'{label} Timer: {timeformat}')
|
57
|
+
time.sleep(1)
|
58
|
+
|
59
|
+
def stop(self):
|
60
|
+
self.is_running = False
|
61
|
+
self.logger.info("Pomodoro stopped.")
|
62
|
+
|
63
|
+
|
64
|
+
def main():
|
65
|
+
import argparse
|
66
|
+
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
67
|
+
parser = argparse.ArgumentParser(description="Simple Pomodoro CLI Timer")
|
68
|
+
parser.add_argument('--work', type=float, default=25, help='Work duration in minutes (default: 25)')
|
69
|
+
parser.add_argument('--break_time', type=float, default=5, help='Break duration in minutes (default: 5)')
|
70
|
+
parser.add_argument('--repetitions', type=int, default=1, help='Number of Pomodoro repetitions (default: 1)')
|
71
|
+
parser.add_argument('--tqdm', action='store_true', help='Show progress bar using tqdm')
|
72
|
+
args = parser.parse_args()
|
73
|
+
timer = PomodoroTimer(work_minutes=args.work, break_minutes=args.break_time, repetitions=args.repetitions,
|
74
|
+
use_tqdm=args.tqdm)
|
75
|
+
timer.start()
|
76
|
+
|
77
|
+
|
78
|
+
if __name__ == "__main__":
|
79
|
+
main()
|
@@ -1,8 +1,10 @@
|
|
1
|
-
import unittest
|
2
|
-
import time
|
3
1
|
import logging
|
2
|
+
import time
|
3
|
+
import unittest
|
4
|
+
|
4
5
|
from pomcli.pomodoro import PomodoroTimer
|
5
6
|
|
7
|
+
|
6
8
|
class TestPomodoroTimer(unittest.TestCase):
|
7
9
|
def setUp(self):
|
8
10
|
self.logger = logging.getLogger("pomodoro_test")
|
@@ -15,17 +17,19 @@ class TestPomodoroTimer(unittest.TestCase):
|
|
15
17
|
class _LogCapture:
|
16
18
|
def __init__(self, output_list):
|
17
19
|
self.output_list = output_list
|
20
|
+
|
18
21
|
def write(self, msg):
|
19
22
|
if msg.strip():
|
20
23
|
self.output_list.append(msg.strip())
|
24
|
+
|
21
25
|
def flush(self):
|
22
26
|
pass
|
23
27
|
|
24
28
|
def test_start_and_stop(self):
|
25
29
|
timer = PomodoroTimer(work_minutes=0, break_minutes=0, logger=self.logger)
|
26
30
|
timer.start()
|
31
|
+
self.assertIn("INFO:Pomodoro round 1 of 1", self.log_output)
|
27
32
|
self.assertIn("INFO:Starting Pomodoro: 0 minutes of work.", self.log_output)
|
28
|
-
self.assertIn("INFO:Time for a break: 0 minutes.", self.log_output)
|
29
33
|
self.assertIn("INFO:Pomodoro session complete!", self.log_output)
|
30
34
|
timer.stop()
|
31
35
|
self.assertIn("INFO:Pomodoro stopped.", self.log_output)
|
@@ -40,6 +44,28 @@ class TestPomodoroTimer(unittest.TestCase):
|
|
40
44
|
t.join()
|
41
45
|
self.assertIn("INFO:Pomodoro stopped.", self.log_output)
|
42
46
|
|
47
|
+
def test_repetitions(self):
|
48
|
+
timer = PomodoroTimer(work_minutes=0, break_minutes=0, repetitions=3, logger=self.logger)
|
49
|
+
timer.start()
|
50
|
+
rounds = [msg for msg in self.log_output if "Pomodoro round" in msg]
|
51
|
+
self.assertEqual(len(rounds), 3)
|
52
|
+
self.assertIn("INFO:Pomodoro round 1 of 3", rounds[0])
|
53
|
+
self.assertIn("INFO:Pomodoro round 2 of 3", rounds[1])
|
54
|
+
self.assertIn("INFO:Pomodoro round 3 of 3", rounds[2])
|
55
|
+
self.assertIn("INFO:Pomodoro session complete!", self.log_output)
|
56
|
+
|
57
|
+
def test_tqdm_usage(self):
|
58
|
+
try:
|
59
|
+
from tqdm import tqdm
|
60
|
+
except ImportError:
|
61
|
+
self.skipTest("tqdm is not installed, skipping tqdm usage test.")
|
62
|
+
|
63
|
+
timer = PomodoroTimer(work_minutes=0.05, break_minutes=0.05, repetitions=2, use_tqdm=True, logger=self.logger)
|
64
|
+
timer.start()
|
65
|
+
self.assertIn("INFO:Starting Pomodoro: 0.05 minutes of work.", self.log_output)
|
66
|
+
self.assertIn("INFO:Time for a break: 0.05 minutes.", self.log_output)
|
67
|
+
self.assertIn("INFO:Pomodoro session complete!", self.log_output)
|
68
|
+
|
69
|
+
|
43
70
|
if __name__ == "__main__":
|
44
71
|
unittest.main()
|
45
|
-
|
pomcli-0.1.0/pomodoro_example.py
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
import time
|
2
|
-
import logging
|
3
|
-
|
4
|
-
class PomodoroTimer:
|
5
|
-
def __init__(self, work_minutes=25, break_minutes=5, logger=None):
|
6
|
-
self.work_minutes = work_minutes
|
7
|
-
self.break_minutes = break_minutes
|
8
|
-
self.is_running = False
|
9
|
-
self.logger = logger or logging.getLogger(__name__)
|
10
|
-
|
11
|
-
def start(self):
|
12
|
-
self.is_running = True
|
13
|
-
self.logger.info(f"Starting Pomodoro: {self.work_minutes} minutes of work.")
|
14
|
-
self._countdown(self.work_minutes * 60, "Work")
|
15
|
-
self.logger.info(f"Time for a break: {self.break_minutes} minutes.")
|
16
|
-
self._countdown(self.break_minutes * 60, "Break")
|
17
|
-
self.logger.info("Pomodoro session complete!")
|
18
|
-
self.is_running = False
|
19
|
-
|
20
|
-
def _countdown(self, seconds, label):
|
21
|
-
while seconds > 0 and self.is_running:
|
22
|
-
mins, secs = divmod(int(seconds), 60)
|
23
|
-
timeformat = f'{mins:02d}:{secs:02d}'
|
24
|
-
self.logger.debug(f'{label} Timer: {timeformat}')
|
25
|
-
time.sleep(1)
|
26
|
-
seconds -= 1
|
27
|
-
|
28
|
-
def stop(self):
|
29
|
-
self.is_running = False
|
30
|
-
self.logger.info("Pomodoro stopped.")
|
31
|
-
|
32
|
-
def main():
|
33
|
-
import argparse
|
34
|
-
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
35
|
-
parser = argparse.ArgumentParser(description="Simple Pomodoro CLI Timer")
|
36
|
-
parser.add_argument('--work', type=float, default=25, help='Work duration in minutes (default: 25)')
|
37
|
-
parser.add_argument('--break_time', type=float, default=5, help='Break duration in minutes (default: 5)')
|
38
|
-
args = parser.parse_args()
|
39
|
-
timer = PomodoroTimer(work_minutes=args.work, break_minutes=args.break_time)
|
40
|
-
timer.start()
|
41
|
-
|
42
|
-
if __name__ == "__main__":
|
43
|
-
main()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|