Move var helpers into their own file, log update with additional levels
Add levels for ALERT, EMERGENCY to be syslog compatible Add direct wrappers for all, but they are not yet fully usable because the stack fix is not yet implemented Add a new debug helepr to get the stack as a string
This commit is contained in:
5
ToDo.md
5
ToDo.md
@@ -1,4 +1,5 @@
|
||||
# ToDo list
|
||||
|
||||
- stub files .pyi
|
||||
- fix all remaning check errors
|
||||
- [ ] stub files .pyi
|
||||
- [ ] Add tests for all, we need 100% test coverate
|
||||
- [ ] Log: add custom format for "stack_correct" if set, this will override the normal stack block
|
||||
|
||||
@@ -53,6 +53,9 @@ notes = ["FIXME", "TODO"]
|
||||
notes-rgx = '(FIXME|TODO)(\((TTD-|#)\[0-9]+\))'
|
||||
[tool.flake8]
|
||||
max-line-length = 120
|
||||
ignore = [
|
||||
"E741" # ignore ambigious variable name
|
||||
]
|
||||
[tool.pylint.MASTER]
|
||||
# this is for the tests/etc folders
|
||||
init-hook='import sys; sys.path.append("src/")'
|
||||
|
||||
@@ -11,7 +11,7 @@ from typing import Any, Tuple, Sequence, cast
|
||||
from pathlib import Path
|
||||
from corelibs.logging_handling.log import Log
|
||||
from corelibs.iterator_handling.list_helpers import convert_to_list, is_list_in_list
|
||||
from corelibs.string_handling.string_helpers import is_int, is_float, str_to_bool
|
||||
from corelibs.var_handling.var_helpers import is_int, is_float, str_to_bool
|
||||
from corelibs.config_handling.settings_loader_handling.settings_loader_check import SettingsLoaderCheck
|
||||
|
||||
|
||||
|
||||
33
src/corelibs/debug_handling/debug_helpers.py
Normal file
33
src/corelibs/debug_handling/debug_helpers.py
Normal file
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
Various debug helpers
|
||||
"""
|
||||
|
||||
import traceback
|
||||
import os
|
||||
|
||||
|
||||
def traceback_call_str(start: int = 2, depth: int = 1):
|
||||
"""
|
||||
get the trace for the last entry
|
||||
|
||||
Keyword Arguments:
|
||||
start {int} -- _description_ (default: {2})
|
||||
depth {int} -- _description_ (default: {1})
|
||||
|
||||
Returns:
|
||||
_type_ -- _description_
|
||||
"""
|
||||
# can't have more than in the stack for depth
|
||||
depth = min(depth, start)
|
||||
depth = start - depth
|
||||
# 0 is full stack length from start
|
||||
if depth == 0:
|
||||
stack = traceback.extract_stack()[-start:]
|
||||
else:
|
||||
stack = traceback.extract_stack()[-start:-depth]
|
||||
return ' -> '.join(
|
||||
f"{os.path.basename(f.filename)}:{f.name}:{f.lineno}"
|
||||
for f in stack
|
||||
)
|
||||
|
||||
# __END__
|
||||
@@ -9,9 +9,10 @@ import logging.handlers
|
||||
import logging
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Mapping, TextIO, TypedDict, Any, TYPE_CHECKING, cast
|
||||
from typing import MutableMapping, TextIO, TypedDict, Any, TYPE_CHECKING, cast
|
||||
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
|
||||
from corelibs.string_handling.text_colors import Colors
|
||||
from corelibs.debug_handling.debug_helpers import traceback_call_str
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from multiprocessing import Queue
|
||||
@@ -41,12 +42,14 @@ class CustomConsoleFormatter(logging.Formatter):
|
||||
"""
|
||||
|
||||
COLORS = {
|
||||
"DEBUG": Colors.cyan,
|
||||
"INFO": Colors.green,
|
||||
"WARNING": Colors.yellow,
|
||||
"ERROR": Colors.red,
|
||||
"CRITICAL": Colors.red_bold,
|
||||
"EXCEPTION": Colors.magenta_bold, # will never be written to console
|
||||
LoggingLevel.DEBUG.name: Colors.cyan,
|
||||
LoggingLevel.INFO.name: Colors.green,
|
||||
LoggingLevel.WARNING.name: Colors.yellow,
|
||||
LoggingLevel.ERROR.name: Colors.red,
|
||||
LoggingLevel.CRITICAL.name: Colors.red_bold,
|
||||
LoggingLevel.ALERT.name: Colors.yellow_bold,
|
||||
LoggingLevel.EMERGENCY.name: Colors.magenta_bold,
|
||||
LoggingLevel.EXCEPTION.name: Colors.magenta_bright, # will never be written to console
|
||||
}
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
@@ -63,7 +66,7 @@ class CustomConsoleFormatter(logging.Formatter):
|
||||
reset = Colors.reset
|
||||
color = self.COLORS.get(record.levelname, reset)
|
||||
# only highlight level for basic
|
||||
if record.levelname in ['DEBUG', 'INFO']:
|
||||
if record.levelname in [LoggingLevel.DEBUG.name, LoggingLevel.INFO.name]:
|
||||
record.levelname = f"{color}{record.levelname}{reset}"
|
||||
return super().format(record)
|
||||
# highlight whole line
|
||||
@@ -71,6 +74,10 @@ class CustomConsoleFormatter(logging.Formatter):
|
||||
return f"{color}{message}{reset}"
|
||||
|
||||
|
||||
# TODO: add custom handlers for stack_correct, if not set fill with %(filename)s:%(funcName)s:%(lineno)d
|
||||
# hasattr(record, 'stack_correct')
|
||||
|
||||
|
||||
# MARK: Log class
|
||||
class Log:
|
||||
"""
|
||||
@@ -86,14 +93,14 @@ class Log:
|
||||
DEFAULT_LOG_LEVEL_CONSOLE: LoggingLevel = LoggingLevel.WARNING
|
||||
# default settings
|
||||
DEFAULT_LOG_SETTINGS: LogSettings = {
|
||||
"log_level_console": LoggingLevel.WARNING,
|
||||
"log_level_file": LoggingLevel.DEBUG,
|
||||
"console_enabled": True,
|
||||
"console_color_output_enabled": True,
|
||||
"add_start_info": True,
|
||||
"add_end_info": False,
|
||||
"log_queue": None,
|
||||
}
|
||||
"log_level_console": LoggingLevel.WARNING,
|
||||
"log_level_file": LoggingLevel.DEBUG,
|
||||
"console_enabled": True,
|
||||
"console_color_output_enabled": True,
|
||||
"add_start_info": True,
|
||||
"add_end_info": False,
|
||||
"log_queue": None,
|
||||
}
|
||||
|
||||
# MARK: constructor
|
||||
def __init__(
|
||||
@@ -103,8 +110,10 @@ class Log:
|
||||
log_settings: dict[str, 'LoggingLevel | str | bool | None | Queue[str]'] | LogSettings | None = None,
|
||||
other_handlers: dict[str, Any] | None = None
|
||||
):
|
||||
# add new level for EXCEPTION
|
||||
logging.addLevelName(LoggingLevel.EXCEPTION.value, 'EXCEPTION')
|
||||
# add new level for alert, emergecny and exception
|
||||
logging.addLevelName(LoggingLevel.ALERT.value, LoggingLevel.ALERT.name)
|
||||
logging.addLevelName(LoggingLevel.EMERGENCY.value, LoggingLevel.EMERGENCY.name)
|
||||
logging.addLevelName(LoggingLevel.EXCEPTION.value, LoggingLevel.EXCEPTION.name)
|
||||
# parse the logging settings
|
||||
self.log_settings = self.__parse_log_settings(log_settings)
|
||||
# if path, set log name with .log
|
||||
@@ -126,7 +135,7 @@ class Log:
|
||||
|
||||
self.log_queue: 'Queue[str] | None' = None
|
||||
self.listener: logging.handlers.QueueListener | None = None
|
||||
self.logger: logging.Logger | None = None
|
||||
self.logger: logging.Logger
|
||||
|
||||
# setup handlers
|
||||
# NOTE if console with color is set first, some of the color formatting is set
|
||||
@@ -220,7 +229,7 @@ class Log:
|
||||
"""
|
||||
if self.handlers.get(handler_name):
|
||||
return False
|
||||
if self.listener is not None or self.logger is not None:
|
||||
if self.listener is not None or hasattr(self, 'logger'):
|
||||
raise ValueError(
|
||||
f"Cannot add handler {handler_name}: {handler.get_name()} because logger is already running"
|
||||
)
|
||||
@@ -335,6 +344,9 @@ class Log:
|
||||
# set maximum logging level for all logging output
|
||||
# log level filtering is done per handler
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
# short name
|
||||
self.lg = self.logger
|
||||
self.l = self.logger
|
||||
|
||||
# MARK: init logger for Fork/Thread
|
||||
@staticmethod
|
||||
@@ -355,18 +367,107 @@ class Log:
|
||||
|
||||
return root_logger
|
||||
|
||||
# FIXME: all below will only work if we add a custom format interface for the stack_correct part
|
||||
# Important note, although they exist, it is recommended to use self.logger.NAME directly
|
||||
# so that the correct filename, method and row number is set
|
||||
# for > 50 use logger.log(LoggingLevel.<LEVEL>.value, ...)
|
||||
# for exception logger.log(LoggingLevel.EXCEPTION.value, ..., execInfo=True)
|
||||
# MARK: log message
|
||||
def exception(self, msg: object, *args: object, extra: Mapping[str, object] | None = None) -> None:
|
||||
def log(self, level: int, msg: object, *args: object, extra: MutableMapping[str, object] | None = None):
|
||||
"""log general"""
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['stack_correct'] = traceback_call_str(start=3)
|
||||
self.logger.log(level, msg, *args, extra=extra)
|
||||
|
||||
# MARK: DEBUG 10
|
||||
def debug(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None:
|
||||
"""debug"""
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['stack_correct'] = traceback_call_str(start=3)
|
||||
self.logger.debug(msg, *args, extra=extra)
|
||||
|
||||
# MARK: INFO 20
|
||||
def info(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None:
|
||||
"""info"""
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['stack_correct'] = traceback_call_str(start=3)
|
||||
self.logger.info(msg, *args, extra=extra)
|
||||
|
||||
# MARK: WARNING 30
|
||||
def warning(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None:
|
||||
"""warning"""
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['stack_correct'] = traceback_call_str(start=3)
|
||||
self.logger.warning(msg, *args, extra=extra)
|
||||
|
||||
# MARK: ERROR 40
|
||||
def error(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None:
|
||||
"""error"""
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['stack_correct'] = traceback_call_str(start=3)
|
||||
self.logger.error(msg, *args, extra=extra)
|
||||
|
||||
# MARK: CRITICAL 50
|
||||
def critical(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None:
|
||||
"""critcal"""
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['stack_correct'] = traceback_call_str(start=3)
|
||||
self.logger.critical(msg, *args, extra=extra)
|
||||
|
||||
# MARK: ALERT 55
|
||||
def alert(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None:
|
||||
"""alert"""
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
# extra_dict = dict(extra)
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['stack_correct'] = traceback_call_str(start=3)
|
||||
self.logger.log(LoggingLevel.ALERT.value, msg, *args, extra=extra)
|
||||
|
||||
# MARK: EMERGECNY: 60
|
||||
def emergency(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None:
|
||||
"""emergency"""
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['stack_correct'] = traceback_call_str(start=3)
|
||||
self.logger.log(LoggingLevel.EMERGENCY.value, msg, *args, extra=extra)
|
||||
|
||||
# MARK: EXCEPTION: 70
|
||||
def exception(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None:
|
||||
"""
|
||||
log on exceotion level
|
||||
log on exceotion level, this is log.exception, but logs with a new level
|
||||
|
||||
Args:
|
||||
msg (object): _description_
|
||||
*args (object): arguments for msg
|
||||
extra: Mapping[str, object] | None: extra arguments for the formatting if needed
|
||||
"""
|
||||
if self.logger is None:
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
if extra is None:
|
||||
extra = {}
|
||||
extra['stack_correct'] = traceback_call_str(start=3)
|
||||
self.logger.log(LoggingLevel.EXCEPTION.value, msg, *args, exc_info=True, extra=extra)
|
||||
|
||||
# MARK: break line
|
||||
@@ -377,7 +478,7 @@ class Log:
|
||||
Keyword Arguments:
|
||||
info {str} -- _description_ (default: {"BREAK"})
|
||||
"""
|
||||
if self.logger is None:
|
||||
if not hasattr(self, 'logger'):
|
||||
raise ValueError('Logger is not yet initialized')
|
||||
self.logger.info("[%s] %s>", info, self.SPACER_CHAR * self.SPACER_LENGTH)
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ class LoggingLevel(Enum):
|
||||
WARNING = logging.WARNING # 30
|
||||
ERROR = logging.ERROR # 40
|
||||
CRITICAL = logging.CRITICAL # 50
|
||||
EXCEPTION = 60 # 60 (manualy set)
|
||||
ALERT = 55 # 55 (for Sys log)
|
||||
EMERGENCY = 60 # 60 (for Sys log)
|
||||
EXCEPTION = 70 # 70 (manualy set, error but with higher level)
|
||||
# Alternative names
|
||||
WARN = logging.WARN # 30 (alias for WARNING)
|
||||
FATAL = logging.FATAL # 50 (alias for CRITICAL)
|
||||
@@ -83,6 +85,6 @@ class LoggingLevel(Enum):
|
||||
|
||||
def is_lower_than(self, level: 'LoggingLevel'):
|
||||
"""if given value is lower than set"""
|
||||
return self.value > level.value
|
||||
return self.value < level.value
|
||||
|
||||
# __END__
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
String helpers
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
from decimal import Decimal, getcontext
|
||||
from textwrap import shorten
|
||||
|
||||
@@ -102,62 +101,4 @@ def format_number(number: float, precision: int = 0) -> str:
|
||||
"f}"
|
||||
).format(_number)
|
||||
|
||||
|
||||
def is_int(string: Any) -> bool:
|
||||
"""
|
||||
check if a value is int
|
||||
|
||||
Arguments:
|
||||
string {Any} -- _description_
|
||||
|
||||
Returns:
|
||||
bool -- _description_
|
||||
"""
|
||||
try:
|
||||
int(string)
|
||||
return True
|
||||
except TypeError:
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def is_float(string: Any) -> bool:
|
||||
"""
|
||||
check if a value is float
|
||||
|
||||
Arguments:
|
||||
string {Any} -- _description_
|
||||
|
||||
Returns:
|
||||
bool -- _description_
|
||||
"""
|
||||
try:
|
||||
float(string)
|
||||
return True
|
||||
except TypeError:
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def str_to_bool(string: str):
|
||||
"""
|
||||
convert string to bool
|
||||
|
||||
Arguments:
|
||||
s {str} -- _description_
|
||||
|
||||
Raises:
|
||||
ValueError: _description_
|
||||
|
||||
Returns:
|
||||
_type_ -- _description_
|
||||
"""
|
||||
if string == "True" or string == "true":
|
||||
return True
|
||||
if string == "False" or string == "false":
|
||||
return False
|
||||
raise ValueError(f"Invalid boolean string: {string}")
|
||||
|
||||
# __END__
|
||||
|
||||
0
src/corelibs/var_handling/__init__.py
Normal file
0
src/corelibs/var_handling/__init__.py
Normal file
65
src/corelibs/var_handling/var_helpers.py
Normal file
65
src/corelibs/var_handling/var_helpers.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
variable convert, check, etc helepr
|
||||
"""
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def is_int(string: Any) -> bool:
|
||||
"""
|
||||
check if a value is int
|
||||
|
||||
Arguments:
|
||||
string {Any} -- _description_
|
||||
|
||||
Returns:
|
||||
bool -- _description_
|
||||
"""
|
||||
try:
|
||||
int(string)
|
||||
return True
|
||||
except TypeError:
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def is_float(string: Any) -> bool:
|
||||
"""
|
||||
check if a value is float
|
||||
|
||||
Arguments:
|
||||
string {Any} -- _description_
|
||||
|
||||
Returns:
|
||||
bool -- _description_
|
||||
"""
|
||||
try:
|
||||
float(string)
|
||||
return True
|
||||
except TypeError:
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def str_to_bool(string: str):
|
||||
"""
|
||||
convert string to bool
|
||||
|
||||
Arguments:
|
||||
s {str} -- _description_
|
||||
|
||||
Raises:
|
||||
ValueError: _description_
|
||||
|
||||
Returns:
|
||||
_type_ -- _description_
|
||||
"""
|
||||
if string == "True" or string == "true":
|
||||
return True
|
||||
if string == "False" or string == "false":
|
||||
return False
|
||||
raise ValueError(f"Invalid boolean string: {string}")
|
||||
|
||||
# __END__
|
||||
@@ -23,16 +23,24 @@ def main():
|
||||
# "console_color_output_enabled": False,
|
||||
}
|
||||
)
|
||||
if log.logger is None:
|
||||
print("failed to start logger")
|
||||
return
|
||||
|
||||
log.logger.debug('[NORMAL] Debug test: %s', log.logger.name)
|
||||
log.lg.debug('[NORMAL] Debug test: %s', log.logger.name)
|
||||
log.debug('[NORMAL-] Debug test: %s', log.logger.name)
|
||||
log.logger.info('[NORMAL] Info test: %s', log.logger.name)
|
||||
log.info('[NORMAL-] Info test: %s', log.logger.name)
|
||||
log.logger.warning('[NORMAL] Warning test: %s', log.logger.name)
|
||||
log.warning('[NORMAL-] Warning test: %s', log.logger.name)
|
||||
log.logger.error('[NORMAL] Error test: %s', log.logger.name)
|
||||
log.error('[NORMAL-] Error test: %s', log.logger.name)
|
||||
log.logger.critical('[NORMAL] Critical test: %s', log.logger.name)
|
||||
log.critical('[NORMAL-] Critical test: %s', log.logger.name)
|
||||
log.logger.log(LoggingLevel.ALERT.value, '[NORMAL] alert test: %s', log.logger.name)
|
||||
log.alert('[NORMAL-] alert test: %s', log.logger.name)
|
||||
log.emergency('[NORMAL-] emergency test: %s', log.logger.name)
|
||||
log.logger.log(LoggingLevel.EMERGENCY.value, '[NORMAL] emergency test: %s', log.logger.name)
|
||||
log.exception('[NORMAL] Exception test: %s', log.logger.name)
|
||||
log.logger.log(LoggingLevel.EXCEPTION.value, '[NORMAL] exception test: %s', log.logger.name, exc_info=True)
|
||||
|
||||
bad_level = 'WRONG'
|
||||
if not Log.validate_log_level(bad_level):
|
||||
|
||||
@@ -47,9 +47,7 @@ def main():
|
||||
"log_queue": log_queue,
|
||||
}
|
||||
)
|
||||
if log.logger is None:
|
||||
print("logger not yet started")
|
||||
return
|
||||
|
||||
log.logger.debug('Pool Fork logging test')
|
||||
max_forks = 2
|
||||
data_sets = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
||||
|
||||
@@ -28,16 +28,13 @@ def main():
|
||||
# "console_color_output_enabled": False,
|
||||
}
|
||||
)
|
||||
if log_q.logger is None:
|
||||
print("failed to start logger")
|
||||
return
|
||||
|
||||
log_q.logger.debug('[QUEUE] Debug test: %s', log_q.logger.name)
|
||||
log_q.logger.info('[QUEUE] Info test: %s', log_q.logger.name)
|
||||
log_q.logger.warning('[QUEUE] Warning test: %s', log_q.logger.name)
|
||||
log_q.logger.error('[QUEUE] Error test: %s', log_q.logger.name)
|
||||
log_q.logger.critical('[QUEUE] Critical test: %s', log_q.logger.name)
|
||||
log_q.exception('[QUEUE] Exception test: %s', log_q.logger.name)
|
||||
log_q.logger.log(LoggingLevel.EXCEPTION.value, '[QUEUE] Exception test: %s', log_q.logger.name, exc_info=True)
|
||||
time.sleep(0.1)
|
||||
|
||||
for handler in log_q.logger.handlers:
|
||||
|
||||
@@ -19,7 +19,9 @@ class TestLoggingLevelEnum:
|
||||
assert LoggingLevel.WARNING.value == 30
|
||||
assert LoggingLevel.ERROR.value == 40
|
||||
assert LoggingLevel.CRITICAL.value == 50
|
||||
assert LoggingLevel.EXCEPTION.value == 60
|
||||
assert LoggingLevel.ALERT.value == 55
|
||||
assert LoggingLevel.EMERGENCY.value == 60
|
||||
assert LoggingLevel.EXCEPTION.value == 70
|
||||
assert LoggingLevel.WARN.value == 30
|
||||
assert LoggingLevel.FATAL.value == 50
|
||||
|
||||
@@ -77,7 +79,9 @@ class TestFromInt:
|
||||
assert LoggingLevel.from_int(30) == LoggingLevel.WARNING
|
||||
assert LoggingLevel.from_int(40) == LoggingLevel.ERROR
|
||||
assert LoggingLevel.from_int(50) == LoggingLevel.CRITICAL
|
||||
assert LoggingLevel.from_int(60) == LoggingLevel.EXCEPTION
|
||||
assert LoggingLevel.from_int(55) == LoggingLevel.ALERT
|
||||
assert LoggingLevel.from_int(60) == LoggingLevel.EMERGENCY
|
||||
assert LoggingLevel.from_int(70) == LoggingLevel.EXCEPTION
|
||||
|
||||
def test_from_int_invalid_cases(self):
|
||||
"""Test from_int with invalid integer inputs."""
|
||||
@@ -142,7 +146,9 @@ class TestToLoggingLevel:
|
||||
assert LoggingLevel.WARNING.to_logging_level() == 30
|
||||
assert LoggingLevel.ERROR.to_logging_level() == 40
|
||||
assert LoggingLevel.CRITICAL.to_logging_level() == 50
|
||||
assert LoggingLevel.EXCEPTION.to_logging_level() == 60
|
||||
assert LoggingLevel.ALERT.to_logging_level() == 55
|
||||
assert LoggingLevel.EMERGENCY.to_logging_level() == 60
|
||||
assert LoggingLevel.EXCEPTION.to_logging_level() == 70
|
||||
|
||||
|
||||
class TestToLowerCase:
|
||||
@@ -155,6 +161,8 @@ class TestToLowerCase:
|
||||
assert LoggingLevel.WARNING.to_lower_case() == "warning"
|
||||
assert LoggingLevel.ERROR.to_lower_case() == "error"
|
||||
assert LoggingLevel.CRITICAL.to_lower_case() == "critical"
|
||||
assert LoggingLevel.ALERT.to_lower_case() == "alert"
|
||||
assert LoggingLevel.EMERGENCY.to_lower_case() == "emergency"
|
||||
assert LoggingLevel.EXCEPTION.to_lower_case() == "exception"
|
||||
|
||||
|
||||
@@ -168,6 +176,8 @@ class TestStrMethod:
|
||||
assert str(LoggingLevel.WARNING) == "WARNING"
|
||||
assert str(LoggingLevel.ERROR) == "ERROR"
|
||||
assert str(LoggingLevel.CRITICAL) == "CRITICAL"
|
||||
assert str(LoggingLevel.ALERT) == "ALERT"
|
||||
assert str(LoggingLevel.EMERGENCY) == "EMERGENCY"
|
||||
assert str(LoggingLevel.EXCEPTION) == "EXCEPTION"
|
||||
|
||||
|
||||
@@ -182,6 +192,8 @@ class TestIncludes:
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.WARNING)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.ALERT)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.EMERGENCY)
|
||||
assert LoggingLevel.DEBUG.includes(LoggingLevel.EXCEPTION)
|
||||
|
||||
# INFO includes INFO and higher
|
||||
@@ -189,6 +201,8 @@ class TestIncludes:
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.WARNING)
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.ALERT)
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.EMERGENCY)
|
||||
assert LoggingLevel.INFO.includes(LoggingLevel.EXCEPTION)
|
||||
|
||||
# INFO does not include DEBUG
|
||||
@@ -197,6 +211,8 @@ class TestIncludes:
|
||||
# ERROR includes ERROR and higher
|
||||
assert LoggingLevel.ERROR.includes(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.ERROR.includes(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.ERROR.includes(LoggingLevel.ALERT)
|
||||
assert LoggingLevel.ERROR.includes(LoggingLevel.EMERGENCY)
|
||||
assert LoggingLevel.ERROR.includes(LoggingLevel.EXCEPTION)
|
||||
|
||||
# ERROR does not include lower levels
|
||||
@@ -212,7 +228,9 @@ class TestIsHigherThan:
|
||||
"""Test is_higher_than method."""
|
||||
assert LoggingLevel.ERROR.is_higher_than(LoggingLevel.WARNING)
|
||||
assert LoggingLevel.CRITICAL.is_higher_than(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.EXCEPTION.is_higher_than(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.ALERT.is_higher_than(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.EMERGENCY.is_higher_than(LoggingLevel.ALERT)
|
||||
assert LoggingLevel.EXCEPTION.is_higher_than(LoggingLevel.EMERGENCY)
|
||||
assert LoggingLevel.INFO.is_higher_than(LoggingLevel.DEBUG)
|
||||
|
||||
# Same level should return False
|
||||
@@ -240,11 +258,15 @@ class TestIsLowerThan:
|
||||
pass
|
||||
|
||||
def test_is_lower_than_actual_behavior(self):
|
||||
"""Test the actual (buggy) behavior of is_lower_than method."""
|
||||
"""Test the actual behavior of is_lower_than method."""
|
||||
# Due to the bug, this method behaves like is_higher_than
|
||||
assert LoggingLevel.ERROR.is_lower_than(LoggingLevel.WARNING)
|
||||
assert LoggingLevel.CRITICAL.is_lower_than(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.INFO.is_lower_than(LoggingLevel.DEBUG)
|
||||
assert LoggingLevel.DEBUG.is_lower_than(LoggingLevel.INFO)
|
||||
assert LoggingLevel.INFO.is_lower_than(LoggingLevel.WARNING)
|
||||
assert LoggingLevel.WARNING.is_lower_than(LoggingLevel.ERROR)
|
||||
assert LoggingLevel.ERROR.is_lower_than(LoggingLevel.CRITICAL)
|
||||
assert LoggingLevel.CRITICAL.is_lower_than(LoggingLevel.ALERT)
|
||||
assert LoggingLevel.ALERT.is_lower_than(LoggingLevel.EMERGENCY)
|
||||
assert LoggingLevel.EMERGENCY.is_lower_than(LoggingLevel.EXCEPTION)
|
||||
|
||||
# Same level should return False
|
||||
assert not LoggingLevel.INFO.is_lower_than(LoggingLevel.INFO)
|
||||
@@ -278,7 +300,8 @@ class TestIntegration:
|
||||
"""Test round-trip conversions work correctly."""
|
||||
original_levels = [
|
||||
LoggingLevel.DEBUG, LoggingLevel.INFO, LoggingLevel.WARNING,
|
||||
LoggingLevel.ERROR, LoggingLevel.CRITICAL, LoggingLevel.EXCEPTION
|
||||
LoggingLevel.ERROR, LoggingLevel.CRITICAL, LoggingLevel.ALERT,
|
||||
LoggingLevel.EXCEPTION, LoggingLevel.EXCEPTION
|
||||
]
|
||||
|
||||
for level in original_levels:
|
||||
@@ -298,7 +321,7 @@ class TestIntegration:
|
||||
levels = [
|
||||
LoggingLevel.NOTSET, LoggingLevel.DEBUG, LoggingLevel.INFO,
|
||||
LoggingLevel.WARNING, LoggingLevel.ERROR, LoggingLevel.CRITICAL,
|
||||
LoggingLevel.EXCEPTION
|
||||
LoggingLevel.ALERT, LoggingLevel.EMERGENCY, LoggingLevel.EXCEPTION
|
||||
]
|
||||
|
||||
for i, level in enumerate(levels):
|
||||
|
||||
@@ -3,10 +3,9 @@ PyTest: string_handling/string_helpers
|
||||
"""
|
||||
|
||||
from textwrap import shorten
|
||||
from typing import Any
|
||||
import pytest
|
||||
from corelibs.string_handling.string_helpers import (
|
||||
shorten_string, left_fill, format_number, is_int, is_float, str_to_bool
|
||||
shorten_string, left_fill, format_number
|
||||
)
|
||||
|
||||
|
||||
@@ -237,238 +236,4 @@ def test_format_number_parametrized(number: float | int, precision: int, expecte
|
||||
"""Parametrized test for format_number"""
|
||||
assert format_number(number, precision) == expected
|
||||
|
||||
# ADDED 2025/7/11 Replace 'your_module' with actual module name
|
||||
|
||||
|
||||
class TestIsInt:
|
||||
"""Test cases for is_int function"""
|
||||
|
||||
def test_valid_integers(self):
|
||||
"""Test with valid integer strings"""
|
||||
assert is_int("123") is True
|
||||
assert is_int("0") is True
|
||||
assert is_int("-456") is True
|
||||
assert is_int("+789") is True
|
||||
assert is_int("000") is True
|
||||
|
||||
def test_invalid_integers(self):
|
||||
"""Test with invalid integer strings"""
|
||||
assert is_int("12.34") is False
|
||||
assert is_int("abc") is False
|
||||
assert is_int("12a") is False
|
||||
assert is_int("") is False
|
||||
assert is_int(" ") is False
|
||||
assert is_int("12.0") is False
|
||||
assert is_int("1e5") is False
|
||||
|
||||
def test_numeric_types(self):
|
||||
"""Test with actual numeric types"""
|
||||
assert is_int(123) is True
|
||||
assert is_int(0) is True
|
||||
assert is_int(-456) is True
|
||||
assert is_int(12.34) is True # float can be converted to int
|
||||
assert is_int(12.0) is True
|
||||
|
||||
def test_other_types(self):
|
||||
"""Test with other data types"""
|
||||
assert is_int(None) is False
|
||||
assert is_int([]) is False
|
||||
assert is_int({}) is False
|
||||
assert is_int(True) is True # bool is subclass of int
|
||||
assert is_int(False) is True
|
||||
|
||||
|
||||
class TestIsFloat:
|
||||
"""Test cases for is_float function"""
|
||||
|
||||
def test_valid_floats(self):
|
||||
"""Test with valid float strings"""
|
||||
assert is_float("12.34") is True
|
||||
assert is_float("0.0") is True
|
||||
assert is_float("-45.67") is True
|
||||
assert is_float("+78.9") is True
|
||||
assert is_float("123") is True # integers are valid floats
|
||||
assert is_float("0") is True
|
||||
assert is_float("1e5") is True
|
||||
assert is_float("1.5e-10") is True
|
||||
assert is_float("inf") is True
|
||||
assert is_float("-inf") is True
|
||||
assert is_float("nan") is True
|
||||
|
||||
def test_invalid_floats(self):
|
||||
"""Test with invalid float strings"""
|
||||
assert is_float("abc") is False
|
||||
assert is_float("12.34.56") is False
|
||||
assert is_float("12a") is False
|
||||
assert is_float("") is False
|
||||
assert is_float(" ") is False
|
||||
assert is_float("12..34") is False
|
||||
|
||||
def test_numeric_types(self):
|
||||
"""Test with actual numeric types"""
|
||||
assert is_float(123) is True
|
||||
assert is_float(12.34) is True
|
||||
assert is_float(0) is True
|
||||
assert is_float(-45.67) is True
|
||||
|
||||
def test_other_types(self):
|
||||
"""Test with other data types"""
|
||||
assert is_float(None) is False
|
||||
assert is_float([]) is False
|
||||
assert is_float({}) is False
|
||||
assert is_float(True) is True # bool can be converted to float
|
||||
assert is_float(False) is True
|
||||
|
||||
|
||||
class TestStrToBool:
|
||||
"""Test cases for str_to_bool function"""
|
||||
|
||||
def test_valid_true_strings(self):
|
||||
"""Test with valid true strings"""
|
||||
assert str_to_bool("True") is True
|
||||
assert str_to_bool("true") is True
|
||||
|
||||
def test_valid_false_strings(self):
|
||||
"""Test with valid false strings"""
|
||||
assert str_to_bool("False") is False
|
||||
assert str_to_bool("false") is False
|
||||
|
||||
def test_invalid_strings(self):
|
||||
"""Test with invalid boolean strings"""
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("TRUE")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("FALSE")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("yes")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("no")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("1")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("0")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool(" True")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("True ")
|
||||
|
||||
def test_error_message_content(self):
|
||||
"""Test that error messages contain the invalid input"""
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
str_to_bool("invalid")
|
||||
assert "Invalid boolean string: invalid" in str(exc_info.value)
|
||||
|
||||
def test_case_sensitivity(self):
|
||||
"""Test that function is case sensitive"""
|
||||
with pytest.raises(ValueError):
|
||||
str_to_bool("TRUE")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
str_to_bool("True ") # with space
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
str_to_bool(" True") # with space
|
||||
|
||||
|
||||
# Additional edge case tests
|
||||
class TestEdgeCases:
|
||||
"""Test edge cases and special scenarios"""
|
||||
|
||||
def test_is_int_with_whitespace(self):
|
||||
"""Test is_int with whitespace (should work due to int() behavior)"""
|
||||
assert is_int(" 123 ") is True
|
||||
assert is_int("\t456\n") is True
|
||||
|
||||
def test_is_float_with_whitespace(self):
|
||||
"""Test is_float with whitespace (should work due to float() behavior)"""
|
||||
assert is_float(" 12.34 ") is True
|
||||
assert is_float("\t45.67\n") is True
|
||||
|
||||
def test_large_numbers(self):
|
||||
"""Test with very large numbers"""
|
||||
large_int = "123456789012345678901234567890"
|
||||
assert is_int(large_int) is True
|
||||
assert is_float(large_int) is True
|
||||
|
||||
def test_scientific_notation(self):
|
||||
"""Test scientific notation"""
|
||||
assert is_int("1e5") is False # int() doesn't handle scientific notation
|
||||
assert is_float("1e5") is True
|
||||
assert is_float("1.5e-10") is True
|
||||
assert is_float("2E+3") is True
|
||||
|
||||
|
||||
# Parametrized tests for more comprehensive coverage
|
||||
class TestParametrized:
|
||||
"""Parametrized tests for better coverage"""
|
||||
|
||||
@pytest.mark.parametrize("value,expected", [
|
||||
("123", True),
|
||||
("0", True),
|
||||
("-456", True),
|
||||
("12.34", False),
|
||||
("abc", False),
|
||||
("", False),
|
||||
(123, True),
|
||||
(12.5, True),
|
||||
(None, False),
|
||||
])
|
||||
def test_is_int_parametrized(self, value: Any, expected: bool):
|
||||
"""Test"""
|
||||
assert is_int(value) == expected
|
||||
|
||||
@pytest.mark.parametrize("value,expected", [
|
||||
("12.34", True),
|
||||
("123", True),
|
||||
("0", True),
|
||||
("-45.67", True),
|
||||
("inf", True),
|
||||
("nan", True),
|
||||
("abc", False),
|
||||
("", False),
|
||||
(12.34, True),
|
||||
(123, True),
|
||||
(None, False),
|
||||
])
|
||||
def test_is_float_parametrized(self, value: Any, expected: bool):
|
||||
"""test"""
|
||||
assert is_float(value) == expected
|
||||
|
||||
@pytest.mark.parametrize("value,expected", [
|
||||
("True", True),
|
||||
("true", True),
|
||||
("False", False),
|
||||
("false", False),
|
||||
])
|
||||
def test_str_to_bool_valid_parametrized(self, value: Any, expected: bool):
|
||||
"""test"""
|
||||
assert str_to_bool(value) == expected
|
||||
|
||||
@pytest.mark.parametrize("invalid_value", [
|
||||
"TRUE",
|
||||
"FALSE",
|
||||
"yes",
|
||||
"no",
|
||||
"1",
|
||||
"0",
|
||||
"",
|
||||
" True",
|
||||
"True ",
|
||||
"invalid",
|
||||
])
|
||||
def test_str_to_bool_invalid_parametrized(self, invalid_value: Any):
|
||||
"""test"""
|
||||
with pytest.raises(ValueError):
|
||||
str_to_bool(invalid_value)
|
||||
|
||||
# __END__
|
||||
|
||||
241
tests/unit/string_handling/test_var_helpers.py
Normal file
241
tests/unit/string_handling/test_var_helpers.py
Normal file
@@ -0,0 +1,241 @@
|
||||
"""
|
||||
var helpers
|
||||
"""
|
||||
|
||||
# ADDED 2025/7/11 Replace 'your_module' with actual module name
|
||||
|
||||
from typing import Any
|
||||
import pytest
|
||||
from corelibs.var_handling.var_helpers import is_int, is_float, str_to_bool
|
||||
|
||||
|
||||
class TestIsInt:
|
||||
"""Test cases for is_int function"""
|
||||
|
||||
def test_valid_integers(self):
|
||||
"""Test with valid integer strings"""
|
||||
assert is_int("123") is True
|
||||
assert is_int("0") is True
|
||||
assert is_int("-456") is True
|
||||
assert is_int("+789") is True
|
||||
assert is_int("000") is True
|
||||
|
||||
def test_invalid_integers(self):
|
||||
"""Test with invalid integer strings"""
|
||||
assert is_int("12.34") is False
|
||||
assert is_int("abc") is False
|
||||
assert is_int("12a") is False
|
||||
assert is_int("") is False
|
||||
assert is_int(" ") is False
|
||||
assert is_int("12.0") is False
|
||||
assert is_int("1e5") is False
|
||||
|
||||
def test_numeric_types(self):
|
||||
"""Test with actual numeric types"""
|
||||
assert is_int(123) is True
|
||||
assert is_int(0) is True
|
||||
assert is_int(-456) is True
|
||||
assert is_int(12.34) is True # float can be converted to int
|
||||
assert is_int(12.0) is True
|
||||
|
||||
def test_other_types(self):
|
||||
"""Test with other data types"""
|
||||
assert is_int(None) is False
|
||||
assert is_int([]) is False
|
||||
assert is_int({}) is False
|
||||
assert is_int(True) is True # bool is subclass of int
|
||||
assert is_int(False) is True
|
||||
|
||||
|
||||
class TestIsFloat:
|
||||
"""Test cases for is_float function"""
|
||||
|
||||
def test_valid_floats(self):
|
||||
"""Test with valid float strings"""
|
||||
assert is_float("12.34") is True
|
||||
assert is_float("0.0") is True
|
||||
assert is_float("-45.67") is True
|
||||
assert is_float("+78.9") is True
|
||||
assert is_float("123") is True # integers are valid floats
|
||||
assert is_float("0") is True
|
||||
assert is_float("1e5") is True
|
||||
assert is_float("1.5e-10") is True
|
||||
assert is_float("inf") is True
|
||||
assert is_float("-inf") is True
|
||||
assert is_float("nan") is True
|
||||
|
||||
def test_invalid_floats(self):
|
||||
"""Test with invalid float strings"""
|
||||
assert is_float("abc") is False
|
||||
assert is_float("12.34.56") is False
|
||||
assert is_float("12a") is False
|
||||
assert is_float("") is False
|
||||
assert is_float(" ") is False
|
||||
assert is_float("12..34") is False
|
||||
|
||||
def test_numeric_types(self):
|
||||
"""Test with actual numeric types"""
|
||||
assert is_float(123) is True
|
||||
assert is_float(12.34) is True
|
||||
assert is_float(0) is True
|
||||
assert is_float(-45.67) is True
|
||||
|
||||
def test_other_types(self):
|
||||
"""Test with other data types"""
|
||||
assert is_float(None) is False
|
||||
assert is_float([]) is False
|
||||
assert is_float({}) is False
|
||||
assert is_float(True) is True # bool can be converted to float
|
||||
assert is_float(False) is True
|
||||
|
||||
|
||||
class TestStrToBool:
|
||||
"""Test cases for str_to_bool function"""
|
||||
|
||||
def test_valid_true_strings(self):
|
||||
"""Test with valid true strings"""
|
||||
assert str_to_bool("True") is True
|
||||
assert str_to_bool("true") is True
|
||||
|
||||
def test_valid_false_strings(self):
|
||||
"""Test with valid false strings"""
|
||||
assert str_to_bool("False") is False
|
||||
assert str_to_bool("false") is False
|
||||
|
||||
def test_invalid_strings(self):
|
||||
"""Test with invalid boolean strings"""
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("TRUE")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("FALSE")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("yes")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("no")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("1")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("0")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool(" True")
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid boolean string"):
|
||||
str_to_bool("True ")
|
||||
|
||||
def test_error_message_content(self):
|
||||
"""Test that error messages contain the invalid input"""
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
str_to_bool("invalid")
|
||||
assert "Invalid boolean string: invalid" in str(exc_info.value)
|
||||
|
||||
def test_case_sensitivity(self):
|
||||
"""Test that function is case sensitive"""
|
||||
with pytest.raises(ValueError):
|
||||
str_to_bool("TRUE")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
str_to_bool("True ") # with space
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
str_to_bool(" True") # with space
|
||||
|
||||
|
||||
# Additional edge case tests
|
||||
class TestEdgeCases:
|
||||
"""Test edge cases and special scenarios"""
|
||||
|
||||
def test_is_int_with_whitespace(self):
|
||||
"""Test is_int with whitespace (should work due to int() behavior)"""
|
||||
assert is_int(" 123 ") is True
|
||||
assert is_int("\t456\n") is True
|
||||
|
||||
def test_is_float_with_whitespace(self):
|
||||
"""Test is_float with whitespace (should work due to float() behavior)"""
|
||||
assert is_float(" 12.34 ") is True
|
||||
assert is_float("\t45.67\n") is True
|
||||
|
||||
def test_large_numbers(self):
|
||||
"""Test with very large numbers"""
|
||||
large_int = "123456789012345678901234567890"
|
||||
assert is_int(large_int) is True
|
||||
assert is_float(large_int) is True
|
||||
|
||||
def test_scientific_notation(self):
|
||||
"""Test scientific notation"""
|
||||
assert is_int("1e5") is False # int() doesn't handle scientific notation
|
||||
assert is_float("1e5") is True
|
||||
assert is_float("1.5e-10") is True
|
||||
assert is_float("2E+3") is True
|
||||
|
||||
|
||||
# Parametrized tests for more comprehensive coverage
|
||||
class TestParametrized:
|
||||
"""Parametrized tests for better coverage"""
|
||||
|
||||
@pytest.mark.parametrize("value,expected", [
|
||||
("123", True),
|
||||
("0", True),
|
||||
("-456", True),
|
||||
("12.34", False),
|
||||
("abc", False),
|
||||
("", False),
|
||||
(123, True),
|
||||
(12.5, True),
|
||||
(None, False),
|
||||
])
|
||||
def test_is_int_parametrized(self, value: Any, expected: bool):
|
||||
"""Test"""
|
||||
assert is_int(value) == expected
|
||||
|
||||
@pytest.mark.parametrize("value,expected", [
|
||||
("12.34", True),
|
||||
("123", True),
|
||||
("0", True),
|
||||
("-45.67", True),
|
||||
("inf", True),
|
||||
("nan", True),
|
||||
("abc", False),
|
||||
("", False),
|
||||
(12.34, True),
|
||||
(123, True),
|
||||
(None, False),
|
||||
])
|
||||
def test_is_float_parametrized(self, value: Any, expected: bool):
|
||||
"""test"""
|
||||
assert is_float(value) == expected
|
||||
|
||||
@pytest.mark.parametrize("value,expected", [
|
||||
("True", True),
|
||||
("true", True),
|
||||
("False", False),
|
||||
("false", False),
|
||||
])
|
||||
def test_str_to_bool_valid_parametrized(self, value: Any, expected: bool):
|
||||
"""test"""
|
||||
assert str_to_bool(value) == expected
|
||||
|
||||
@pytest.mark.parametrize("invalid_value", [
|
||||
"TRUE",
|
||||
"FALSE",
|
||||
"yes",
|
||||
"no",
|
||||
"1",
|
||||
"0",
|
||||
"",
|
||||
" True",
|
||||
"True ",
|
||||
"invalid",
|
||||
])
|
||||
def test_str_to_bool_invalid_parametrized(self, invalid_value: Any):
|
||||
"""test"""
|
||||
with pytest.raises(ValueError):
|
||||
str_to_bool(invalid_value)
|
||||
Reference in New Issue
Block a user