TheSandmanAJM 0.1__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.
- thesandmanajm-0.1/LICENSE.txt +17 -0
- thesandmanajm-0.1/PKG-INFO +34 -0
- thesandmanajm-0.1/README.md +5 -0
- thesandmanajm-0.1/TheSandmanAJM/__init__.py +2 -0
- thesandmanajm-0.1/TheSandmanAJM/_version.py +1 -0
- thesandmanajm-0.1/TheSandmanAJM/the_sandman.py +119 -0
- thesandmanajm-0.1/TheSandmanAJM.egg-info/PKG-INFO +34 -0
- thesandmanajm-0.1/TheSandmanAJM.egg-info/SOURCES.txt +14 -0
- thesandmanajm-0.1/TheSandmanAJM.egg-info/dependency_links.txt +1 -0
- thesandmanajm-0.1/TheSandmanAJM.egg-info/requires.txt +1 -0
- thesandmanajm-0.1/TheSandmanAJM.egg-info/top_level.txt +1 -0
- thesandmanajm-0.1/pyproject.toml +3 -0
- thesandmanajm-0.1/setup.cfg +7 -0
- thesandmanajm-0.1/setup.py +45 -0
- thesandmanajm-0.1/tests/test_the_sandman.py +104 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
Copyright (c) 2018 Andrew McSparron
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
The above copyright notice and this permission notice shall be included in all
|
|
10
|
+
copies or substantial portions of the Software.
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
12
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
13
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
14
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
15
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
16
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
17
|
+
SOFTWARE.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: TheSandmanAJM
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: A utility class to facilitate and log time delays with custom sleep durations.
|
|
5
|
+
Home-page: https://github.com/amcsparron2793-Water/TheSandmanAJM
|
|
6
|
+
Download-URL: https://github.com/amcsparron2793-Water/TheSandmanAJM/archive/refs/tags/0.1.tar.gz
|
|
7
|
+
Author: Amcsparron
|
|
8
|
+
Author-email: amcsparron@albanyny.gov
|
|
9
|
+
License: MIT License
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE.txt
|
|
17
|
+
Requires-Dist: tqdm
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: author-email
|
|
20
|
+
Dynamic: classifier
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: download-url
|
|
24
|
+
Dynamic: home-page
|
|
25
|
+
Dynamic: license
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: summary
|
|
29
|
+
|
|
30
|
+
# <u>TheSandmanAJM</u>
|
|
31
|
+
### <i>A utility class to facilitate and log time delays with custom sleep durations.</i>
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
A utility class to facilitate and log time delays with custom sleep durations.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.1'
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from logging import getLogger, Logger
|
|
3
|
+
from time import sleep
|
|
4
|
+
|
|
5
|
+
from tqdm import tqdm
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TheSandman:
|
|
9
|
+
"""
|
|
10
|
+
A utility class to facilitate and log time delays with custom sleep durations.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
DEFAULT_SLEEP_TIME_SECONDS (int): Default sleep duration in seconds if not specified.
|
|
14
|
+
sleep_time (int): Actual sleep time (in seconds) to be used by the instance.
|
|
15
|
+
sleep_time_string (str): Human-readable string representing the current sleep duration.
|
|
16
|
+
logger (Logger): Logging instance for logging messages related to sleep operations.
|
|
17
|
+
|
|
18
|
+
Methods:
|
|
19
|
+
sleep_time_string:
|
|
20
|
+
Property getter and setter for updating the human-readable sleep time string.
|
|
21
|
+
|
|
22
|
+
sleep_round():
|
|
23
|
+
Splits the sleep duration into two equal parts. It logs and prints messages depicting the current sleep state, including the remaining time, and sleeps for the given durations.
|
|
24
|
+
"""
|
|
25
|
+
# default 600 secs = 10 minutes
|
|
26
|
+
DEFAULT_SLEEP_TIME_SECONDS = 600
|
|
27
|
+
DEFAULT_USE_VISUAL_SLEEP = True
|
|
28
|
+
DEFAULT_SILENT_SLEEP = False
|
|
29
|
+
|
|
30
|
+
def __init__(self, sleep_time_seconds=None, **kwargs):
|
|
31
|
+
self.sleep_time_start = None
|
|
32
|
+
self.use_visual_sleep = kwargs.get('use_visual_sleep', self.__class__.DEFAULT_USE_VISUAL_SLEEP)
|
|
33
|
+
self.silent_sleep = kwargs.get('silent_sleep', self.__class__.DEFAULT_SILENT_SLEEP)
|
|
34
|
+
|
|
35
|
+
self.sleep_time: int = sleep_time_seconds or self.__class__.DEFAULT_SLEEP_TIME_SECONDS
|
|
36
|
+
self._is_time_remaining = False
|
|
37
|
+
self._sleep_time_string = None
|
|
38
|
+
|
|
39
|
+
self.logger: Logger = kwargs.get('logger', getLogger(__name__))
|
|
40
|
+
self.sleep_time_string = self.sleep_time
|
|
41
|
+
self.logger.info(f'TheSandman initialized - sleep time set as {self.sleep_time_string}')
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def sleep_time_string(self):
|
|
45
|
+
return self._sleep_time_string
|
|
46
|
+
|
|
47
|
+
@sleep_time_string.setter
|
|
48
|
+
def sleep_time_string(self, value: int):
|
|
49
|
+
if self._is_time_remaining:
|
|
50
|
+
more = 'more'
|
|
51
|
+
else:
|
|
52
|
+
more = ''
|
|
53
|
+
if value >= 60:
|
|
54
|
+
self._sleep_time_string = f'sleeping for {value // 60} {more} minute(s)'
|
|
55
|
+
else:
|
|
56
|
+
self._sleep_time_string = f'sleeping for {value} {more} second(s)'
|
|
57
|
+
|
|
58
|
+
str_parts = [self._sleep_time_string, f'(started at {self.sleep_time_start})']
|
|
59
|
+
self._sleep_time_string = ' '.join(str_parts)
|
|
60
|
+
|
|
61
|
+
def _setup_sleep_in_rounds(self, **kwargs):
|
|
62
|
+
self.sleep_time_start = datetime.now().strftime('%m/%d/%Y %H:%M')
|
|
63
|
+
if self.use_visual_sleep:
|
|
64
|
+
kwargs['print_msg'] = False
|
|
65
|
+
elif self.silent_sleep:
|
|
66
|
+
kwargs['print_msg'] = False
|
|
67
|
+
else:
|
|
68
|
+
kwargs['print_msg'] = True
|
|
69
|
+
self._is_time_remaining = False
|
|
70
|
+
return kwargs
|
|
71
|
+
|
|
72
|
+
def _sleep_round(self, curr_sleep_round: int, total_rounds: int, print_msg: bool, **kwargs):
|
|
73
|
+
if curr_sleep_round == total_rounds - 1:
|
|
74
|
+
self._is_time_remaining = True
|
|
75
|
+
sleep_time_seconds = (self.sleep_time // total_rounds)
|
|
76
|
+
self.sleep(sleep_time_seconds, print_msg=print_msg, **kwargs)
|
|
77
|
+
|
|
78
|
+
def sleep_in_rounds(self, rounds=2, **kwargs):
|
|
79
|
+
kwargs = self._setup_sleep_in_rounds(**kwargs)
|
|
80
|
+
|
|
81
|
+
for sleep_round in range(rounds):
|
|
82
|
+
self._sleep_round(sleep_round, rounds, **kwargs)
|
|
83
|
+
|
|
84
|
+
def visual_sleep(self, sleep_time_seconds: int) -> None:
|
|
85
|
+
try:
|
|
86
|
+
for _ in tqdm(range(sleep_time_seconds),
|
|
87
|
+
desc=f"{self.sleep_time_string}",
|
|
88
|
+
unit="second"):
|
|
89
|
+
sleep(1)
|
|
90
|
+
except Exception as e:
|
|
91
|
+
if e.__class__.__name__ != 'KeyboardInterrupt':
|
|
92
|
+
self.logger.error(f"visual_sleep failed: {e}, turning off visual sleep and trying again...")
|
|
93
|
+
self.use_visual_sleep = False
|
|
94
|
+
self.sleep(sleep_time_seconds)
|
|
95
|
+
else:
|
|
96
|
+
raise
|
|
97
|
+
|
|
98
|
+
def sleep(self, sleep_time_seconds: int, **kwargs):
|
|
99
|
+
"""
|
|
100
|
+
:param sleep_time_seconds: The number of seconds the function should pause execution.
|
|
101
|
+
:type sleep_time_seconds: int
|
|
102
|
+
:return: None
|
|
103
|
+
:rtype: None
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
self.sleep_time_string = self.sleep_time if not self._is_time_remaining else sleep_time_seconds
|
|
107
|
+
self.logger.info(self.sleep_time_string, **kwargs)
|
|
108
|
+
|
|
109
|
+
if self.use_visual_sleep:
|
|
110
|
+
self.visual_sleep(sleep_time_seconds)
|
|
111
|
+
else:
|
|
112
|
+
if not self.silent_sleep:
|
|
113
|
+
print(self.sleep_time_string)
|
|
114
|
+
sleep(sleep_time_seconds)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == '__main__':
|
|
118
|
+
ts = TheSandman(sleep_time_seconds=30)
|
|
119
|
+
ts.sleep_in_rounds(rounds=3)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: TheSandmanAJM
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: A utility class to facilitate and log time delays with custom sleep durations.
|
|
5
|
+
Home-page: https://github.com/amcsparron2793-Water/TheSandmanAJM
|
|
6
|
+
Download-URL: https://github.com/amcsparron2793-Water/TheSandmanAJM/archive/refs/tags/0.1.tar.gz
|
|
7
|
+
Author: Amcsparron
|
|
8
|
+
Author-email: amcsparron@albanyny.gov
|
|
9
|
+
License: MIT License
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE.txt
|
|
17
|
+
Requires-Dist: tqdm
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: author-email
|
|
20
|
+
Dynamic: classifier
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: download-url
|
|
24
|
+
Dynamic: home-page
|
|
25
|
+
Dynamic: license
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: summary
|
|
29
|
+
|
|
30
|
+
# <u>TheSandmanAJM</u>
|
|
31
|
+
### <i>A utility class to facilitate and log time delays with custom sleep durations.</i>
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
A utility class to facilitate and log time delays with custom sleep durations.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.cfg
|
|
5
|
+
setup.py
|
|
6
|
+
TheSandmanAJM/__init__.py
|
|
7
|
+
TheSandmanAJM/_version.py
|
|
8
|
+
TheSandmanAJM/the_sandman.py
|
|
9
|
+
TheSandmanAJM.egg-info/PKG-INFO
|
|
10
|
+
TheSandmanAJM.egg-info/SOURCES.txt
|
|
11
|
+
TheSandmanAJM.egg-info/dependency_links.txt
|
|
12
|
+
TheSandmanAJM.egg-info/requires.txt
|
|
13
|
+
TheSandmanAJM.egg-info/top_level.txt
|
|
14
|
+
tests/test_the_sandman.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tqdm
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
TheSandmanAJM
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
project_name = 'TheSandmanAJM'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_long_description():
|
|
9
|
+
this_dir = Path(__file__).parent
|
|
10
|
+
readme_path = this_dir / "README.md"
|
|
11
|
+
if readme_path.is_file():
|
|
12
|
+
long_description = (this_dir / "README.md").read_text()
|
|
13
|
+
else:
|
|
14
|
+
long_description = 'A utility class to facilitate and log time delays with custom sleep durations.'
|
|
15
|
+
return long_description
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_property(prop, project):
|
|
19
|
+
result = re.search(r'{}\s*=\s*[\'"]([^\'"]*)[\'"]'.format(prop), open(project + '/_version.py').read())
|
|
20
|
+
return result.group(1)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
setup(
|
|
24
|
+
name=project_name,
|
|
25
|
+
version=get_property('__version__', project_name),
|
|
26
|
+
packages=['TheSandmanAJM'],
|
|
27
|
+
url='https://github.com/amcsparron2793-Water/TheSandmanAJM',
|
|
28
|
+
download_url=f'https://github.com/amcsparron2793-Water/TheSandmanAJM/archive/refs/tags/{get_property("__version__", project_name)}.tar.gz',
|
|
29
|
+
keywords=[],
|
|
30
|
+
install_requires=['tqdm'],
|
|
31
|
+
license='MIT License',
|
|
32
|
+
author='Amcsparron',
|
|
33
|
+
author_email='amcsparron@albanyny.gov',
|
|
34
|
+
description='A utility class to facilitate and log time delays with custom sleep durations.',
|
|
35
|
+
long_description=get_long_description(),
|
|
36
|
+
long_description_content_type='text/markdown',
|
|
37
|
+
# this is for pypi categories etc
|
|
38
|
+
classifiers=[
|
|
39
|
+
'Development Status :: 3 - Alpha', # Chose either "3 - Alpha", "4 - Beta" or "5 - Production/Stable" as the current state of your package
|
|
40
|
+
'Intended Audience :: Developers', # Define that your audience are developers
|
|
41
|
+
'Topic :: Software Development :: Build Tools',
|
|
42
|
+
'License :: OSI Approved :: MIT License', # Again, pick a license
|
|
43
|
+
'Programming Language :: Python :: 3', # Specify which python versions that you want to support
|
|
44
|
+
]
|
|
45
|
+
)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
from TheSandmanAJM.the_sandman import TheSandman
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@pytest.fixture
|
|
7
|
+
def mock_logger():
|
|
8
|
+
return MagicMock()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def sandman(mock_logger):
|
|
13
|
+
return TheSandman(sleep_time_seconds=10, logger=mock_logger)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_initialization_defaults():
|
|
17
|
+
ts = TheSandman()
|
|
18
|
+
assert ts.sleep_time == 600
|
|
19
|
+
assert ts.use_visual_sleep is True
|
|
20
|
+
assert ts.silent_sleep is False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_initialization_custom():
|
|
24
|
+
ts = TheSandman(sleep_time_seconds=30, use_visual_sleep=False, silent_sleep=True)
|
|
25
|
+
assert ts.sleep_time == 30
|
|
26
|
+
assert ts.use_visual_sleep is False
|
|
27
|
+
assert ts.silent_sleep is True
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_sleep_time_string_seconds(sandman):
|
|
31
|
+
sandman.sleep_time_start = "2026-08-23 14:30"
|
|
32
|
+
sandman.sleep_time_string = 45
|
|
33
|
+
assert "sleeping for 45 second(s)" in sandman.sleep_time_string
|
|
34
|
+
assert "(started at 2026-08-23 14:30)" in sandman.sleep_time_string
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_sleep_time_string_minutes(sandman):
|
|
38
|
+
sandman.sleep_time_start = "2026-08-23 14:30"
|
|
39
|
+
sandman.sleep_time_string = 125
|
|
40
|
+
assert "sleeping for 2 minute(s)" in sandman.sleep_time_string
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_sleep_time_string_with_remaining(sandman):
|
|
44
|
+
sandman.sleep_time_start = "2026-08-23 14:30"
|
|
45
|
+
sandman._is_time_remaining = True
|
|
46
|
+
sandman.sleep_time_string = 30
|
|
47
|
+
assert "sleeping for 30 more second(s)" in sandman.sleep_time_string
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_setup_sleep_in_rounds(sandman):
|
|
51
|
+
kwargs = sandman._setup_sleep_in_rounds(extra="data")
|
|
52
|
+
assert sandman.sleep_time_start is not None
|
|
53
|
+
assert sandman._is_time_remaining is False
|
|
54
|
+
assert kwargs['extra'] == "data"
|
|
55
|
+
# Since use_visual_sleep is True by default, print_msg should be False
|
|
56
|
+
assert kwargs['print_msg'] is False
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@patch('TheSandmanAJM.the_sandman.sleep')
|
|
60
|
+
@patch('builtins.print')
|
|
61
|
+
def test_sleep_non_visual(mock_print, mock_sleep, sandman, mock_logger):
|
|
62
|
+
sandman.use_visual_sleep = False
|
|
63
|
+
sandman.silent_sleep = False
|
|
64
|
+
sandman.sleep(5)
|
|
65
|
+
mock_sleep.assert_called_once_with(5)
|
|
66
|
+
mock_print.assert_called_once()
|
|
67
|
+
mock_logger.info.assert_called()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@patch('TheSandmanAJM.the_sandman.TheSandman.visual_sleep')
|
|
71
|
+
def test_sleep_visual_calls_visual_sleep(mock_visual_sleep, sandman):
|
|
72
|
+
sandman.use_visual_sleep = True
|
|
73
|
+
sandman.sleep(5)
|
|
74
|
+
mock_visual_sleep.assert_called_once_with(5)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@patch('TheSandmanAJM.the_sandman.tqdm')
|
|
78
|
+
@patch('TheSandmanAJM.the_sandman.sleep')
|
|
79
|
+
def test_visual_sleep(mock_sleep, mock_tqdm, sandman):
|
|
80
|
+
# Mock tqdm to return a mock range
|
|
81
|
+
mock_tqdm.return_value = range(5)
|
|
82
|
+
sandman.visual_sleep(5)
|
|
83
|
+
assert mock_sleep.call_count == 5
|
|
84
|
+
mock_tqdm.assert_called_once()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@patch('TheSandmanAJM.the_sandman.TheSandman.sleep')
|
|
88
|
+
def test_sleep_in_rounds(mock_ts_sleep, sandman):
|
|
89
|
+
sandman.sleep_time = 30
|
|
90
|
+
sandman.sleep_in_rounds(rounds=3)
|
|
91
|
+
assert mock_ts_sleep.call_count == 3
|
|
92
|
+
# 30 // 3 = 10
|
|
93
|
+
mock_ts_sleep.assert_called_with(10, print_msg=False)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@patch('TheSandmanAJM.the_sandman.tqdm')
|
|
97
|
+
@patch('TheSandmanAJM.the_sandman.TheSandman.sleep')
|
|
98
|
+
def test_visual_sleep_exception_fallback(mock_ts_sleep, mock_tqdm, sandman, mock_logger):
|
|
99
|
+
mock_tqdm.side_effect = Exception("tqdm error")
|
|
100
|
+
sandman.use_visual_sleep = True
|
|
101
|
+
sandman.visual_sleep(5)
|
|
102
|
+
assert sandman.use_visual_sleep is False
|
|
103
|
+
mock_ts_sleep.assert_called_once_with(5)
|
|
104
|
+
mock_logger.error.assert_called()
|