Compare commits

...

5 Commits

Author SHA1 Message Date
Clemens Schwaighofer
29dd906fe0 v0.22.0: per run log file rotate 2025-08-01 16:04:18 +09:00
Clemens Schwaighofer
d5dc4028c3 Merge branch 'development' 2025-08-01 16:02:40 +09:00
Clemens Schwaighofer
0df049d453 Add per run log rotate flag
This flag will use the normal file handler with a file name that has date + time + milliseconds
to create a new file each time the script is run
2025-08-01 16:01:50 +09:00
Clemens Schwaighofer
0bd7c1f685 v0.21.1: Update convert time string to skip any numbers 2025-07-29 09:30:56 +09:00
Clemens Schwaighofer
2f08ecabbf For convert time string, skip convert if incoming value is a number of any type
Any float number will be rounded, and everything that is any kind of number will be then converted to int and returned
The rest will be converted to string and normal convert is run
2025-07-29 09:29:38 +09:00
7 changed files with 45 additions and 13 deletions

View File

@@ -3,3 +3,5 @@
- [x] stub files .pyi
- [ ] Add tests for all, we need 100% test coverate
- [x] Log: add custom format for "stack_correct" if set, this will override the normal stack block
- [ ] Log: add rotate for size based
- [ ] All folders and file names need to be revisited for naming and content collection

View File

@@ -1,7 +1,7 @@
# MARK: Project info
[project]
name = "corelibs"
version = "0.21.0"
version = "0.22.0"
description = "Collection of utils for Python scripts"
readme = "README.md"
requires-python = ">=3.13"

View File

@@ -7,6 +7,7 @@ attach "init_worker_logging" with the set log_queue
import re
import logging.handlers
import logging
from datetime import datetime
import time
from pathlib import Path
from typing import MutableMapping, TextIO, TypedDict, Any, TYPE_CHECKING, cast
@@ -23,6 +24,7 @@ class LogSettings(TypedDict):
"""log settings, for Log setup"""
log_level_console: LoggingLevel
log_level_file: LoggingLevel
per_run_log: bool
console_enabled: bool
console_color_output_enabled: bool
add_start_info: bool
@@ -392,6 +394,7 @@ class Log(LogParent):
DEFAULT_LOG_SETTINGS: LogSettings = {
"log_level_console": DEFAULT_LOG_LEVEL_CONSOLE,
"log_level_file": DEFAULT_LOG_LEVEL_FILE,
"per_run_log": False,
"console_enabled": True,
"console_color_output_enabled": True,
"add_start_info": True,
@@ -440,7 +443,7 @@ class Log(LogParent):
# 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.*
self.handlers: dict[str, Any] = {}
self.add_handler('file_handler', self.__create_timed_rotating_file_handler(
self.add_handler('file_handler', self.__create_file_handler(
'file_handler', self.log_settings['log_level_file'], log_path)
)
if self.log_settings['console_enabled']:
@@ -492,6 +495,7 @@ class Log(LogParent):
default_log_settings[__log_entry] = LoggingLevel.from_any(__log_level)
# check bool
for __log_entry in [
"per_run_log",
"console_enabled",
"console_color_output_enabled",
"add_start_info",
@@ -566,24 +570,35 @@ class Log(LogParent):
return console_handler
# MARK: file handler
def __create_timed_rotating_file_handler(
def __create_file_handler(
self, handler_name: str,
log_level_file: LoggingLevel, log_path: Path,
# for TimedRotating, if per_run_log is off
when: str = "D", interval: int = 1, backup_count: int = 0
) -> logging.handlers.TimedRotatingFileHandler:
) -> logging.handlers.TimedRotatingFileHandler | logging.FileHandler:
# file logger
# when: S/M/H/D/W0-W6/midnight
# interval: how many, 1D = every day
# backup_count: how many old to keep, 0 = all
if not self.validate_log_level(log_level_file):
log_level_file = self.DEFAULT_LOG_LEVEL_FILE
file_handler = logging.handlers.TimedRotatingFileHandler(
filename=log_path,
encoding="utf-8",
when=when,
interval=interval,
backupCount=backup_count
)
if self.log_settings['per_run_log']:
# log path, remove them stem (".log"), then add the datetime and add .log again
now = datetime.now()
# we add microseconds part to get milli seconds
new_stem=f"{log_path.stem}.{now.strftime('%Y-%m-%d_%H-%M-%S')}.{str(now.microsecond)[:3]}"
file_handler = logging.FileHandler(
filename=log_path.with_name(f"{new_stem}{log_path.suffix}"),
encoding="utf-8",
)
else:
file_handler = logging.handlers.TimedRotatingFileHandler(
filename=log_path,
encoding="utf-8",
when=when,
interval=interval,
backupCount=backup_count
)
formatter_file_handler = logging.Formatter(
(
# time stamp

View File

@@ -5,6 +5,7 @@ Current timestamp strings and time zones
import re
from datetime import datetime
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
from corelibs.var_handling.var_helpers import is_float
class TimeParseError(Exception):
@@ -35,7 +36,7 @@ class TimestampStrings:
self.timestamp_file = self.timestamp_now.strftime("%Y-%m-%d_%H%M%S")
def convert_to_seconds(time_string: str) -> int:
def convert_to_seconds(time_string: str | int | float) -> int:
"""
Conver a string with time units into a seconds string
The following units are allowed
@@ -53,6 +54,12 @@ def convert_to_seconds(time_string: str) -> int:
int -- _description_
"""
# skip out if this is a number of any type
# numbers will br made float, rounded and then converted to int
if is_float(time_string):
return int(round(float(time_string)))
time_string = str(time_string)
# Define time unit conversion factors
unit_factors: dict[str, int] = {
'Y': 31536000, # 365 days * 86400 seconds/day

View File

@@ -24,6 +24,7 @@ def main():
# "log_level_console": None,
"log_level_file": 'DEBUG',
# "console_color_output_enabled": False,
"per_run_log": True
}
)
logn = Logger(log.get_logger_settings())

View File

@@ -31,6 +31,13 @@ def main() -> None:
"30m 45 minutes", # minutes appears twice
"1Y 2 years", # years appears twice
"1x 2 yrs", # invalid names
123, # int
789.12, # float
456.56, # float, high
"4566", # int as string
"5551.12", # float as string
"5551.56", # float, high as string
]
for time_string in test_cases:

2
uv.lock generated
View File

@@ -44,7 +44,7 @@ wheels = [
[[package]]
name = "corelibs"
version = "0.19.1"
version = "0.21.0"
source = { editable = "." }
dependencies = [
{ name = "jmespath" },