Skip to content

Commit 5e31ddb

Browse files
Merge pull request #64 from python-thread/feature/verbosity-setting
Feature: verbosity setting
2 parents 669bc5b + 0e87ae8 commit 5e31ddb

File tree

4 files changed

+216
-5
lines changed

4 files changed

+216
-5
lines changed

src/thread/thread.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ def wrapper(
137137

138138
except SystemExit:
139139
self.status = 'Killed'
140-
print('KILLED ident: %s' % self.ident)
140+
if Settings.VERBOSITY > 'quiet':
141+
print('KILLED ident: %s' % self.ident)
141142
return
142143

143144
return wrapper
@@ -532,8 +533,9 @@ def start(self) -> None:
532533
# Handle abrupt exit
533534
def service_shutdown(signum, frame):
534535
if Settings.GRACEFUL_EXIT_ENABLED:
535-
print('\nCaught signal %d' % signum)
536-
print('Gracefully killing active threads')
536+
if Settings.VERBOSITY > 'quiet':
537+
print('\nCaught signal %d' % signum)
538+
print('Gracefully killing active threads')
537539

538540
for thread in Threads:
539541
if isinstance(thread, Thread):
@@ -545,7 +547,8 @@ def service_shutdown(signum, frame):
545547
):
546548
pass
547549
except Exception:
548-
print('Failed to kill ident: %d' % thread.ident or 0)
550+
if Settings.VERBOSITY > 'quiet':
551+
print('Failed to kill ident: %d' % thread.ident or 0)
549552
sys.exit(0)
550553

551554

src/thread/utils/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
from .config import Settings
66

77
from . import (
8+
config,
89
algorithm,
910
)

src/thread/utils/config.py

+142-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,155 @@
1+
from typing import Any, Callable, Literal, Union
2+
3+
_Verbosity_Num = Literal[0, 1, 2]
4+
_Verbosity_Enum = Literal['quiet', 'normal', 'verbose']
5+
VerbosityLevel = Union[_Verbosity_Num, _Verbosity_Enum]
6+
VerbosityMapping: dict[_Verbosity_Enum, _Verbosity_Num] = {
7+
'quiet': 0,
8+
'normal': 1,
9+
'verbose': 2,
10+
}
11+
12+
13+
class Verbosity:
14+
"""
15+
# Verbosity
16+
17+
Can be instantiated with and compared against a number or an enum.
18+
"""
19+
20+
level_number: _Verbosity_Num
21+
level_string: _Verbosity_Enum
22+
23+
def __init__(self, level: VerbosityLevel) -> None:
24+
"""
25+
Initializes the verbosity object.
26+
27+
Parameters
28+
----------
29+
:param level: The level of verbosity. Can be a number or an enum.
30+
31+
Raises
32+
------
33+
ValueError: If the level is not a valid number or enum.
34+
ValueError: If the level is not of a valid type.
35+
"""
36+
if isinstance(level, str):
37+
if level not in VerbosityMapping.keys():
38+
raise ValueError('Invalid verbosity level')
39+
self.level_string = level
40+
self.level_number = VerbosityMapping[level]
41+
elif isinstance(level, int):
42+
if level not in VerbosityMapping.values():
43+
raise ValueError('Invalid verbosity level')
44+
self.level_number = level
45+
self.level_string = list(VerbosityMapping.keys())[level]
46+
else:
47+
raise ValueError(f'{type(level)} is not a valid verbosity level')
48+
49+
def __str__(self) -> str:
50+
return self.level_string
51+
52+
def __eq__(self, other: Any) -> bool:
53+
try:
54+
return self._compare(other, lambda a, b: a == b)
55+
except ValueError:
56+
return False
57+
58+
def __lt__(self, other: Any) -> bool:
59+
return self._compare(other, lambda a, b: a < b)
60+
61+
def __le__(self, other: Any) -> bool:
62+
return self._compare(other, lambda a, b: a <= b)
63+
64+
def __gt__(self, other: Any) -> bool:
65+
return self._compare(other, lambda a, b: a > b)
66+
67+
def __ge__(self, other: Any) -> bool:
68+
return self._compare(other, lambda a, b: a >= b)
69+
70+
def __ne__(self, other: Any) -> bool:
71+
return not self.__eq__(other)
72+
73+
def _compare(
74+
self, other: Any, operator: Callable[[VerbosityLevel, Any], bool]
75+
) -> bool:
76+
if isinstance(other, Verbosity):
77+
return operator(self.level_number, other.level_number)
78+
if isinstance(other, int):
79+
return operator(self.level_number, other)
80+
if isinstance(other, str):
81+
if Verbosity.is_valid_level(other):
82+
return operator(self.level_number, VerbosityMapping[other])
83+
return operator(self.level_string, other)
84+
raise ValueError('Cannot compare Verbosity with other types')
85+
86+
@staticmethod
87+
def is_valid_level(level: Any) -> bool:
88+
"""
89+
Determines whether the given level is a valid verbosity level.
90+
91+
Parameters
92+
----------
93+
:param level: The level to check.
94+
95+
Returns
96+
-------
97+
:returns: True if the level is a valid verbosity level, False otherwise.
98+
"""
99+
if isinstance(level, int):
100+
return level in VerbosityMapping.values()
101+
if isinstance(level, str):
102+
return level in VerbosityMapping.keys()
103+
return False
104+
105+
1106
class Settings:
2107
"""
3108
# Settings
4109
`Non Instantiable`
5110
"""
6111

112+
# Verbosity
113+
VerbosityLevel = VerbosityLevel
114+
VERBOSITY: Verbosity = Verbosity(1)
115+
116+
# Graceful Exit
7117
GRACEFUL_EXIT_ENABLED: bool = True
8118

9119
def __init__(self):
10120
raise NotImplementedError('This class is not instantiable')
11121

12122
@staticmethod
13-
def set_graceful_exit(enabled: bool = True):
123+
def set_graceful_exit(enabled: bool = True) -> None:
124+
"""
125+
Enables/Disables graceful exiting.
126+
127+
Parameters
128+
----------
129+
:param enabled: True to enable graceful exit, False otherwise.
130+
131+
Returns
132+
-------
133+
:returns: None
134+
"""
14135
Settings.GRACEFUL_EXIT_ENABLED = enabled
136+
137+
@staticmethod
138+
def set_verbosity(verbosity: VerbosityLevel = 'normal') -> None:
139+
"""
140+
Sets the verbosity level.
141+
142+
Parameters
143+
----------
144+
:param verbosity: The level of verbosity. Can be a number or an enum.
145+
146+
Returns
147+
-------
148+
:returns: None
149+
150+
Raises
151+
------
152+
ValueError: If the level is not a valid number or enum.
153+
ValueError: If the level is not of a valid type.
154+
"""
155+
Settings.VERBOSITY = Verbosity(verbosity)

tests/test_verbosity.py

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import pytest
2+
from src.thread.utils.config import Verbosity
3+
4+
5+
# >>>>>>>>>> General Use <<<<<<<<<< #
6+
def test_eqTrue():
7+
assert Verbosity(0) == 0
8+
assert Verbosity(0) == 'quiet'
9+
assert Verbosity(1) == 'normal'
10+
assert Verbosity(1) == Verbosity(1)
11+
12+
13+
def test_neTrue():
14+
assert Verbosity(0) != 1
15+
assert Verbosity(0) != 'normal'
16+
assert Verbosity(1) != 'quiet'
17+
assert Verbosity(1) != Verbosity(0)
18+
19+
20+
def test_ltTrue():
21+
assert Verbosity(0) < 1
22+
assert Verbosity(0) < 'normal'
23+
assert Verbosity(1) < 'verbose'
24+
assert Verbosity(1) < Verbosity(2)
25+
26+
27+
def test_leTrue():
28+
assert Verbosity(0) <= 1
29+
assert Verbosity(0) <= 'normal'
30+
assert Verbosity(1) <= 'verbose'
31+
assert Verbosity(1) <= Verbosity(2)
32+
33+
34+
def test_gtTrue():
35+
assert Verbosity(1) > 0
36+
assert Verbosity(1) > 'quiet'
37+
assert Verbosity(2) > 'normal'
38+
assert Verbosity(2) > Verbosity(1)
39+
40+
41+
def test_geTrue():
42+
assert Verbosity(1) >= 0
43+
assert Verbosity(1) >= 'quiet'
44+
assert Verbosity(2) >= 'normal'
45+
assert Verbosity(2) >= Verbosity(1)
46+
47+
48+
# >>>>>>>>>> Raising <<<<<<<<<< #
49+
def test_ltRaise():
50+
with pytest.raises(ValueError):
51+
Verbosity(0) < Exception()
52+
53+
54+
def test_leRaise():
55+
with pytest.raises(ValueError):
56+
Verbosity(0) <= Exception()
57+
58+
59+
def test_gtRaise():
60+
with pytest.raises(ValueError):
61+
Verbosity(1) > Exception()
62+
63+
64+
def test_geRaise():
65+
with pytest.raises(ValueError):
66+
Verbosity(1) >= Exception()

0 commit comments

Comments
 (0)