Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
743a0a8ac9 | ||
|
|
694712ed2e | ||
|
|
ea3b4f1790 | ||
|
|
da68818d4f |
@@ -1,7 +1,7 @@
|
|||||||
# MARK: Project info
|
# MARK: Project info
|
||||||
[project]
|
[project]
|
||||||
name = "corelibs"
|
name = "corelibs"
|
||||||
version = "0.13.1"
|
version = "0.14.0"
|
||||||
description = "Collection of utils for Python scripts"
|
description = "Collection of utils for Python scripts"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|||||||
@@ -5,10 +5,33 @@ List of regex compiled strings that can be used
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
EMAIL_REGEX_BASIC = r"""
|
def compile_re(reg: str) -> re.Pattern[str]:
|
||||||
|
"""
|
||||||
|
compile a regex with verbose flag
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
reg {str} -- _description_
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
re.Pattern[str] -- _description_
|
||||||
|
"""
|
||||||
|
return re.compile(reg, re.VERBOSE)
|
||||||
|
|
||||||
|
|
||||||
|
# email regex
|
||||||
|
EMAIL_BASIC_REGEX = r"""
|
||||||
^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}
|
^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}
|
||||||
@(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[a-zA-Z]{2,6}$
|
@(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[a-zA-Z]{2,6}$
|
||||||
"""
|
"""
|
||||||
EMAIL_REGEX_BASIC_COMPILED = re.compile(EMAIL_REGEX_BASIC)
|
# Domain regex with localhost
|
||||||
|
DOMAIN_WITH_LOCALHOST_REGEX = r"""
|
||||||
|
^(?:localhost|(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[A-Za-z]{2,})$
|
||||||
|
"""
|
||||||
|
# domain regex with loclhost and optional port
|
||||||
|
DOMAIN_WITH_LOCALHOST_PORT_REGEX = r"""
|
||||||
|
^(?:localhost|(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[A-Za-z]{2,})(?::\d+)?$
|
||||||
|
"""
|
||||||
|
# Domain, no localhost
|
||||||
|
DOMAIN_REGEX = r"^(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[A-Za-z]{2,}$"
|
||||||
|
|
||||||
# __END__
|
# __END__
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ Class of checks that can be run on value entries
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
from corelibs.check_handling.regex_constants import EMAIL_REGEX_BASIC
|
from corelibs.check_handling.regex_constants import (
|
||||||
|
EMAIL_BASIC_REGEX, DOMAIN_WITH_LOCALHOST_REGEX, DOMAIN_WITH_LOCALHOST_PORT_REGEX, DOMAIN_REGEX
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SettingsLoaderCheckValue(TypedDict):
|
class SettingsLoaderCheckValue(TypedDict):
|
||||||
@@ -45,27 +47,25 @@ class SettingsLoaderCheck:
|
|||||||
},
|
},
|
||||||
# This does a baisc email check, only alphanumeric with special characters
|
# This does a baisc email check, only alphanumeric with special characters
|
||||||
"string.email.basic": {
|
"string.email.basic": {
|
||||||
"regex": EMAIL_REGEX_BASIC,
|
"regex": EMAIL_BASIC_REGEX,
|
||||||
"regex_clean": None,
|
"regex_clean": None,
|
||||||
"replace": "",
|
"replace": "",
|
||||||
},
|
},
|
||||||
# Domain check, including localhost no port
|
# Domain check, including localhost no port
|
||||||
"string.domain.with-localhost": {
|
"string.domain.with-localhost": {
|
||||||
"regex": r"^(?:localhost|(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[A-Za-z]{2,})$",
|
"regex": DOMAIN_WITH_LOCALHOST_REGEX,
|
||||||
"regex_clean": None,
|
"regex_clean": None,
|
||||||
"replace": "",
|
"replace": "",
|
||||||
},
|
},
|
||||||
# Domain check, with localhost and port
|
# Domain check, with localhost and port
|
||||||
"string.domain.with-localhost.port": {
|
"string.domain.with-localhost.port": {
|
||||||
"regex": r"""
|
"regex": DOMAIN_WITH_LOCALHOST_PORT_REGEX,
|
||||||
^(?:localhost|(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[A-Za-z]{2,})(?::\d+)?$
|
|
||||||
""",
|
|
||||||
"regex_clean": None,
|
"regex_clean": None,
|
||||||
"replace": "",
|
"replace": "",
|
||||||
},
|
},
|
||||||
# Domain check, no pure localhost allowed
|
# Domain check, no pure localhost allowed
|
||||||
"string.domain": {
|
"string.domain": {
|
||||||
"regex": r"^(?!-)[A-Za-z0-9-]{1,63}(?<!-)(?:\.[A-Za-z0-9-]{1,63}(?<!-))*\.[A-Za-z]{2,}$",
|
"regex": DOMAIN_REGEX,
|
||||||
"regex_clean": None,
|
"regex_clean": None,
|
||||||
"replace": "",
|
"replace": "",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -73,11 +73,32 @@ class CustomConsoleFormatter(logging.Formatter):
|
|||||||
message = super().format(record)
|
message = super().format(record)
|
||||||
return f"{color}{message}{reset}"
|
return f"{color}{message}{reset}"
|
||||||
|
|
||||||
|
|
||||||
# TODO: add custom handlers for stack_trace, if not set fill with %(filename)s:%(funcName)s:%(lineno)d
|
# TODO: add custom handlers for stack_trace, if not set fill with %(filename)s:%(funcName)s:%(lineno)d
|
||||||
# hasattr(record, 'stack_trace')
|
# hasattr(record, 'stack_trace')
|
||||||
|
|
||||||
|
|
||||||
|
class CustomHandlerFilter(logging.Filter):
|
||||||
|
"""
|
||||||
|
Add a custom handler for filtering
|
||||||
|
"""
|
||||||
|
def __init__(self, handler_name: str, filter_exceptions: bool = False):
|
||||||
|
super().__init__(name=handler_name)
|
||||||
|
self.handler_name = handler_name
|
||||||
|
self.filter_exceptions = filter_exceptions
|
||||||
|
|
||||||
|
def filter(self, record: logging.LogRecord) -> bool:
|
||||||
|
# if console and exception do not show
|
||||||
|
if self.handler_name == 'console' and self.filter_exceptions:
|
||||||
|
return record.levelname != "EXCEPTION"
|
||||||
|
# if cnosole entry is true and traget file filter
|
||||||
|
if hasattr(record, 'console') and getattr(record, 'console') is True and self.handler_name == 'file':
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
# def __filter_exceptions(self, record: logging.LogRecord) -> bool:
|
||||||
|
# return record.levelname != "EXCEPTION"
|
||||||
|
|
||||||
|
|
||||||
# MARK: Log class
|
# MARK: Log class
|
||||||
class Log:
|
class Log:
|
||||||
"""
|
"""
|
||||||
@@ -142,7 +163,7 @@ class Log:
|
|||||||
# in the file writer too, for the ones where color is set BEFORE the format
|
# in the file writer too, for the ones where color is set BEFORE the format
|
||||||
# Any is logging.StreamHandler, logging.FileHandler and all logging.handlers.*
|
# Any is logging.StreamHandler, logging.FileHandler and all logging.handlers.*
|
||||||
self.handlers: dict[str, Any] = {}
|
self.handlers: dict[str, Any] = {}
|
||||||
self.add_handler('file_handler', self.__create_time_rotating_file_handler(
|
self.add_handler('file_handler', self.__create_timed_rotating_file_handler(
|
||||||
self.log_settings['log_level_file'], log_path)
|
self.log_settings['log_level_file'], log_path)
|
||||||
)
|
)
|
||||||
if self.log_settings['console_enabled']:
|
if self.log_settings['console_enabled']:
|
||||||
@@ -211,8 +232,8 @@ class Log:
|
|||||||
default_log_settings['log_queue'] = __setting
|
default_log_settings['log_queue'] = __setting
|
||||||
return default_log_settings
|
return default_log_settings
|
||||||
|
|
||||||
def __filter_exceptions(self, record: logging.LogRecord) -> bool:
|
# def __filter_exceptions(self, record: logging.LogRecord) -> bool:
|
||||||
return record.levelname != "EXCEPTION"
|
# return record.levelname != "EXCEPTION"
|
||||||
|
|
||||||
# MARK: add a handler
|
# MARK: add a handler
|
||||||
def add_handler(
|
def add_handler(
|
||||||
@@ -259,16 +280,15 @@ class Log:
|
|||||||
formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date)
|
formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date)
|
||||||
else:
|
else:
|
||||||
formatter_console = logging.Formatter(format_string, datefmt=format_date)
|
formatter_console = logging.Formatter(format_string, datefmt=format_date)
|
||||||
console_handler.setLevel(log_level_console.name)
|
|
||||||
console_handler.set_name('console')
|
console_handler.set_name('console')
|
||||||
|
console_handler.setLevel(log_level_console.name)
|
||||||
# do not show exceptions logs on console
|
# do not show exceptions logs on console
|
||||||
if filter_exceptions:
|
console_handler.addFilter(CustomHandlerFilter('console', filter_exceptions))
|
||||||
console_handler.addFilter(self.__filter_exceptions)
|
|
||||||
console_handler.setFormatter(formatter_console)
|
console_handler.setFormatter(formatter_console)
|
||||||
return console_handler
|
return console_handler
|
||||||
|
|
||||||
# MARK: file handler
|
# MARK: file handler
|
||||||
def __create_time_rotating_file_handler(
|
def __create_timed_rotating_file_handler(
|
||||||
self, log_level_file: LoggingLevel, log_path: Path,
|
self, log_level_file: LoggingLevel, log_path: Path,
|
||||||
when: str = "D", interval: int = 1, backup_count: int = 0
|
when: str = "D", interval: int = 1, backup_count: int = 0
|
||||||
) -> logging.handlers.TimedRotatingFileHandler:
|
) -> logging.handlers.TimedRotatingFileHandler:
|
||||||
@@ -304,6 +324,8 @@ class Log:
|
|||||||
)
|
)
|
||||||
file_handler.set_name('file_timed_rotate')
|
file_handler.set_name('file_timed_rotate')
|
||||||
file_handler.setLevel(log_level_file.name)
|
file_handler.setLevel(log_level_file.name)
|
||||||
|
# do not show errors flagged with console (they are from exceptions)
|
||||||
|
file_handler.addFilter(CustomHandlerFilter('file'))
|
||||||
file_handler.setFormatter(formatter_file_handler)
|
file_handler.setFormatter(formatter_file_handler)
|
||||||
return file_handler
|
return file_handler
|
||||||
|
|
||||||
@@ -454,7 +476,11 @@ class Log:
|
|||||||
self.logger.log(LoggingLevel.EMERGENCY.value, msg, *args, extra=extra, stacklevel=2)
|
self.logger.log(LoggingLevel.EMERGENCY.value, msg, *args, extra=extra, stacklevel=2)
|
||||||
|
|
||||||
# MARK: EXCEPTION: 70
|
# MARK: EXCEPTION: 70
|
||||||
def exception(self, msg: object, *args: object, extra: MutableMapping[str, object] | None = None) -> None:
|
def exception(
|
||||||
|
self,
|
||||||
|
msg: object, *args: object, extra: MutableMapping[str, object] | None = None,
|
||||||
|
log_error: bool = True
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
log on exceotion level, this is log.exception, but logs with a new level
|
log on exceotion level, this is log.exception, but logs with a new level
|
||||||
|
|
||||||
@@ -462,12 +488,19 @@ class Log:
|
|||||||
msg (object): _description_
|
msg (object): _description_
|
||||||
*args (object): arguments for msg
|
*args (object): arguments for msg
|
||||||
extra: Mapping[str, object] | None: extra arguments for the formatting if needed
|
extra: Mapping[str, object] | None: extra arguments for the formatting if needed
|
||||||
|
log_error: (bool): If set to false will not write additional error message for console (Default True)
|
||||||
"""
|
"""
|
||||||
if not hasattr(self, 'logger'):
|
if not hasattr(self, 'logger'):
|
||||||
raise ValueError('Logger is not yet initialized')
|
raise ValueError('Logger is not yet initialized')
|
||||||
if extra is None:
|
if extra is None:
|
||||||
extra = {}
|
extra = {}
|
||||||
extra['stack_trace'] = traceback_call_str(start=3)
|
extra['stack_trace'] = traceback_call_str(start=3)
|
||||||
|
# write to console first with extra flag for filtering in file
|
||||||
|
if log_error:
|
||||||
|
self.logger.log(
|
||||||
|
LoggingLevel.ERROR.value,
|
||||||
|
f"<=EXCEPTION> {msg}", *args, extra=dict(extra) | {'console': True}, stacklevel=2
|
||||||
|
)
|
||||||
self.logger.log(LoggingLevel.EXCEPTION.value, msg, *args, exc_info=True, extra=extra, stacklevel=2)
|
self.logger.log(LoggingLevel.EXCEPTION.value, msg, *args, exc_info=True, extra=extra, stacklevel=2)
|
||||||
|
|
||||||
# MARK: break line
|
# MARK: break line
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ def main():
|
|||||||
print(f"Divied: {__test}")
|
print(f"Divied: {__test}")
|
||||||
except ZeroDivisionError as e:
|
except ZeroDivisionError as e:
|
||||||
log.logger.critical("Divison through zero: %s", e)
|
log.logger.critical("Divison through zero: %s", e)
|
||||||
log.exception("Divison through zero")
|
log.exception("Divison through zero: %s", e)
|
||||||
|
|
||||||
for handler in log.logger.handlers:
|
for handler in log.logger.handlers:
|
||||||
print(f"Handler (logger) {handler} -> {handler.level} -> {LoggingLevel.from_any(handler.level)}")
|
print(f"Handler (logger) {handler} -> {handler.level} -> {LoggingLevel.from_any(handler.level)}")
|
||||||
|
|||||||
Reference in New Issue
Block a user