PomCli 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.
- pomcli-0.1.0/.idea/.gitignore +8 -0
- pomcli-0.1.0/.idea/.name +1 -0
- pomcli-0.1.0/.idea/PomCli.iml +11 -0
- pomcli-0.1.0/.idea/inspectionProfiles/profiles_settings.xml +6 -0
- pomcli-0.1.0/.idea/misc.xml +6 -0
- pomcli-0.1.0/.idea/modules.xml +8 -0
- pomcli-0.1.0/.idea/workspace.xml +86 -0
- pomcli-0.1.0/LICENSE.txt +9 -0
- pomcli-0.1.0/PKG-INFO +55 -0
- pomcli-0.1.0/README.md +33 -0
- pomcli-0.1.0/pomodoro_example.py +5 -0
- pomcli-0.1.0/pyproject.toml +64 -0
- pomcli-0.1.0/src/pomcli/__about__.py +3 -0
- pomcli-0.1.0/src/pomcli/__init__.py +2 -0
- pomcli-0.1.0/src/pomcli/pomodoro.py +43 -0
- pomcli-0.1.0/tests/__init__.py +3 -0
- pomcli-0.1.0/tests/test_pomodoro.py +45 -0
pomcli-0.1.0/.idea/.name
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
PomCli
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<module type="PYTHON_MODULE" version="4">
|
3
|
+
<component name="NewModuleRootManager">
|
4
|
+
<content url="file://$MODULE_DIR$">
|
5
|
+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
6
|
+
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
7
|
+
</content>
|
8
|
+
<orderEntry type="jdk" jdkName="Hatch (pythonproject1) [Python 3.12.7]" jdkType="Python SDK" />
|
9
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
10
|
+
</component>
|
11
|
+
</module>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project version="4">
|
3
|
+
<component name="ProjectModuleManager">
|
4
|
+
<modules>
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/PythonProject1.iml" filepath="$PROJECT_DIR$/.idea/PythonProject1.iml" />
|
6
|
+
</modules>
|
7
|
+
</component>
|
8
|
+
</project>
|
@@ -0,0 +1,86 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project version="4">
|
3
|
+
<component name="AutoImportSettings">
|
4
|
+
<option name="autoReloadType" value="SELECTIVE" />
|
5
|
+
</component>
|
6
|
+
<component name="ChangeListManager">
|
7
|
+
<list default="true" id="21804819-0ee5-4d07-9a58-0a8a692c6689" name="Changes" comment="" />
|
8
|
+
<option name="SHOW_DIALOG" value="false" />
|
9
|
+
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
10
|
+
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
11
|
+
<option name="LAST_RESOLUTION" value="IGNORE" />
|
12
|
+
</component>
|
13
|
+
<component name="ProjectColorInfo"><![CDATA[{
|
14
|
+
"associatedIndex": 1
|
15
|
+
}]]></component>
|
16
|
+
<component name="ProjectId" id="2z7o5ttqCSmO2xFVLxQDn63jJfG" />
|
17
|
+
<component name="ProjectViewState">
|
18
|
+
<option name="hideEmptyMiddlePackages" value="true" />
|
19
|
+
<option name="showLibraryContents" value="true" />
|
20
|
+
</component>
|
21
|
+
<component name="PropertiesComponent"><![CDATA[{
|
22
|
+
"keyToString": {
|
23
|
+
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
24
|
+
"Python tests.Python tests for test_pomodoro.TestPomodoroTimer.executor": "Run",
|
25
|
+
"Python.hello_example.executor": "Run",
|
26
|
+
"Python.pomodoro_example.executor": "Run",
|
27
|
+
"RunOnceActivity.ShowReadmeOnStart": "true",
|
28
|
+
"node.js.detected.package.eslint": "true",
|
29
|
+
"node.js.detected.package.tslint": "true",
|
30
|
+
"node.js.selected.package.eslint": "(autodetect)",
|
31
|
+
"node.js.selected.package.tslint": "(autodetect)",
|
32
|
+
"nodejs_package_manager_path": "npm",
|
33
|
+
"vue.rearranger.settings.migration": "true"
|
34
|
+
}
|
35
|
+
}]]></component>
|
36
|
+
<component name="RunManager">
|
37
|
+
<configuration name="Python tests for test_pomodoro.TestPomodoroTimer" type="tests" factoryName="Autodetect" temporary="true" nameIsGenerated="true">
|
38
|
+
<module name="PythonProject1" />
|
39
|
+
<option name="ENV_FILES" value="" />
|
40
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
41
|
+
<option name="PARENT_ENVS" value="true" />
|
42
|
+
<option name="SDK_HOME" value="" />
|
43
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/tests" />
|
44
|
+
<option name="IS_MODULE_SDK" value="true" />
|
45
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
46
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
47
|
+
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
48
|
+
<option name="_new_additionalArguments" value="""" />
|
49
|
+
<option name="_new_target" value=""test_pomodoro.TestPomodoroTimer"" />
|
50
|
+
<option name="_new_targetType" value=""PYTHON"" />
|
51
|
+
<method v="2" />
|
52
|
+
</configuration>
|
53
|
+
<recent_temporary>
|
54
|
+
<list>
|
55
|
+
<item itemvalue="Python tests.Python tests for test_pomodoro.TestPomodoroTimer" />
|
56
|
+
</list>
|
57
|
+
</recent_temporary>
|
58
|
+
</component>
|
59
|
+
<component name="SharedIndexes">
|
60
|
+
<attachedChunks>
|
61
|
+
<set>
|
62
|
+
<option value="bundled-js-predefined-d6986cc7102b-b26f3e71634d-JavaScript-PY-251.26094.141" />
|
63
|
+
<option value="bundled-python-sdk-9f8e2b94138c-36ea0e71a18c-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-251.26094.141" />
|
64
|
+
</set>
|
65
|
+
</attachedChunks>
|
66
|
+
</component>
|
67
|
+
<component name="TaskManager">
|
68
|
+
<task active="true" id="Default" summary="Default task">
|
69
|
+
<changelist id="21804819-0ee5-4d07-9a58-0a8a692c6689" name="Changes" comment="" />
|
70
|
+
<created>1751091293397</created>
|
71
|
+
<option name="number" value="Default" />
|
72
|
+
<option name="presentableId" value="Default" />
|
73
|
+
<updated>1751091293397</updated>
|
74
|
+
<workItem from="1751091294400" duration="2280000" />
|
75
|
+
</task>
|
76
|
+
<servers />
|
77
|
+
</component>
|
78
|
+
<component name="TypeScriptGeneratedFilesManager">
|
79
|
+
<option name="version" value="3" />
|
80
|
+
</component>
|
81
|
+
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
82
|
+
<SUITE FILE_PATH="coverage/PythonProject1$hello_example.coverage" NAME="hello_example Coverage Results" MODIFIED="1751091752281" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
83
|
+
<SUITE FILE_PATH="coverage/PythonProject1$pomodoro_example.coverage" NAME="pomodoro_example Coverage Results" MODIFIED="1751091915089" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
84
|
+
<SUITE FILE_PATH="coverage/PythonProject1$.coverage" NAME=" Coverage Results" MODIFIED="1751092017011" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
85
|
+
</component>
|
86
|
+
</project>
|
pomcli-0.1.0/LICENSE.txt
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025-present Yaniv Grosskopf <101043539+YanivGros@users.noreply.github.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
pomcli-0.1.0/PKG-INFO
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: PomCli
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A simple Pomodoro timer CLI tool.
|
5
|
+
Project-URL: Documentation, https://github.com/YanivGrosskopf/PomCli#readme
|
6
|
+
Project-URL: Issues, https://github.com/YanivGrosskopf/PomCli/issues
|
7
|
+
Project-URL: Source, https://github.com/YanivGrosskopf/PomCli
|
8
|
+
Author-email: Yaniv Grosskopf <qywoec@gmail.com>
|
9
|
+
License-Expression: MIT
|
10
|
+
License-File: LICENSE.txt
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
12
|
+
Classifier: Programming Language :: Python
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
18
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
19
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
20
|
+
Requires-Python: >=3.8
|
21
|
+
Description-Content-Type: text/markdown
|
22
|
+
|
23
|
+
# PomCli
|
24
|
+
|
25
|
+
[](https://pypi.org/project/pomcli)
|
26
|
+
[](https://pypi.org/project/pomcli)
|
27
|
+
|
28
|
+
-----
|
29
|
+
|
30
|
+
## Table of Contents
|
31
|
+
|
32
|
+
- [Installation](#installation)
|
33
|
+
- [Usage](#usage)
|
34
|
+
- [License](#license)
|
35
|
+
|
36
|
+
## Installation
|
37
|
+
|
38
|
+
```console
|
39
|
+
pip install pomcli
|
40
|
+
```
|
41
|
+
|
42
|
+
## Usage
|
43
|
+
|
44
|
+
Run the Pomodoro timer from the command line:
|
45
|
+
|
46
|
+
```console
|
47
|
+
pomcli --work 25 --break_time 5
|
48
|
+
```
|
49
|
+
|
50
|
+
- `--work`: Work duration in minutes (default: 25)
|
51
|
+
- `--break_time`: Break duration in minutes (default: 5)
|
52
|
+
|
53
|
+
## License
|
54
|
+
|
55
|
+
`PomCli` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
pomcli-0.1.0/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# PomCli
|
2
|
+
|
3
|
+
[](https://pypi.org/project/pomcli)
|
4
|
+
[](https://pypi.org/project/pomcli)
|
5
|
+
|
6
|
+
-----
|
7
|
+
|
8
|
+
## Table of Contents
|
9
|
+
|
10
|
+
- [Installation](#installation)
|
11
|
+
- [Usage](#usage)
|
12
|
+
- [License](#license)
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
```console
|
17
|
+
pip install pomcli
|
18
|
+
```
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
Run the Pomodoro timer from the command line:
|
23
|
+
|
24
|
+
```console
|
25
|
+
pomcli --work 25 --break_time 5
|
26
|
+
```
|
27
|
+
|
28
|
+
- `--work`: Work duration in minutes (default: 25)
|
29
|
+
- `--break_time`: Break duration in minutes (default: 5)
|
30
|
+
|
31
|
+
## License
|
32
|
+
|
33
|
+
`PomCli` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
@@ -0,0 +1,64 @@
|
|
1
|
+
[build-system]
|
2
|
+
requires = ["hatchling"]
|
3
|
+
build-backend = "hatchling.build"
|
4
|
+
|
5
|
+
[project]
|
6
|
+
name = "PomCli"
|
7
|
+
dynamic = ["version"]
|
8
|
+
description = 'A simple Pomodoro timer CLI tool.'
|
9
|
+
readme = "README.md"
|
10
|
+
requires-python = ">=3.8"
|
11
|
+
license = "MIT"
|
12
|
+
keywords = []
|
13
|
+
authors = [
|
14
|
+
{ name = "Yaniv Grosskopf", email = "qywoec@gmail.com" },
|
15
|
+
]
|
16
|
+
classifiers = [
|
17
|
+
"Development Status :: 4 - Beta",
|
18
|
+
"Programming Language :: Python",
|
19
|
+
"Programming Language :: Python :: 3.8",
|
20
|
+
"Programming Language :: Python :: 3.9",
|
21
|
+
"Programming Language :: Python :: 3.10",
|
22
|
+
"Programming Language :: Python :: 3.11",
|
23
|
+
"Programming Language :: Python :: 3.12",
|
24
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
25
|
+
"Programming Language :: Python :: Implementation :: PyPy",
|
26
|
+
]
|
27
|
+
dependencies = []
|
28
|
+
|
29
|
+
[project.urls]
|
30
|
+
Documentation = "https://github.com/YanivGrosskopf/PomCli#readme"
|
31
|
+
Issues = "https://github.com/YanivGrosskopf/PomCli/issues"
|
32
|
+
Source = "https://github.com/YanivGrosskopf/PomCli"
|
33
|
+
|
34
|
+
[tool.hatch.version]
|
35
|
+
path = "src/pomcli/__about__.py"
|
36
|
+
|
37
|
+
[tool.hatch.envs.types]
|
38
|
+
extra-dependencies = [
|
39
|
+
"mypy>=1.0.0",
|
40
|
+
]
|
41
|
+
[tool.hatch.envs.types.scripts]
|
42
|
+
check = "mypy --install-types --non-interactive {args:src/pomcli tests}"
|
43
|
+
|
44
|
+
[tool.coverage.run]
|
45
|
+
source_pkgs = ["pomcli", "tests"]
|
46
|
+
branch = true
|
47
|
+
parallel = true
|
48
|
+
omit = [
|
49
|
+
"src/pomcli/__about__.py",
|
50
|
+
]
|
51
|
+
|
52
|
+
[tool.coverage.paths]
|
53
|
+
pomcli = ["src/pomcli", "*/pomcli/src/pomcli"]
|
54
|
+
tests = ["tests", "*/pythonproject1/tests"]
|
55
|
+
|
56
|
+
[tool.coverage.report]
|
57
|
+
exclude_lines = [
|
58
|
+
"no cov",
|
59
|
+
"if __name__ == .__main__.:",
|
60
|
+
"if TYPE_CHECKING:",
|
61
|
+
]
|
62
|
+
|
63
|
+
[project.scripts]
|
64
|
+
pomcli = "pomcli.pomodoro:main"
|
@@ -0,0 +1,43 @@
|
|
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()
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import unittest
|
2
|
+
import time
|
3
|
+
import logging
|
4
|
+
from pomcli.pomodoro import PomodoroTimer
|
5
|
+
|
6
|
+
class TestPomodoroTimer(unittest.TestCase):
|
7
|
+
def setUp(self):
|
8
|
+
self.logger = logging.getLogger("pomodoro_test")
|
9
|
+
self.logger.setLevel(logging.DEBUG)
|
10
|
+
self.log_output = []
|
11
|
+
handler = logging.StreamHandler(self._LogCapture(self.log_output))
|
12
|
+
handler.setFormatter(logging.Formatter('%(levelname)s:%(message)s'))
|
13
|
+
self.logger.handlers = [handler]
|
14
|
+
|
15
|
+
class _LogCapture:
|
16
|
+
def __init__(self, output_list):
|
17
|
+
self.output_list = output_list
|
18
|
+
def write(self, msg):
|
19
|
+
if msg.strip():
|
20
|
+
self.output_list.append(msg.strip())
|
21
|
+
def flush(self):
|
22
|
+
pass
|
23
|
+
|
24
|
+
def test_start_and_stop(self):
|
25
|
+
timer = PomodoroTimer(work_minutes=0, break_minutes=0, logger=self.logger)
|
26
|
+
timer.start()
|
27
|
+
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
|
+
self.assertIn("INFO:Pomodoro session complete!", self.log_output)
|
30
|
+
timer.stop()
|
31
|
+
self.assertIn("INFO:Pomodoro stopped.", self.log_output)
|
32
|
+
|
33
|
+
def test_stop_midway(self):
|
34
|
+
timer = PomodoroTimer(work_minutes=0.001, break_minutes=0, logger=self.logger)
|
35
|
+
import threading
|
36
|
+
t = threading.Thread(target=timer.start)
|
37
|
+
t.start()
|
38
|
+
time.sleep(0.5)
|
39
|
+
timer.stop()
|
40
|
+
t.join()
|
41
|
+
self.assertIn("INFO:Pomodoro stopped.", self.log_output)
|
42
|
+
|
43
|
+
if __name__ == "__main__":
|
44
|
+
unittest.main()
|
45
|
+
|