Compare commits

...

2 Commits

Author SHA1 Message Date
Clemens Schwaighofer
af7633183c v0.36.0: Log console format settings with bitwise mask 2025-11-19 11:31:50 +09:00
Clemens Schwaighofer
1280b2f855 Log switch to bitwise flag settings for console format type
Has the following settings
TIME, TIME_SECONDS, TIME_MILLISECONDS, TIME_MICROSECONDS: enable time output in different formats
TIME and TIME_MILLISECONDS are equivalent, if multiple are set the smallest precision wins
TIMEZONE: add time zone to time output
NAME: log group name
FILE: short file name
FUNCTION: function name
LINENO: line number

There is a class with quick grouped settings
ConsoleFormatSettings
ALL: all options enabled, time is in milliseconds
CONDENSED: time without time zone, file and line number
MINIMAL: only time without time zone
BARE: only the message, no other info
2025-11-19 11:25:49 +09:00
12 changed files with 240 additions and 305 deletions

View File

@@ -1,7 +1,7 @@
# MARK: Project info # MARK: Project info
[project] [project]
name = "corelibs" name = "corelibs"
version = "0.35.2" version = "0.36.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"

View File

@@ -11,6 +11,7 @@ from datetime import datetime
import time import time
from pathlib import Path from pathlib import Path
import atexit import atexit
from enum import Flag, auto
from typing import MutableMapping, 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.logging_handling.logging_level_handling.logging_level import LoggingLevel
from corelibs.string_handling.text_colors import Colors from corelibs.string_handling.text_colors import Colors
@@ -20,6 +21,38 @@ if TYPE_CHECKING:
from multiprocessing import Queue from multiprocessing import Queue
class ConsoleFormat(Flag):
"""console format type bitmap flags"""
TIME = auto()
TIME_SECONDS = auto()
TIME_MILLISECONDS = auto()
TIME_MICROSECONDS = auto()
TIMEZONE = auto()
NAME = auto()
FILE = auto()
FUNCTION = auto()
LINENO = auto()
class ConsoleFormatSettings:
"""Console format quick settings groups"""
# shows everything, time with milliseconds, and time zone, log name, file, function, line number
ALL = (
ConsoleFormat.TIME |
ConsoleFormat.TIMEZONE |
ConsoleFormat.NAME |
ConsoleFormat.FILE |
ConsoleFormat.FUNCTION |
ConsoleFormat.LINENO
)
# show time with no time zone, file and line
CONDENSED = ConsoleFormat.TIME | ConsoleFormat.FILE | ConsoleFormat.LINENO
# only time
MINIMAL = ConsoleFormat.TIME
# only message
BARE = ConsoleFormat(0)
# MARK: Log settings TypedDict # MARK: Log settings TypedDict
class LogSettings(TypedDict): class LogSettings(TypedDict):
"""log settings, for Log setup""" """log settings, for Log setup"""
@@ -28,8 +61,7 @@ class LogSettings(TypedDict):
per_run_log: bool per_run_log: bool
console_enabled: bool console_enabled: bool
console_color_output_enabled: bool console_color_output_enabled: bool
console_format_type: str console_format_type: ConsoleFormat
console_iso_precision: str
add_start_info: bool add_start_info: bool
add_end_info: bool add_end_info: bool
log_queue: 'Queue[str] | None' log_queue: 'Queue[str] | None'
@@ -41,18 +73,6 @@ class LoggerInit(TypedDict):
log_queue: 'Queue[str] | None' log_queue: 'Queue[str] | None'
# show log title, file, function and line number types
CONSOLE_FORMAT_TYPE_NORMAL = 'normal'
# show file and line number only
CONSOLE_FORMAT_TYPE_CONDENSED = 'condensed'
# only show timestamp, log level and message
CONSOLE_FORMAT_TYPE_MINIMAL = 'minimal'
# for console ISO time format
CONSOLE_ISO_TIME_SECONDS = 'seconds'
CONSOLE_ISO_TIME_MILLISECONDS = 'milliseconds'
CONSOLE_ISO_TIME_MICROSECONDS = 'microseconds'
# MARK: Custom color filter # MARK: Custom color filter
class CustomConsoleFormatter(logging.Formatter): class CustomConsoleFormatter(logging.Formatter):
""" """
@@ -70,21 +90,6 @@ class CustomConsoleFormatter(logging.Formatter):
LoggingLevel.EXCEPTION.name: Colors.magenta_bright, # will never be written to console LoggingLevel.EXCEPTION.name: Colors.magenta_bright, # will never be written to console
} }
# def formatTime(self, record: logging.LogRecord, datefmt: str | None = None):
# """
# Set timestamp in ISO8601 format
# Arguments:
# record {logging.LogRecord} -- _description_
# Keyword Arguments:
# datefmt {str | None} -- _description_ (default: {None})
# Returns:
# _type_ -- _description_
# """
# return datetime.fromtimestamp(record.created).astimezone().isoformat(sep=' ', timespec='milliseconds')
def format(self, record: logging.LogRecord) -> str: def format(self, record: logging.LogRecord) -> str:
""" """
set the color highlight set the color highlight
@@ -439,8 +444,7 @@ class Log(LogParent):
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": True, "console_color_output_enabled": True,
# do not print log title, file, function and line number # do not print log title, file, function and line number
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": True, "add_start_info": True,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,
@@ -451,7 +455,10 @@ class Log(LogParent):
self, self,
log_path: Path, log_path: Path,
log_name: str, log_name: str,
log_settings: dict[str, 'LoggingLevel | str | bool | None | Queue[str]'] | LogSettings | None = None, log_settings: (
dict[str, 'LoggingLevel | str | bool | None | Queue[str] | ConsoleFormat'] | # noqa: E501 # pylint: disable=line-too-long
LogSettings | None
) = None,
other_handlers: dict[str, Any] | None = None other_handlers: dict[str, Any] | None = None
): ):
LogParent.__init__(self) LogParent.__init__(self)
@@ -496,7 +503,6 @@ class Log(LogParent):
'stream_handler', 'stream_handler',
self.log_settings['log_level_console'], self.log_settings['log_level_console'],
console_format_type=self.log_settings['console_format_type'], console_format_type=self.log_settings['console_format_type'],
console_iso_precision=self.log_settings['console_iso_precision']
)) ))
# add other handlers, # add other handlers,
if other_handlers is not None: if other_handlers is not None:
@@ -523,7 +529,8 @@ class Log(LogParent):
# MARK: parse log settings # MARK: parse log settings
def __parse_log_settings( def __parse_log_settings(
self, self,
log_settings: dict[str, 'LoggingLevel | str | bool | None | Queue[str]'] | LogSettings | None log_settings: dict[str, 'LoggingLevel | str | bool | None | Queue[str] | ConsoleFormat'] | # noqa: E501 # pylint: disable=line-too-long
LogSettings | None
) -> LogSettings: ) -> LogSettings:
# skip with defaul it not set # skip with defaul it not set
if log_settings is None: if log_settings is None:
@@ -554,26 +561,9 @@ class Log(LogParent):
__setting = self.DEFAULT_LOG_SETTINGS.get(__log_entry, True) __setting = self.DEFAULT_LOG_SETTINGS.get(__log_entry, True)
default_log_settings[__log_entry] = __setting default_log_settings[__log_entry] = __setting
# check console log type # check console log type
default_log_settings['console_format_type'] = cast('str', log_settings.get( default_log_settings['console_format_type'] = cast('ConsoleFormat', log_settings.get(
'console_format_type', self.DEFAULT_LOG_SETTINGS['console_format_type'] 'console_format_type', self.DEFAULT_LOG_SETTINGS['console_format_type']
)) ))
# if not valid
if default_log_settings['console_format_type'] not in [
CONSOLE_FORMAT_TYPE_NORMAL,
CONSOLE_FORMAT_TYPE_CONDENSED,
CONSOLE_FORMAT_TYPE_MINIMAL,
]:
default_log_settings['console_format_type'] = self.DEFAULT_LOG_SETTINGS['console_format_type']
# check console iso time precision
default_log_settings['console_iso_precision'] = cast('str', log_settings.get(
'console_iso_precision', self.DEFAULT_LOG_SETTINGS['console_iso_precision']
))
if default_log_settings['console_iso_precision'] not in [
CONSOLE_ISO_TIME_SECONDS,
CONSOLE_ISO_TIME_MILLISECONDS,
CONSOLE_ISO_TIME_MICROSECONDS,
]:
default_log_settings['console_iso_precision'] = self.DEFAULT_LOG_SETTINGS['console_iso_precision']
# check log queue # check log queue
__setting = log_settings.get('log_queue', self.DEFAULT_LOG_SETTINGS['log_queue']) __setting = log_settings.get('log_queue', self.DEFAULT_LOG_SETTINGS['log_queue'])
if __setting is not None: if __setting is not None:
@@ -612,51 +602,89 @@ class Log(LogParent):
self, handler_name: str, self, handler_name: str,
log_level_console: LoggingLevel = LoggingLevel.WARNING, log_level_console: LoggingLevel = LoggingLevel.WARNING,
filter_exceptions: bool = True, filter_exceptions: bool = True,
console_format_type: str = CONSOLE_FORMAT_TYPE_NORMAL, console_format_type: ConsoleFormat = ConsoleFormatSettings.ALL,
console_iso_precision: str = CONSOLE_ISO_TIME_MILLISECONDS
) -> logging.StreamHandler[TextIO]: ) -> logging.StreamHandler[TextIO]:
# console logger # console logger
if not self.validate_log_level(log_level_console): if not self.validate_log_level(log_level_console):
log_level_console = self.DEFAULT_LOG_LEVEL_CONSOLE log_level_console = self.DEFAULT_LOG_LEVEL_CONSOLE
console_handler = logging.StreamHandler() console_handler = logging.StreamHandler()
# format layouts print(f"Console format type: {console_format_type}")
format_string = ( # build the format string based on what flags are set
# '[%(asctime)s.%(msecs)03d] ' format_string = ''
'[%(asctime)s] ' # time part if any of the times are requested
'[%(name)s] ' if (
'[%(filename)s:%(funcName)s:%(lineno)d] ' ConsoleFormat.TIME in console_format_type or
'<%(levelname)s> ' ConsoleFormat.TIME_SECONDS in console_format_type or
'%(message)s' ConsoleFormat.TIME_MILLISECONDS in console_format_type or
) ConsoleFormat.TIME_MICROSECONDS in console_format_type
if console_format_type == CONSOLE_FORMAT_TYPE_CONDENSED: ):
format_string = ( format_string += '[%(asctime)s] '
'[%(asctime)s] ' # set log name
'[%(filename)s:%(lineno)d] ' if ConsoleFormat.NAME in console_format_type:
'<%(levelname)s> ' format_string += '[%(name)s] '
'%(message)s' # for any file/function/line number call
) if (
elif console_format_type == CONSOLE_FORMAT_TYPE_MINIMAL: ConsoleFormat.FILE in console_format_type or
format_string = ( ConsoleFormat.FUNCTION in console_format_type or
'[%(asctime)s] ' ConsoleFormat.LINENO in console_format_type
'<%(levelname)s> ' ):
'%(message)s' format_string += '['
) set_group: list[str] = []
format_date = "%Y-%m-%d %H:%M:%S" if ConsoleFormat.FILE in console_format_type:
set_group.append('%(filename)s')
if ConsoleFormat.FUNCTION in console_format_type:
set_group.append('%(funcName)s')
if ConsoleFormat.LINENO in console_format_type:
set_group.append('%(lineno)d')
format_string += ':'.join(set_group)
format_string += '] '
# always level + message
format_string += '<%(levelname)s> %(message)s'
# basic date, but this will be overridden to ISO in formatTime
# format_date = "%Y-%m-%d %H:%M:%S"
# color or not # color or not
if self.log_settings['console_color_output_enabled']: if self.log_settings['console_color_output_enabled']:
formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date) # formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date)
formatter_console = CustomConsoleFormatter(format_string)
else: else:
formatter_console = logging.Formatter(format_string, datefmt=format_date) # formatter_console = logging.Formatter(format_string, datefmt=format_date)
print(f"PREC: {console_iso_precision}") formatter_console = logging.Formatter(format_string)
# this one needs lambda self, ... # default for TIME is milliseconds
# logging.Formatter.formatTime = ( # if we have multiple set, the smallest precision wins
formatter_console.formatTime = ( if ConsoleFormat.TIME_MICROSECONDS in console_format_type:
lambda record, datefmt=None: iso_precision = 'microseconds'
datetime elif (
.fromtimestamp(record.created) ConsoleFormat.TIME_MILLISECONDS in console_format_type or
.astimezone() ConsoleFormat.TIME in console_format_type
.isoformat(sep="T", timespec=console_iso_precision) ):
) iso_precision = 'milliseconds'
elif ConsoleFormat.TIME_SECONDS in console_format_type:
iso_precision = 'seconds'
else:
iso_precision = 'milliseconds'
# do timestamp modification only if we have time requested
if (
ConsoleFormat.TIME in console_format_type or
ConsoleFormat.TIME_SECONDS in console_format_type or
ConsoleFormat.TIME_MILLISECONDS in console_format_type or
ConsoleFormat.TIME_MICROSECONDS in console_format_type
):
# if we have with TZ we as the asttimezone call
if ConsoleFormat.TIMEZONE in console_format_type:
formatter_console.formatTime = (
lambda record, datefmt=None:
datetime
.fromtimestamp(record.created)
.astimezone()
.isoformat(sep=" ", timespec=iso_precision)
)
else:
formatter_console.formatTime = (
lambda record, datefmt=None:
datetime
.fromtimestamp(record.created)
.isoformat(sep=" ", timespec=iso_precision)
)
console_handler.set_name(handler_name) console_handler.set_name(handler_name)
console_handler.setLevel(log_level_console.name) console_handler.setLevel(log_level_console.name)
# do not show exceptions logs on console # do not show exceptions logs on console

View File

@@ -6,7 +6,7 @@ Log logging_handling.log testing
import sys import sys
from pathlib import Path from pathlib import Path
# this is for testing only # this is for testing only
from corelibs.logging_handling.log import Log, Logger, CONSOLE_FORMAT_TYPE_MINIMAL, CONSOLE_ISO_TIME_MICROSECONDS from corelibs.logging_handling.log import Log, Logger, ConsoleFormat, ConsoleFormatSettings
from corelibs.debug_handling.debug_helpers import exception_stack, call_stack from corelibs.debug_handling.debug_helpers import exception_stack, call_stack
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
@@ -25,13 +25,19 @@ def main():
"log_level_file": 'DEBUG', "log_level_file": 'DEBUG',
# "console_color_output_enabled": False, # "console_color_output_enabled": False,
"per_run_log": True, "per_run_log": True,
# Set console log type # Set console log type, must be sent as value for ConsoleFormat or bitwise of ConsoleFormatType
"console_format_type": CONSOLE_FORMAT_TYPE_MINIMAL, # "console_format_type": ConsoleFormatSettings.BARE,
"console_iso_precision": CONSOLE_ISO_TIME_MICROSECONDS, # "console_format_type": ConsoleFormatSettings.MINIMAL,
# "console_format_type": ConsoleFormatType.TIME_MICROSECONDS | ConsoleFormatType.NAME,
# "console_format_type": ConsoleFormatType.NAME,
"console_format_type": ConsoleFormat.TIME | ConsoleFormat.TIMEZONE | ConsoleFormat.LINENO,
} }
) )
logn = Logger(log.get_logger_settings()) logn = Logger(log.get_logger_settings())
log.info("ConsoleFormatType FILE is: %s", ConsoleFormat.FILE)
log.info("ConsoleFormatSettings ALL is: %s", ConsoleFormatSettings.ALL)
log.logger.debug('[NORMAL] Debug test: %s', log.logger.name) log.logger.debug('[NORMAL] Debug test: %s', log.logger.name)
log.lg.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.debug('[NORMAL-] Debug test: %s', log.logger.name)

View File

@@ -11,12 +11,7 @@ from corelibs.logging_handling.log import (
Log, Log,
LogParent, LogParent,
LogSettings, LogSettings,
CONSOLE_FORMAT_TYPE_NORMAL, ConsoleFormatSettings,
CONSOLE_FORMAT_TYPE_CONDENSED,
CONSOLE_FORMAT_TYPE_MINIMAL,
CONSOLE_ISO_TIME_MILLISECONDS,
CONSOLE_ISO_TIME_SECONDS,
CONSOLE_ISO_TIME_MICROSECONDS,
) )
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
@@ -39,8 +34,7 @@ def basic_log_settings() -> LogSettings:
"per_run_log": False, "per_run_log": False,
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,
@@ -107,10 +101,10 @@ class TestLogSettingsParsing:
assert log.log_settings["console_enabled"] == Log.DEFAULT_LOG_SETTINGS["console_enabled"] assert log.log_settings["console_enabled"] == Log.DEFAULT_LOG_SETTINGS["console_enabled"]
assert log.log_settings["per_run_log"] == Log.DEFAULT_LOG_SETTINGS["per_run_log"] assert log.log_settings["per_run_log"] == Log.DEFAULT_LOG_SETTINGS["per_run_log"]
def test_parse_console_format_type_normal(self, tmp_log_path: Path): def test_parse_console_format_type_all(self, tmp_log_path: Path):
"""Test parsing with console_format_type set to normal""" """Test parsing with console_format_type set to ALL"""
settings: dict[str, Any] = { settings: dict[str, Any] = {
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
} }
log = Log( log = Log(
log_path=tmp_log_path, log_path=tmp_log_path,
@@ -118,12 +112,12 @@ class TestLogSettingsParsing:
log_settings=settings # type: ignore log_settings=settings # type: ignore
) )
assert log.log_settings["console_format_type"] == CONSOLE_FORMAT_TYPE_NORMAL assert log.log_settings["console_format_type"] == ConsoleFormatSettings.ALL
def test_parse_console_format_type_condensed(self, tmp_log_path: Path): def test_parse_console_format_type_condensed(self, tmp_log_path: Path):
"""Test parsing with console_format_type set to condensed""" """Test parsing with console_format_type set to CONDENSED"""
settings: dict[str, Any] = { settings: dict[str, Any] = {
"console_format_type": CONSOLE_FORMAT_TYPE_CONDENSED, "console_format_type": ConsoleFormatSettings.CONDENSED,
} }
log = Log( log = Log(
log_path=tmp_log_path, log_path=tmp_log_path,
@@ -131,12 +125,12 @@ class TestLogSettingsParsing:
log_settings=settings # type: ignore log_settings=settings # type: ignore
) )
assert log.log_settings["console_format_type"] == CONSOLE_FORMAT_TYPE_CONDENSED assert log.log_settings["console_format_type"] == ConsoleFormatSettings.CONDENSED
def test_parse_console_format_type_minimal(self, tmp_log_path: Path): def test_parse_console_format_type_minimal(self, tmp_log_path: Path):
"""Test parsing with console_format_type set to minimal""" """Test parsing with console_format_type set to MINIMAL"""
settings: dict[str, Any] = { settings: dict[str, Any] = {
"console_format_type": CONSOLE_FORMAT_TYPE_MINIMAL, "console_format_type": ConsoleFormatSettings.MINIMAL,
} }
log = Log( log = Log(
log_path=tmp_log_path, log_path=tmp_log_path,
@@ -144,105 +138,34 @@ class TestLogSettingsParsing:
log_settings=settings # type: ignore log_settings=settings # type: ignore
) )
assert log.log_settings["console_format_type"] == CONSOLE_FORMAT_TYPE_MINIMAL assert log.log_settings["console_format_type"] == ConsoleFormatSettings.MINIMAL
def test_parse_console_format_type_bare(self, tmp_log_path: Path):
"""Test parsing with console_format_type set to BARE"""
settings: dict[str, Any] = {
"console_format_type": ConsoleFormatSettings.BARE,
}
log = Log(
log_path=tmp_log_path,
log_name="test",
log_settings=settings # type: ignore
)
assert log.log_settings["console_format_type"] == ConsoleFormatSettings.BARE
def test_parse_console_format_type_invalid(self, tmp_log_path: Path): def test_parse_console_format_type_invalid(self, tmp_log_path: Path):
"""Test parsing with invalid console_format_type falls back to default""" """Test parsing with invalid console_format_type raises TypeError"""
settings: dict[str, Any] = { settings: dict[str, Any] = {
"console_format_type": "invalid_format", "console_format_type": "invalid_format",
} }
log = Log( # Invalid console_format_type causes TypeError during handler creation
log_path=tmp_log_path, # because the code doesn't validate the type before using it
log_name="test", with pytest.raises(TypeError, match="'in <string>' requires string as left operand"):
log_settings=settings # type: ignore Log(
) log_path=tmp_log_path,
log_name="test",
# Should fall back to default log_settings=settings # type: ignore
assert log.log_settings["console_format_type"] == Log.DEFAULT_LOG_SETTINGS["console_format_type"] )
def test_parse_console_iso_precision_seconds(self, tmp_log_path: Path):
"""Test parsing with console_iso_precision set to seconds"""
settings: dict[str, Any] = {
"console_iso_precision": CONSOLE_ISO_TIME_SECONDS,
}
log = Log(
log_path=tmp_log_path,
log_name="test",
log_settings=settings # type: ignore
)
assert log.log_settings["console_iso_precision"] == CONSOLE_ISO_TIME_SECONDS
def test_parse_console_iso_precision_milliseconds(self, tmp_log_path: Path):
"""Test parsing with console_iso_precision set to milliseconds"""
settings: dict[str, Any] = {
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
}
log = Log(
log_path=tmp_log_path,
log_name="test",
log_settings=settings # type: ignore
)
assert log.log_settings["console_iso_precision"] == CONSOLE_ISO_TIME_MILLISECONDS
def test_parse_console_iso_precision_microseconds(self, tmp_log_path: Path):
"""Test parsing with console_iso_precision set to microseconds"""
settings: dict[str, Any] = {
"console_iso_precision": CONSOLE_ISO_TIME_MICROSECONDS,
}
log = Log(
log_path=tmp_log_path,
log_name="test",
log_settings=settings # type: ignore
)
assert log.log_settings["console_iso_precision"] == CONSOLE_ISO_TIME_MICROSECONDS
def test_parse_console_iso_precision_invalid(self, tmp_log_path: Path):
"""Test parsing with invalid console_iso_precision falls back to default"""
settings: dict[str, Any] = {
"console_iso_precision": "invalid_precision",
}
log = Log(
log_path=tmp_log_path,
log_name="test",
log_settings=settings # type: ignore
)
# Should fall back to default
assert log.log_settings["console_iso_precision"] == Log.DEFAULT_LOG_SETTINGS["console_iso_precision"]
def test_parse_both_console_settings_valid(self, tmp_log_path: Path):
"""Test parsing with both console_format_type and console_iso_precision set"""
settings: dict[str, Any] = {
"console_format_type": CONSOLE_FORMAT_TYPE_CONDENSED,
"console_iso_precision": CONSOLE_ISO_TIME_MICROSECONDS,
}
log = Log(
log_path=tmp_log_path,
log_name="test",
log_settings=settings # type: ignore
)
assert log.log_settings["console_format_type"] == CONSOLE_FORMAT_TYPE_CONDENSED
assert log.log_settings["console_iso_precision"] == CONSOLE_ISO_TIME_MICROSECONDS
def test_parse_both_console_settings_invalid(self, tmp_log_path: Path):
"""Test parsing with both console settings invalid falls back to defaults"""
settings: dict[str, Any] = {
"console_format_type": "invalid_format",
"console_iso_precision": "invalid_precision",
}
log = Log(
log_path=tmp_log_path,
log_name="test",
log_settings=settings # type: ignore
)
# Should fall back to defaults
assert log.log_settings["console_format_type"] == Log.DEFAULT_LOG_SETTINGS["console_format_type"]
assert log.log_settings["console_iso_precision"] == Log.DEFAULT_LOG_SETTINGS["console_iso_precision"]
# MARK: Test Spacer Constants # MARK: Test Spacer Constants
@@ -305,8 +228,7 @@ class TestParametrized:
("per_run_log", True, "not_bool"), ("per_run_log", True, "not_bool"),
("console_enabled", False, 123), ("console_enabled", False, 123),
("console_color_output_enabled", True, None), ("console_color_output_enabled", True, None),
("console_format_type", CONSOLE_FORMAT_TYPE_NORMAL, "invalid_format"), ("console_format_type", ConsoleFormatSettings.ALL, "invalid_format"),
("console_iso_precision", CONSOLE_ISO_TIME_MILLISECONDS, "invalid_precision"),
("add_start_info", False, []), ("add_start_info", False, []),
("add_end_info", True, {}), ("add_end_info", True, {}),
]) ])

View File

@@ -13,8 +13,7 @@ from corelibs.logging_handling.log import (
LogParent, LogParent,
LogSettings, LogSettings,
CustomConsoleFormatter, CustomConsoleFormatter,
CONSOLE_FORMAT_TYPE_NORMAL, ConsoleFormatSettings,
CONSOLE_ISO_TIME_MILLISECONDS,
) )
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
@@ -37,8 +36,7 @@ def basic_log_settings() -> LogSettings:
"per_run_log": False, "per_run_log": False,
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,
@@ -173,8 +171,7 @@ class TestLogInitialization:
"per_run_log": False, "per_run_log": False,
"console_enabled": False, "console_enabled": False,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,
@@ -196,8 +193,7 @@ class TestLogInitialization:
"per_run_log": True, "per_run_log": True,
"console_enabled": False, "console_enabled": False,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,
@@ -264,8 +260,7 @@ class TestLogInitialization:
"per_run_log": False, "per_run_log": False,
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": True, "console_color_output_enabled": True,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,

View File

@@ -11,8 +11,7 @@ from corelibs.logging_handling.log import (
Log, Log,
LogSettings, LogSettings,
CustomConsoleFormatter, CustomConsoleFormatter,
CONSOLE_FORMAT_TYPE_NORMAL, ConsoleFormatSettings,
CONSOLE_ISO_TIME_MILLISECONDS,
) )
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
@@ -35,8 +34,7 @@ def basic_log_settings() -> LogSettings:
"per_run_log": False, "per_run_log": False,
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,

View File

@@ -11,8 +11,7 @@ from corelibs.logging_handling.log import (
Log, Log,
LogSettings, LogSettings,
CustomHandlerFilter, CustomHandlerFilter,
CONSOLE_FORMAT_TYPE_NORMAL, ConsoleFormatSettings,
CONSOLE_ISO_TIME_MILLISECONDS,
) )
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
@@ -35,8 +34,7 @@ def basic_log_settings() -> LogSettings:
"per_run_log": False, "per_run_log": False,
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,

View File

@@ -11,8 +11,7 @@ from corelibs.logging_handling.log import (
Log, Log,
LogParent, LogParent,
LogSettings, LogSettings,
CONSOLE_FORMAT_TYPE_NORMAL, ConsoleFormatSettings,
CONSOLE_ISO_TIME_MILLISECONDS,
) )
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
@@ -35,8 +34,7 @@ def basic_log_settings() -> LogSettings:
"per_run_log": False, "per_run_log": False,
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,
@@ -65,8 +63,7 @@ class TestHandlerManagement:
"per_run_log": False, "per_run_log": False,
"console_enabled": False, "console_enabled": False,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,

View File

@@ -10,8 +10,7 @@ from corelibs.logging_handling.log import (
Log, Log,
Logger, Logger,
LogSettings, LogSettings,
CONSOLE_FORMAT_TYPE_NORMAL, ConsoleFormatSettings,
CONSOLE_ISO_TIME_MILLISECONDS,
) )
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
@@ -34,8 +33,7 @@ def basic_log_settings() -> LogSettings:
"per_run_log": False, "per_run_log": False,
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,

View File

@@ -10,8 +10,7 @@ import pytest
from corelibs.logging_handling.log import ( from corelibs.logging_handling.log import (
Log, Log,
LogSettings, LogSettings,
CONSOLE_FORMAT_TYPE_NORMAL, ConsoleFormatSettings,
CONSOLE_ISO_TIME_MILLISECONDS,
) )
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
@@ -34,8 +33,7 @@ def basic_log_settings() -> LogSettings:
"per_run_log": False, "per_run_log": False,
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,
@@ -92,8 +90,7 @@ class TestEdgeCases:
"per_run_log": False, "per_run_log": False,
"console_enabled": False, "console_enabled": False,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": True, # Enable end info "add_end_info": True, # Enable end info
"log_queue": None, "log_queue": None,

View File

@@ -12,8 +12,7 @@ import pytest
from corelibs.logging_handling.log import ( from corelibs.logging_handling.log import (
Log, Log,
LogSettings, LogSettings,
CONSOLE_FORMAT_TYPE_NORMAL, ConsoleFormatSettings,
CONSOLE_ISO_TIME_MILLISECONDS,
) )
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
@@ -36,8 +35,7 @@ def basic_log_settings() -> LogSettings:
"per_run_log": False, "per_run_log": False,
"console_enabled": True, "console_enabled": True,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": None, "log_queue": None,
@@ -72,8 +70,7 @@ class TestQueueListener:
"per_run_log": False, "per_run_log": False,
"console_enabled": False, "console_enabled": False,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": mock_queue, # type: ignore "log_queue": mock_queue, # type: ignore
@@ -109,8 +106,7 @@ class TestQueueListener:
"per_run_log": False, "per_run_log": False,
"console_enabled": False, "console_enabled": False,
"console_color_output_enabled": False, "console_color_output_enabled": False,
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL, "console_format_type": ConsoleFormatSettings.ALL,
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
"add_start_info": False, "add_start_info": False,
"add_end_info": False, "add_end_info": False,
"log_queue": mock_queue, # type: ignore "log_queue": mock_queue, # type: ignore

112
uv.lock generated
View File

@@ -108,7 +108,7 @@ wheels = [
[[package]] [[package]]
name = "corelibs" name = "corelibs"
version = "0.35.2" version = "0.36.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "cryptography" }, { name = "cryptography" },
@@ -143,63 +143,63 @@ dev = [
[[package]] [[package]]
name = "coverage" name = "coverage"
version = "7.11.3" version = "7.12.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d2/59/9698d57a3b11704c7b89b21d69e9d23ecf80d538cabb536c8b63f4a12322/coverage-7.11.3.tar.gz", hash = "sha256:0f59387f5e6edbbffec2281affb71cdc85e0776c1745150a3ab9b6c1d016106b", size = 815210, upload-time = "2025-11-10T00:13:17.18Z" } sdist = { url = "https://files.pythonhosted.org/packages/89/26/4a96807b193b011588099c3b5c89fbb05294e5b90e71018e065465f34eb6/coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c", size = 819341, upload-time = "2025-11-18T13:34:20.766Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/6d/f6/d8572c058211c7d976f24dab71999a565501fb5b3cdcb59cf782f19c4acb/coverage-7.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84b892e968164b7a0498ddc5746cdf4e985700b902128421bb5cec1080a6ee36", size = 216694, upload-time = "2025-11-10T00:11:34.296Z" }, { url = "https://files.pythonhosted.org/packages/b8/14/771700b4048774e48d2c54ed0c674273702713c9ee7acdfede40c2666747/coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941", size = 217725, upload-time = "2025-11-18T13:32:49.22Z" },
{ url = "https://files.pythonhosted.org/packages/4a/f6/b6f9764d90c0ce1bce8d995649fa307fff21f4727b8d950fa2843b7b0de5/coverage-7.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f761dbcf45e9416ec4698e1a7649248005f0064ce3523a47402d1bff4af2779e", size = 217065, upload-time = "2025-11-10T00:11:36.281Z" }, { url = "https://files.pythonhosted.org/packages/17/a7/3aa4144d3bcb719bf67b22d2d51c2d577bf801498c13cb08f64173e80497/coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a", size = 218098, upload-time = "2025-11-18T13:32:50.78Z" },
{ url = "https://files.pythonhosted.org/packages/a5/8d/a12cb424063019fd077b5be474258a0ed8369b92b6d0058e673f0a945982/coverage-7.11.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1410bac9e98afd9623f53876fae7d8a5db9f5a0ac1c9e7c5188463cb4b3212e2", size = 248062, upload-time = "2025-11-10T00:11:37.903Z" }, { url = "https://files.pythonhosted.org/packages/fc/9c/b846bbc774ff81091a12a10203e70562c91ae71badda00c5ae5b613527b1/coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d", size = 249093, upload-time = "2025-11-18T13:32:52.554Z" },
{ url = "https://files.pythonhosted.org/packages/7f/9c/dab1a4e8e75ce053d14259d3d7485d68528a662e286e184685ea49e71156/coverage-7.11.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:004cdcea3457c0ea3233622cd3464c1e32ebba9b41578421097402bee6461b63", size = 250657, upload-time = "2025-11-10T00:11:39.509Z" }, { url = "https://files.pythonhosted.org/packages/76/b6/67d7c0e1f400b32c883e9342de4a8c2ae7c1a0b57c5de87622b7262e2309/coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211", size = 251686, upload-time = "2025-11-18T13:32:54.862Z" },
{ url = "https://files.pythonhosted.org/packages/3f/89/a14f256438324f33bae36f9a1a7137729bf26b0a43f5eda60b147ec7c8c7/coverage-7.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f067ada2c333609b52835ca4d4868645d3b63ac04fb2b9a658c55bba7f667d3", size = 251900, upload-time = "2025-11-10T00:11:41.372Z" }, { url = "https://files.pythonhosted.org/packages/cc/75/b095bd4b39d49c3be4bffbb3135fea18a99a431c52dd7513637c0762fecb/coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d", size = 252930, upload-time = "2025-11-18T13:32:56.417Z" },
{ url = "https://files.pythonhosted.org/packages/04/07/75b0d476eb349f1296486b1418b44f2d8780cc8db47493de3755e5340076/coverage-7.11.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:07bc7745c945a6d95676953e86ba7cebb9f11de7773951c387f4c07dc76d03f5", size = 248254, upload-time = "2025-11-10T00:11:43.27Z" }, { url = "https://files.pythonhosted.org/packages/6e/f3/466f63015c7c80550bead3093aacabf5380c1220a2a93c35d374cae8f762/coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c", size = 249296, upload-time = "2025-11-18T13:32:58.074Z" },
{ url = "https://files.pythonhosted.org/packages/5a/4b/0c486581fa72873489ca092c52792d008a17954aa352809a7cbe6cf0bf07/coverage-7.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8bba7e4743e37484ae17d5c3b8eb1ce78b564cb91b7ace2e2182b25f0f764cb5", size = 250041, upload-time = "2025-11-10T00:11:45.274Z" }, { url = "https://files.pythonhosted.org/packages/27/86/eba2209bf2b7e28c68698fc13437519a295b2d228ba9e0ec91673e09fa92/coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9", size = 251068, upload-time = "2025-11-18T13:32:59.646Z" },
{ url = "https://files.pythonhosted.org/packages/af/a3/0059dafb240ae3e3291f81b8de00e9c511d3dd41d687a227dd4b529be591/coverage-7.11.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbffc22d80d86fbe456af9abb17f7a7766e7b2101f7edaacc3535501691563f7", size = 248004, upload-time = "2025-11-10T00:11:46.93Z" }, { url = "https://files.pythonhosted.org/packages/ec/55/ca8ae7dbba962a3351f18940b359b94c6bafdd7757945fdc79ec9e452dc7/coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0", size = 249034, upload-time = "2025-11-18T13:33:01.481Z" },
{ url = "https://files.pythonhosted.org/packages/83/93/967d9662b1eb8c7c46917dcc7e4c1875724ac3e73c3cb78e86d7a0ac719d/coverage-7.11.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:0dba4da36730e384669e05b765a2c49f39514dd3012fcc0398dd66fba8d746d5", size = 247828, upload-time = "2025-11-10T00:11:48.563Z" }, { url = "https://files.pythonhosted.org/packages/7a/d7/39136149325cad92d420b023b5fd900dabdd1c3a0d1d5f148ef4a8cedef5/coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508", size = 248853, upload-time = "2025-11-18T13:33:02.935Z" },
{ url = "https://files.pythonhosted.org/packages/4c/1c/5077493c03215701e212767e470b794548d817dfc6247a4718832cc71fac/coverage-7.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ae12fe90b00b71a71b69f513773310782ce01d5f58d2ceb2b7c595ab9d222094", size = 249588, upload-time = "2025-11-10T00:11:50.581Z" }, { url = "https://files.pythonhosted.org/packages/fe/b6/76e1add8b87ef60e00643b0b7f8f7bb73d4bf5249a3be19ebefc5793dd25/coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc", size = 250619, upload-time = "2025-11-18T13:33:04.336Z" },
{ url = "https://files.pythonhosted.org/packages/7f/a5/77f64de461016e7da3e05d7d07975c89756fe672753e4cf74417fc9b9052/coverage-7.11.3-cp313-cp313-win32.whl", hash = "sha256:12d821de7408292530b0d241468b698bce18dd12ecaf45316149f53877885f8c", size = 219223, upload-time = "2025-11-10T00:11:52.184Z" }, { url = "https://files.pythonhosted.org/packages/95/87/924c6dc64f9203f7a3c1832a6a0eee5a8335dbe5f1bdadcc278d6f1b4d74/coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8", size = 220261, upload-time = "2025-11-18T13:33:06.493Z" },
{ url = "https://files.pythonhosted.org/packages/ed/1c/ec51a3c1a59d225b44bdd3a4d463135b3159a535c2686fac965b698524f4/coverage-7.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:6bb599052a974bb6cedfa114f9778fedfad66854107cf81397ec87cb9b8fbcf2", size = 220033, upload-time = "2025-11-10T00:11:53.871Z" }, { url = "https://files.pythonhosted.org/packages/91/77/dd4aff9af16ff776bf355a24d87eeb48fc6acde54c907cc1ea89b14a8804/coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07", size = 221072, upload-time = "2025-11-18T13:33:07.926Z" },
{ url = "https://files.pythonhosted.org/packages/01/ec/e0ce39746ed558564c16f2cc25fa95ce6fc9fa8bfb3b9e62855d4386b886/coverage-7.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:bb9d7efdb063903b3fdf77caec7b77c3066885068bdc0d44bc1b0c171033f944", size = 218661, upload-time = "2025-11-10T00:11:55.597Z" }, { url = "https://files.pythonhosted.org/packages/70/49/5c9dc46205fef31b1b226a6e16513193715290584317fd4df91cdaf28b22/coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc", size = 219702, upload-time = "2025-11-18T13:33:09.631Z" },
{ url = "https://files.pythonhosted.org/packages/46/cb/483f130bc56cbbad2638248915d97b185374d58b19e3cc3107359715949f/coverage-7.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:fb58da65e3339b3dbe266b607bb936efb983d86b00b03eb04c4ad5b442c58428", size = 217389, upload-time = "2025-11-10T00:11:57.59Z" }, { url = "https://files.pythonhosted.org/packages/9b/62/f87922641c7198667994dd472a91e1d9b829c95d6c29529ceb52132436ad/coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87", size = 218420, upload-time = "2025-11-18T13:33:11.153Z" },
{ url = "https://files.pythonhosted.org/packages/cb/ae/81f89bae3afef75553cf10e62feb57551535d16fd5859b9ee5a2a97ddd27/coverage-7.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8d16bbe566e16a71d123cd66382c1315fcd520c7573652a8074a8fe281b38c6a", size = 217742, upload-time = "2025-11-10T00:11:59.519Z" }, { url = "https://files.pythonhosted.org/packages/85/dd/1cc13b2395ef15dbb27d7370a2509b4aee77890a464fb35d72d428f84871/coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6", size = 218773, upload-time = "2025-11-18T13:33:12.569Z" },
{ url = "https://files.pythonhosted.org/packages/db/6e/a0fb897041949888191a49c36afd5c6f5d9f5fd757e0b0cd99ec198a324b/coverage-7.11.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a8258f10059b5ac837232c589a350a2df4a96406d6d5f2a09ec587cbdd539655", size = 259049, upload-time = "2025-11-10T00:12:01.592Z" }, { url = "https://files.pythonhosted.org/packages/74/40/35773cc4bb1e9d4658d4fb669eb4195b3151bef3bbd6f866aba5cd5dac82/coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7", size = 260078, upload-time = "2025-11-18T13:33:14.037Z" },
{ url = "https://files.pythonhosted.org/packages/d9/b6/d13acc67eb402d91eb94b9bd60593411799aed09ce176ee8d8c0e39c94ca/coverage-7.11.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c5627429f7fbff4f4131cfdd6abd530734ef7761116811a707b88b7e205afd7", size = 261113, upload-time = "2025-11-10T00:12:03.639Z" }, { url = "https://files.pythonhosted.org/packages/ec/ee/231bb1a6ffc2905e396557585ebc6bdc559e7c66708376d245a1f1d330fc/coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560", size = 262144, upload-time = "2025-11-18T13:33:15.601Z" },
{ url = "https://files.pythonhosted.org/packages/ea/07/a6868893c48191d60406df4356aa7f0f74e6de34ef1f03af0d49183e0fa1/coverage-7.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:465695268414e149bab754c54b0c45c8ceda73dd4a5c3ba255500da13984b16d", size = 263546, upload-time = "2025-11-10T00:12:05.485Z" }, { url = "https://files.pythonhosted.org/packages/28/be/32f4aa9f3bf0b56f3971001b56508352c7753915345d45fab4296a986f01/coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12", size = 264574, upload-time = "2025-11-18T13:33:17.354Z" },
{ url = "https://files.pythonhosted.org/packages/24/e5/28598f70b2c1098332bac47925806353b3313511d984841111e6e760c016/coverage-7.11.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4ebcddfcdfb4c614233cff6e9a3967a09484114a8b2e4f2c7a62dc83676ba13f", size = 258260, upload-time = "2025-11-10T00:12:07.137Z" }, { url = "https://files.pythonhosted.org/packages/68/7c/00489fcbc2245d13ab12189b977e0cf06ff3351cb98bc6beba8bd68c5902/coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296", size = 259298, upload-time = "2025-11-18T13:33:18.958Z" },
{ url = "https://files.pythonhosted.org/packages/0e/58/58e2d9e6455a4ed746a480c4b9cf96dc3cb2a6b8f3efbee5efd33ae24b06/coverage-7.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:13b2066303a1c1833c654d2af0455bb009b6e1727b3883c9964bc5c2f643c1d0", size = 261121, upload-time = "2025-11-10T00:12:09.138Z" }, { url = "https://files.pythonhosted.org/packages/96/b4/f0760d65d56c3bea95b449e02570d4abd2549dc784bf39a2d4721a2d8ceb/coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507", size = 262150, upload-time = "2025-11-18T13:33:20.644Z" },
{ url = "https://files.pythonhosted.org/packages/17/57/38803eefb9b0409934cbc5a14e3978f0c85cb251d2b6f6a369067a7105a0/coverage-7.11.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d8750dd20362a1b80e3cf84f58013d4672f89663aee457ea59336df50fab6739", size = 258736, upload-time = "2025-11-10T00:12:11.195Z" }, { url = "https://files.pythonhosted.org/packages/c5/71/9a9314df00f9326d78c1e5a910f520d599205907432d90d1c1b7a97aa4b1/coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d", size = 259763, upload-time = "2025-11-18T13:33:22.189Z" },
{ url = "https://files.pythonhosted.org/packages/a8/f3/f94683167156e93677b3442be1d4ca70cb33718df32a2eea44a5898f04f6/coverage-7.11.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ab6212e62ea0e1006531a2234e209607f360d98d18d532c2fa8e403c1afbdd71", size = 257625, upload-time = "2025-11-10T00:12:12.843Z" }, { url = "https://files.pythonhosted.org/packages/10/34/01a0aceed13fbdf925876b9a15d50862eb8845454301fe3cdd1df08b2182/coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2", size = 258653, upload-time = "2025-11-18T13:33:24.239Z" },
{ url = "https://files.pythonhosted.org/packages/87/ed/42d0bf1bc6bfa7d65f52299a31daaa866b4c11000855d753857fe78260ac/coverage-7.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a6b17c2b5e0b9bb7702449200f93e2d04cb04b1414c41424c08aa1e5d352da76", size = 259827, upload-time = "2025-11-10T00:12:15.128Z" }, { url = "https://files.pythonhosted.org/packages/8d/04/81d8fd64928acf1574bbb0181f66901c6c1c6279c8ccf5f84259d2c68ae9/coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455", size = 260856, upload-time = "2025-11-18T13:33:26.365Z" },
{ url = "https://files.pythonhosted.org/packages/d3/76/5682719f5d5fbedb0c624c9851ef847407cae23362deb941f185f489c54e/coverage-7.11.3-cp313-cp313t-win32.whl", hash = "sha256:426559f105f644b69290ea414e154a0d320c3ad8a2bb75e62884731f69cf8e2c", size = 219897, upload-time = "2025-11-10T00:12:17.274Z" }, { url = "https://files.pythonhosted.org/packages/f2/76/fa2a37bfaeaf1f766a2d2360a25a5297d4fb567098112f6517475eee120b/coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d", size = 220936, upload-time = "2025-11-18T13:33:28.165Z" },
{ url = "https://files.pythonhosted.org/packages/10/e0/1da511d0ac3d39e6676fa6cc5ec35320bbf1cebb9b24e9ee7548ee4e931a/coverage-7.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:90a96fcd824564eae6137ec2563bd061d49a32944858d4bdbae5c00fb10e76ac", size = 220959, upload-time = "2025-11-10T00:12:19.292Z" }, { url = "https://files.pythonhosted.org/packages/f9/52/60f64d932d555102611c366afb0eb434b34266b1d9266fc2fe18ab641c47/coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c", size = 222001, upload-time = "2025-11-18T13:33:29.656Z" },
{ url = "https://files.pythonhosted.org/packages/e5/9d/e255da6a04e9ec5f7b633c54c0fdfa221a9e03550b67a9c83217de12e96c/coverage-7.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:1e33d0bebf895c7a0905fcfaff2b07ab900885fc78bba2a12291a2cfbab014cc", size = 219234, upload-time = "2025-11-10T00:12:21.251Z" }, { url = "https://files.pythonhosted.org/packages/77/df/c303164154a5a3aea7472bf323b7c857fed93b26618ed9fc5c2955566bb0/coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d", size = 220273, upload-time = "2025-11-18T13:33:31.415Z" },
{ url = "https://files.pythonhosted.org/packages/84/d6/634ec396e45aded1772dccf6c236e3e7c9604bc47b816e928f32ce7987d1/coverage-7.11.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fdc5255eb4815babcdf236fa1a806ccb546724c8a9b129fd1ea4a5448a0bf07c", size = 216746, upload-time = "2025-11-10T00:12:23.089Z" }, { url = "https://files.pythonhosted.org/packages/bf/2e/fc12db0883478d6e12bbd62d481210f0c8daf036102aa11434a0c5755825/coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92", size = 217777, upload-time = "2025-11-18T13:33:32.86Z" },
{ url = "https://files.pythonhosted.org/packages/28/76/1079547f9d46f9c7c7d0dad35b6873c98bc5aa721eeabceafabd722cd5e7/coverage-7.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fe3425dc6021f906c6325d3c415e048e7cdb955505a94f1eb774dafc779ba203", size = 217077, upload-time = "2025-11-10T00:12:24.863Z" }, { url = "https://files.pythonhosted.org/packages/1f/c1/ce3e525d223350c6ec16b9be8a057623f54226ef7f4c2fee361ebb6a02b8/coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360", size = 218100, upload-time = "2025-11-18T13:33:34.532Z" },
{ url = "https://files.pythonhosted.org/packages/2d/71/6ad80d6ae0d7cb743b9a98df8bb88b1ff3dc54491508a4a97549c2b83400/coverage-7.11.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4ca5f876bf41b24378ee67c41d688155f0e54cdc720de8ef9ad6544005899240", size = 248122, upload-time = "2025-11-10T00:12:26.553Z" }, { url = "https://files.pythonhosted.org/packages/15/87/113757441504aee3808cb422990ed7c8bcc2d53a6779c66c5adef0942939/coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac", size = 249151, upload-time = "2025-11-18T13:33:36.135Z" },
{ url = "https://files.pythonhosted.org/packages/20/1d/784b87270784b0b88e4beec9d028e8d58f73ae248032579c63ad2ac6f69a/coverage-7.11.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9061a3e3c92b27fd8036dafa26f25d95695b6aa2e4514ab16a254f297e664f83", size = 250638, upload-time = "2025-11-10T00:12:28.555Z" }, { url = "https://files.pythonhosted.org/packages/d9/1d/9529d9bd44049b6b05bb319c03a3a7e4b0a8a802d28fa348ad407e10706d/coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d", size = 251667, upload-time = "2025-11-18T13:33:37.996Z" },
{ url = "https://files.pythonhosted.org/packages/f5/26/b6dd31e23e004e9de84d1a8672cd3d73e50f5dae65dbd0f03fa2cdde6100/coverage-7.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:abcea3b5f0dc44e1d01c27090bc32ce6ffb7aa665f884f1890710454113ea902", size = 251972, upload-time = "2025-11-10T00:12:30.246Z" }, { url = "https://files.pythonhosted.org/packages/11/bb/567e751c41e9c03dc29d3ce74b8c89a1e3396313e34f255a2a2e8b9ebb56/coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c", size = 253003, upload-time = "2025-11-18T13:33:39.553Z" },
{ url = "https://files.pythonhosted.org/packages/c9/ef/f9c64d76faac56b82daa036b34d4fe9ab55eb37f22062e68e9470583e688/coverage-7.11.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:68c4eb92997dbaaf839ea13527be463178ac0ddd37a7ac636b8bc11a51af2428", size = 248147, upload-time = "2025-11-10T00:12:32.195Z" }, { url = "https://files.pythonhosted.org/packages/e4/b3/c2cce2d8526a02fb9e9ca14a263ca6fc074449b33a6afa4892838c903528/coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434", size = 249185, upload-time = "2025-11-18T13:33:42.086Z" },
{ url = "https://files.pythonhosted.org/packages/b6/eb/5b666f90a8f8053bd264a1ce693d2edef2368e518afe70680070fca13ecd/coverage-7.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:149eccc85d48c8f06547534068c41d69a1a35322deaa4d69ba1561e2e9127e75", size = 249995, upload-time = "2025-11-10T00:12:33.969Z" }, { url = "https://files.pythonhosted.org/packages/0e/a7/967f93bb66e82c9113c66a8d0b65ecf72fc865adfba5a145f50c7af7e58d/coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc", size = 251025, upload-time = "2025-11-18T13:33:43.634Z" },
{ url = "https://files.pythonhosted.org/packages/eb/7b/871e991ffb5d067f8e67ffb635dabba65b231d6e0eb724a4a558f4a702a5/coverage-7.11.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:08c0bcf932e47795c49f0406054824b9d45671362dfc4269e0bc6e4bff010704", size = 247948, upload-time = "2025-11-10T00:12:36.341Z" }, { url = "https://files.pythonhosted.org/packages/b9/b2/f2f6f56337bc1af465d5b2dc1ee7ee2141b8b9272f3bf6213fcbc309a836/coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc", size = 248979, upload-time = "2025-11-18T13:33:46.04Z" },
{ url = "https://files.pythonhosted.org/packages/0a/8b/ce454f0af9609431b06dbe5485fc9d1c35ddc387e32ae8e374f49005748b/coverage-7.11.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:39764c6167c82d68a2d8c97c33dba45ec0ad9172570860e12191416f4f8e6e1b", size = 247770, upload-time = "2025-11-10T00:12:38.167Z" }, { url = "https://files.pythonhosted.org/packages/f4/7a/bf4209f45a4aec09d10a01a57313a46c0e0e8f4c55ff2965467d41a92036/coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e", size = 248800, upload-time = "2025-11-18T13:33:47.546Z" },
{ url = "https://files.pythonhosted.org/packages/61/8f/79002cb58a61dfbd2085de7d0a46311ef2476823e7938db80284cedd2428/coverage-7.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3224c7baf34e923ffc78cb45e793925539d640d42c96646db62dbd61bbcfa131", size = 249431, upload-time = "2025-11-10T00:12:40.354Z" }, { url = "https://files.pythonhosted.org/packages/b8/b7/1e01b8696fb0521810f60c5bbebf699100d6754183e6cc0679bf2ed76531/coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17", size = 250460, upload-time = "2025-11-18T13:33:49.537Z" },
{ url = "https://files.pythonhosted.org/packages/58/cc/d06685dae97468ed22999440f2f2f5060940ab0e7952a7295f236d98cce7/coverage-7.11.3-cp314-cp314-win32.whl", hash = "sha256:c713c1c528284d636cd37723b0b4c35c11190da6f932794e145fc40f8210a14a", size = 219508, upload-time = "2025-11-10T00:12:42.231Z" }, { url = "https://files.pythonhosted.org/packages/71/ae/84324fb9cb46c024760e706353d9b771a81b398d117d8c1fe010391c186f/coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933", size = 220533, upload-time = "2025-11-18T13:33:51.16Z" },
{ url = "https://files.pythonhosted.org/packages/5f/ed/770cd07706a3598c545f62d75adf2e5bd3791bffccdcf708ec383ad42559/coverage-7.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:c381a252317f63ca0179d2c7918e83b99a4ff3101e1b24849b999a00f9cd4f86", size = 220325, upload-time = "2025-11-10T00:12:44.065Z" }, { url = "https://files.pythonhosted.org/packages/e2/71/1033629deb8460a8f97f83e6ac4ca3b93952e2b6f826056684df8275e015/coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe", size = 221348, upload-time = "2025-11-18T13:33:52.776Z" },
{ url = "https://files.pythonhosted.org/packages/ee/ac/6a1c507899b6fb1b9a56069954365f655956bcc648e150ce64c2b0ecbed8/coverage-7.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:3e33a968672be1394eded257ec10d4acbb9af2ae263ba05a99ff901bb863557e", size = 218899, upload-time = "2025-11-10T00:12:46.18Z" }, { url = "https://files.pythonhosted.org/packages/0a/5f/ac8107a902f623b0c251abdb749be282dc2ab61854a8a4fcf49e276fce2f/coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d", size = 219922, upload-time = "2025-11-18T13:33:54.316Z" },
{ url = "https://files.pythonhosted.org/packages/9a/58/142cd838d960cd740654d094f7b0300d7b81534bb7304437d2439fb685fb/coverage-7.11.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f9c96a29c6d65bd36a91f5634fef800212dff69dacdb44345c4c9783943ab0df", size = 217471, upload-time = "2025-11-10T00:12:48.392Z" }, { url = "https://files.pythonhosted.org/packages/79/6e/f27af2d4da367f16077d21ef6fe796c874408219fa6dd3f3efe7751bd910/coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d", size = 218511, upload-time = "2025-11-18T13:33:56.343Z" },
{ url = "https://files.pythonhosted.org/packages/bc/2c/2f44d39eb33e41ab3aba80571daad32e0f67076afcf27cb443f9e5b5a3ee/coverage-7.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2ec27a7a991d229213c8070d31e3ecf44d005d96a9edc30c78eaeafaa421c001", size = 217742, upload-time = "2025-11-10T00:12:50.182Z" }, { url = "https://files.pythonhosted.org/packages/67/dd/65fd874aa460c30da78f9d259400d8e6a4ef457d61ab052fd248f0050558/coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03", size = 218771, upload-time = "2025-11-18T13:33:57.966Z" },
{ url = "https://files.pythonhosted.org/packages/32/76/8ebc66c3c699f4de3174a43424c34c086323cd93c4930ab0f835731c443a/coverage-7.11.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:72c8b494bd20ae1c58528b97c4a67d5cfeafcb3845c73542875ecd43924296de", size = 259120, upload-time = "2025-11-10T00:12:52.451Z" }, { url = "https://files.pythonhosted.org/packages/55/e0/7c6b71d327d8068cb79c05f8f45bf1b6145f7a0de23bbebe63578fe5240a/coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9", size = 260151, upload-time = "2025-11-18T13:33:59.597Z" },
{ url = "https://files.pythonhosted.org/packages/19/89/78a3302b9595f331b86e4f12dfbd9252c8e93d97b8631500888f9a3a2af7/coverage-7.11.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:60ca149a446da255d56c2a7a813b51a80d9497a62250532598d249b3cdb1a926", size = 261229, upload-time = "2025-11-10T00:12:54.667Z" }, { url = "https://files.pythonhosted.org/packages/49/ce/4697457d58285b7200de6b46d606ea71066c6e674571a946a6ea908fb588/coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6", size = 262257, upload-time = "2025-11-18T13:34:01.166Z" },
{ url = "https://files.pythonhosted.org/packages/07/59/1a9c0844dadef2a6efac07316d9781e6c5a3f3ea7e5e701411e99d619bfd/coverage-7.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb5069074db19a534de3859c43eec78e962d6d119f637c41c8e028c5ab3f59dd", size = 263642, upload-time = "2025-11-10T00:12:56.841Z" }, { url = "https://files.pythonhosted.org/packages/2f/33/acbc6e447aee4ceba88c15528dbe04a35fb4d67b59d393d2e0d6f1e242c1/coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339", size = 264671, upload-time = "2025-11-18T13:34:02.795Z" },
{ url = "https://files.pythonhosted.org/packages/37/86/66c15d190a8e82eee777793cabde730640f555db3c020a179625a2ad5320/coverage-7.11.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac5d5329c9c942bbe6295f4251b135d860ed9f86acd912d418dce186de7c19ac", size = 258193, upload-time = "2025-11-10T00:12:58.687Z" }, { url = "https://files.pythonhosted.org/packages/87/ec/e2822a795c1ed44d569980097be839c5e734d4c0c1119ef8e0a073496a30/coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e", size = 259231, upload-time = "2025-11-18T13:34:04.397Z" },
{ url = "https://files.pythonhosted.org/packages/c7/c7/4a4aeb25cb6f83c3ec4763e5f7cc78da1c6d4ef9e22128562204b7f39390/coverage-7.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e22539b676fafba17f0a90ac725f029a309eb6e483f364c86dcadee060429d46", size = 261107, upload-time = "2025-11-10T00:13:00.502Z" }, { url = "https://files.pythonhosted.org/packages/72/c5/a7ec5395bb4a49c9b7ad97e63f0c92f6bf4a9e006b1393555a02dae75f16/coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13", size = 262137, upload-time = "2025-11-18T13:34:06.068Z" },
{ url = "https://files.pythonhosted.org/packages/ed/91/b986b5035f23cf0272446298967ecdd2c3c0105ee31f66f7e6b6948fd7f8/coverage-7.11.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2376e8a9c889016f25472c452389e98bc6e54a19570b107e27cde9d47f387b64", size = 258717, upload-time = "2025-11-10T00:13:02.747Z" }, { url = "https://files.pythonhosted.org/packages/67/0c/02c08858b764129f4ecb8e316684272972e60777ae986f3865b10940bdd6/coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f", size = 259745, upload-time = "2025-11-18T13:34:08.04Z" },
{ url = "https://files.pythonhosted.org/packages/f0/c7/6c084997f5a04d050c513545d3344bfa17bd3b67f143f388b5757d762b0b/coverage-7.11.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4234914b8c67238a3c4af2bba648dc716aa029ca44d01f3d51536d44ac16854f", size = 257541, upload-time = "2025-11-10T00:13:04.689Z" }, { url = "https://files.pythonhosted.org/packages/5a/04/4fd32b7084505f3829a8fe45c1a74a7a728cb251aaadbe3bec04abcef06d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1", size = 258570, upload-time = "2025-11-18T13:34:09.676Z" },
{ url = "https://files.pythonhosted.org/packages/3b/c5/38e642917e406930cb67941210a366ccffa767365c8f8d9ec0f465a8b218/coverage-7.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0b4101e2b3c6c352ff1f70b3a6fcc7c17c1ab1a91ccb7a33013cb0782af9820", size = 259872, upload-time = "2025-11-10T00:13:06.559Z" }, { url = "https://files.pythonhosted.org/packages/48/35/2365e37c90df4f5342c4fa202223744119fe31264ee2924f09f074ea9b6d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b", size = 260899, upload-time = "2025-11-18T13:34:11.259Z" },
{ url = "https://files.pythonhosted.org/packages/b7/67/5e812979d20c167f81dbf9374048e0193ebe64c59a3d93d7d947b07865fa/coverage-7.11.3-cp314-cp314t-win32.whl", hash = "sha256:305716afb19133762e8cf62745c46c4853ad6f9eeba54a593e373289e24ea237", size = 220289, upload-time = "2025-11-10T00:13:08.635Z" }, { url = "https://files.pythonhosted.org/packages/05/56/26ab0464ca733fa325e8e71455c58c1c374ce30f7c04cebb88eabb037b18/coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a", size = 221313, upload-time = "2025-11-18T13:34:12.863Z" },
{ url = "https://files.pythonhosted.org/packages/24/3a/b72573802672b680703e0df071faadfab7dcd4d659aaaffc4626bc8bbde8/coverage-7.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:9245bd392572b9f799261c4c9e7216bafc9405537d0f4ce3ad93afe081a12dc9", size = 221398, upload-time = "2025-11-10T00:13:10.734Z" }, { url = "https://files.pythonhosted.org/packages/da/1c/017a3e1113ed34d998b27d2c6dba08a9e7cb97d362f0ec988fcd873dcf81/coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291", size = 222423, upload-time = "2025-11-18T13:34:15.14Z" },
{ url = "https://files.pythonhosted.org/packages/f8/4e/649628f28d38bad81e4e8eb3f78759d20ac173e3c456ac629123815feb40/coverage-7.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:9a1d577c20b4334e5e814c3d5fe07fa4a8c3ae42a601945e8d7940bab811d0bd", size = 219435, upload-time = "2025-11-10T00:13:12.712Z" }, { url = "https://files.pythonhosted.org/packages/4c/36/bcc504fdd5169301b52568802bb1b9cdde2e27a01d39fbb3b4b508ab7c2c/coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384", size = 220459, upload-time = "2025-11-18T13:34:17.222Z" },
{ url = "https://files.pythonhosted.org/packages/19/8f/92bdd27b067204b99f396a1414d6342122f3e2663459baf787108a6b8b84/coverage-7.11.3-py3-none-any.whl", hash = "sha256:351511ae28e2509c8d8cae5311577ea7dd511ab8e746ffc8814a0896c3d33fbe", size = 208478, upload-time = "2025-11-10T00:13:14.908Z" }, { url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a", size = 209503, upload-time = "2025-11-18T13:34:18.892Z" },
] ]
[[package]] [[package]]