From 6f4157f8207c4ed6ccc4a90f3bd9201a90718a96 Mon Sep 17 00:00:00 2001 From: AlexNg Date: Mon, 11 Mar 2024 16:54:59 +0800 Subject: [PATCH 01/10] feat: Adding verbosity setting --- src/thread/utils/config.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/thread/utils/config.py b/src/thread/utils/config.py index f9108c9..ac7b9a4 100644 --- a/src/thread/utils/config.py +++ b/src/thread/utils/config.py @@ -4,6 +4,7 @@ class Settings: `Non Instantiable` """ + VERBOSITY: bool = True GRACEFUL_EXIT_ENABLED: bool = True def __init__(self): @@ -12,3 +13,7 @@ def __init__(self): @staticmethod def set_graceful_exit(enabled: bool = True): Settings.GRACEFUL_EXIT_ENABLED = enabled + + @staticmethod + def set_verbosity(verbosity: bool = True): + Settings.VERBOSITY = verbosity From baf4f910386ca982ab85272212843d8fd30c22ae Mon Sep 17 00:00:00 2001 From: AlexNg Date: Mon, 11 Mar 2024 23:57:33 +0800 Subject: [PATCH 02/10] style: Code formatting --- src/thread/utils/config.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/thread/utils/config.py b/src/thread/utils/config.py index 5f817db..5cecd02 100644 --- a/src/thread/utils/config.py +++ b/src/thread/utils/config.py @@ -4,16 +4,16 @@ class Settings: `Non Instantiable` """ - VERBOSITY: bool = True - GRACEFUL_EXIT_ENABLED: bool = True + VERBOSITY: bool = True + GRACEFUL_EXIT_ENABLED: bool = True def __init__(self): raise NotImplementedError('This class is not instantiable') - @staticmethod - def set_graceful_exit(enabled: bool = True): - Settings.GRACEFUL_EXIT_ENABLED = enabled + @staticmethod + def set_graceful_exit(enabled: bool = True): + Settings.GRACEFUL_EXIT_ENABLED = enabled - @staticmethod - def set_verbosity(verbosity: bool = True): - Settings.VERBOSITY = verbosity + @staticmethod + def set_verbosity(verbosity: bool = True): + Settings.VERBOSITY = verbosity From 3468335b9e73ee303ff0c3102199441cc40d91d5 Mon Sep 17 00:00:00 2001 From: AlexNg Date: Tue, 12 Mar 2024 13:11:23 +0800 Subject: [PATCH 03/10] feat: Export config --- src/thread/utils/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/thread/utils/__init__.py b/src/thread/utils/__init__.py index 030ef71..76866a6 100644 --- a/src/thread/utils/__init__.py +++ b/src/thread/utils/__init__.py @@ -5,5 +5,6 @@ from .config import Settings from . import ( + config, algorithm, ) From c1bcf387276bbe99a35554c0263ec818042485b9 Mon Sep 17 00:00:00 2001 From: AlexNg Date: Tue, 12 Mar 2024 13:12:42 +0800 Subject: [PATCH 04/10] feat: Add verbosity levels --- src/thread/utils/config.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/thread/utils/config.py b/src/thread/utils/config.py index 5cecd02..4932362 100644 --- a/src/thread/utils/config.py +++ b/src/thread/utils/config.py @@ -1,3 +1,16 @@ +from typing import Any, Literal, Union, Callable + + +_Verbosity_Num = Literal[0, 1, 2] +_Verbosity_Enum = Literal['quiet', 'normal', 'verbose'] +VerbosityLevel = Union[_Verbosity_Num, _Verbosity_Enum] +VerbosityMapping: dict[_Verbosity_Enum, _Verbosity_Num] = { + 'quiet': 0, + 'normal': 1, + 'verbose': 2, +} + + class Settings: """ # Settings From dc4fca2df7533d64e35f4385d5990dbaf4ede6f5 Mon Sep 17 00:00:00 2001 From: AlexNg Date: Tue, 12 Mar 2024 13:14:01 +0800 Subject: [PATCH 05/10] feat: Add verbosity class --- src/thread/utils/config.py | 88 +++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/thread/utils/config.py b/src/thread/utils/config.py index 4932362..70c9c08 100644 --- a/src/thread/utils/config.py +++ b/src/thread/utils/config.py @@ -11,13 +11,99 @@ } +class Verbosity: + """ + # Verbosity + + Can be instantiated with and compared against a number or an enum. + """ + + level_number: _Verbosity_Num + level_string: _Verbosity_Enum + + def __init__(self, level: VerbosityLevel) -> None: + """ + Initializes the verbosity object. + + Parameters + ---------- + :param level: The level of verbosity. Can be a number or an enum. + + Raises + ------ + ValueError: If the level is not a valid number or enum. + ValueError: If the level is not of a valid type. + """ + if isinstance(level, str): + if level not in ['quiet', 'normal', 'verbose']: + raise ValueError('Invalid verbosity level') + self.level_string = level + self.level_number = VerbosityMapping[level] + elif isinstance(level, int): + if level not in [0, 1, 2]: + raise ValueError('Invalid verbosity level') + self.level_number = level + self.level_string = list(VerbosityMapping.keys())[level] + else: + raise ValueError(f'{type(level)} is not a valid verbosity level') + + def __str__(self) -> str: + return self.level_string + + def __eq__(self, other: Any) -> bool: + try: + return self._compare(other, lambda a, b: a == b) + except ValueError: + return False + + def __lt__(self, other: Any) -> bool: + return self._compare(other, lambda a, b: a < b) + + def __le__(self, other: Any) -> bool: + return self._compare(other, lambda a, b: a <= b) + + def __gt__(self, other: Any) -> bool: + return self._compare(other, lambda a, b: a > b) + + def __ge__(self, other: Any) -> bool: + return self._compare(other, lambda a, b: a >= b) + + def __ne__(self, other: Any) -> bool: + return not self.__eq__(other) + + def _compare( + self, other: Any, operator: Callable[[VerbosityLevel, Any], bool] + ) -> bool: + if isinstance(other, Verbosity): + return operator(self.level_number, other.level_number) + if isinstance(other, int): + return operator(self.level_number, other) + if isinstance(other, str): + if Verbosity.is_valid_level(other): + return operator(self.level_number, VerbosityMapping[other]) + return operator(self.level_string, other) + raise ValueError('Cannot compare Verbosity with other types') + + @staticmethod + def is_valid_level(level: Any) -> bool: + if isinstance(level, int): + return level in VerbosityMapping.values() + if isinstance(level, str): + return level in VerbosityMapping.keys() + return False + + class Settings: """ # Settings `Non Instantiable` """ - VERBOSITY: bool = True + # Verbosity + VerbosityLevel = VerbosityLevel + VERBOSITY: Verbosity = Verbosity(1) + + # Graceful Exit GRACEFUL_EXIT_ENABLED: bool = True def __init__(self): From e83a31d580dd787652fea3a9f0af4b2694848143 Mon Sep 17 00:00:00 2001 From: AlexNg Date: Tue, 12 Mar 2024 13:16:16 +0800 Subject: [PATCH 06/10] refactor: Utilise mapping --- src/thread/utils/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/thread/utils/config.py b/src/thread/utils/config.py index 70c9c08..818ca4d 100644 --- a/src/thread/utils/config.py +++ b/src/thread/utils/config.py @@ -35,12 +35,12 @@ def __init__(self, level: VerbosityLevel) -> None: ValueError: If the level is not of a valid type. """ if isinstance(level, str): - if level not in ['quiet', 'normal', 'verbose']: + if level not in VerbosityMapping.keys(): raise ValueError('Invalid verbosity level') self.level_string = level self.level_number = VerbosityMapping[level] elif isinstance(level, int): - if level not in [0, 1, 2]: + if level not in VerbosityMapping.values(): raise ValueError('Invalid verbosity level') self.level_number = level self.level_string = list(VerbosityMapping.keys())[level] From 30d57c4b27635c4155f98d8e6c49cca485844435 Mon Sep 17 00:00:00 2001 From: AlexNg Date: Tue, 12 Mar 2024 13:16:34 +0800 Subject: [PATCH 07/10] test: Implement testing for verbosity --- tests/test_verbosity.py | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 tests/test_verbosity.py diff --git a/tests/test_verbosity.py b/tests/test_verbosity.py new file mode 100644 index 0000000..cc6929a --- /dev/null +++ b/tests/test_verbosity.py @@ -0,0 +1,66 @@ +import pytest +from src.thread.utils.config import Verbosity + + +# >>>>>>>>>> General Use <<<<<<<<<< # +def test_eqTrue(): + assert Verbosity(0) == 0 + assert Verbosity(0) == 'quiet' + assert Verbosity(1) == 'normal' + assert Verbosity(1) == Verbosity(1) + + +def test_neTrue(): + assert Verbosity(0) != 1 + assert Verbosity(0) != 'normal' + assert Verbosity(1) != 'quiet' + assert Verbosity(1) != Verbosity(0) + + +def test_ltTrue(): + assert Verbosity(0) < 1 + assert Verbosity(0) < 'normal' + assert Verbosity(1) < 'verbose' + assert Verbosity(1) < Verbosity(2) + + +def test_leTrue(): + assert Verbosity(0) <= 1 + assert Verbosity(0) <= 'normal' + assert Verbosity(1) <= 'verbose' + assert Verbosity(1) <= Verbosity(2) + + +def test_gtTrue(): + assert Verbosity(1) > 0 + assert Verbosity(1) > 'quiet' + assert Verbosity(2) > 'normal' + assert Verbosity(2) > Verbosity(1) + + +def test_geTrue(): + assert Verbosity(1) >= 0 + assert Verbosity(1) >= 'quiet' + assert Verbosity(2) >= 'normal' + assert Verbosity(2) >= Verbosity(1) + + +# >>>>>>>>>> Raising <<<<<<<<<< # +def test_ltRaise(): + with pytest.raises(ValueError): + Verbosity(0) < Exception() + + +def test_leRaise(): + with pytest.raises(ValueError): + Verbosity(0) <= Exception() + + +def test_gtRaise(): + with pytest.raises(ValueError): + Verbosity(1) > Exception() + + +def test_geRaise(): + with pytest.raises(ValueError): + Verbosity(1) >= Exception() From 9513e834f8058ec2b9d8918f9ae7bc2736551161 Mon Sep 17 00:00:00 2001 From: AlexNg Date: Tue, 12 Mar 2024 13:19:43 +0800 Subject: [PATCH 08/10] feat: Implement verbosity --- src/thread/thread.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/thread/thread.py b/src/thread/thread.py index d597f3a..6a64b2e 100644 --- a/src/thread/thread.py +++ b/src/thread/thread.py @@ -137,7 +137,8 @@ def wrapper( except SystemExit: self.status = 'Killed' - print('KILLED ident: %s' % self.ident) + if Settings.VERBOSITY > 'quiet': + print('KILLED ident: %s' % self.ident) return return wrapper @@ -532,8 +533,9 @@ def start(self) -> None: # Handle abrupt exit def service_shutdown(signum, frame): if Settings.GRACEFUL_EXIT_ENABLED: - print('\nCaught signal %d' % signum) - print('Gracefully killing active threads') + if Settings.VERBOSITY > 'quiet': + print('\nCaught signal %d' % signum) + print('Gracefully killing active threads') for thread in Threads: if isinstance(thread, Thread): @@ -545,7 +547,8 @@ def service_shutdown(signum, frame): ): pass except Exception: - print('Failed to kill ident: %d' % thread.ident or 0) + if Settings.VERBOSITY > 'quiet': + print('Failed to kill ident: %d' % thread.ident or 0) sys.exit(0) From 41603a090a338a671d3fd8f043991c2e3222bbd6 Mon Sep 17 00:00:00 2001 From: AlexNg Date: Tue, 12 Mar 2024 14:42:56 +0800 Subject: [PATCH 09/10] style: Ruff formatting --- src/thread/utils/config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/thread/utils/config.py b/src/thread/utils/config.py index 818ca4d..492667f 100644 --- a/src/thread/utils/config.py +++ b/src/thread/utils/config.py @@ -1,5 +1,4 @@ -from typing import Any, Literal, Union, Callable - +from typing import Any, Callable, Literal, Union _Verbosity_Num = Literal[0, 1, 2] _Verbosity_Enum = Literal['quiet', 'normal', 'verbose'] From 0e87ae8004d434d42d30d674bf2af8c7118b6b16 Mon Sep 17 00:00:00 2001 From: AlexNg Date: Tue, 12 Mar 2024 14:43:37 +0800 Subject: [PATCH 10/10] feat: Update docstring and signature --- src/thread/utils/config.py | 44 +++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/thread/utils/config.py b/src/thread/utils/config.py index 492667f..081410e 100644 --- a/src/thread/utils/config.py +++ b/src/thread/utils/config.py @@ -85,6 +85,17 @@ def _compare( @staticmethod def is_valid_level(level: Any) -> bool: + """ + Determines whether the given level is a valid verbosity level. + + Parameters + ---------- + :param level: The level to check. + + Returns + ------- + :returns: True if the level is a valid verbosity level, False otherwise. + """ if isinstance(level, int): return level in VerbosityMapping.values() if isinstance(level, str): @@ -109,9 +120,36 @@ def __init__(self): raise NotImplementedError('This class is not instantiable') @staticmethod - def set_graceful_exit(enabled: bool = True): + def set_graceful_exit(enabled: bool = True) -> None: + """ + Enables/Disables graceful exiting. + + Parameters + ---------- + :param enabled: True to enable graceful exit, False otherwise. + + Returns + ------- + :returns: None + """ Settings.GRACEFUL_EXIT_ENABLED = enabled @staticmethod - def set_verbosity(verbosity: bool = True): - Settings.VERBOSITY = verbosity + def set_verbosity(verbosity: VerbosityLevel = 'normal') -> None: + """ + Sets the verbosity level. + + Parameters + ---------- + :param verbosity: The level of verbosity. Can be a number or an enum. + + Returns + ------- + :returns: None + + Raises + ------ + ValueError: If the level is not a valid number or enum. + ValueError: If the level is not of a valid type. + """ + Settings.VERBOSITY = Verbosity(verbosity)