bear-utils 0.7.11__tar.gz → 0.7.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bear_utils-0.7.11 → bear_utils-0.7.13}/PKG-INFO +3 -3
- {bear_utils-0.7.11 → bear_utils-0.7.13}/README.md +1 -1
- {bear_utils-0.7.11 → bear_utils-0.7.13}/pyproject.toml +3 -7
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/__init__.py +5 -3
- bear_utils-0.7.13/src/bear_utils/constants/date_related.py +23 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/extras/__init__.py +3 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/extras/_tools.py +36 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/_styles.py +1 -1
- bear_utils-0.7.13/src/bear_utils/time/__init__.py +30 -0
- bear_utils-0.7.11/src/bear_utils/constants/date_related.py +0 -36
- bear_utils-0.7.11/src/bear_utils/time/__init__.py +0 -16
- bear_utils-0.7.11/src/bear_utils/time/_helpers.py +0 -91
- bear_utils-0.7.11/src/bear_utils/time/_time_class.py +0 -316
- bear_utils-0.7.11/src/bear_utils/time/_timer.py +0 -80
- bear_utils-0.7.11/src/bear_utils/time/_tools.py +0 -17
- bear_utils-0.7.11/src/bear_utils/time/time_manager.py +0 -218
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/ai/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/ai/ai_helpers/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/ai/ai_helpers/_common.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/ai/ai_helpers/_config.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/ai/ai_helpers/_parsers.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/ai/ai_helpers/_types.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/cache/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/cli/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/cli/commands.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/cli/prompt_helpers.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/cli/shell/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/cli/shell/_base_command.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/cli/shell/_base_shell.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/cli/shell/_common.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/config/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/config/config_manager.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/config/dir_manager.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/config/settings_manager.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/constants/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/constants/_exceptions.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/constants/_lazy_typing.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/constants/time_related.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/database/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/database/_db_manager.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/events/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/events/events_class.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/events/events_module.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/extras/_async_helpers.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/extras/platform_utils.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/extras/wrappers/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/extras/wrappers/add_methods.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/_base_file_handler.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/file_handler_factory.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/json_file_handler.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/log_file_handler.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/txt_file_handler.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/yaml_file_handler.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/ignore_parser.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/graphics/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/graphics/bear_gradient.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/graphics/image_helpers.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/gui/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/gui/gui_tools/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/gui/gui_tools/_settings.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/gui/gui_tools/_types.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/gui/gui_tools/qt_app.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/gui/gui_tools/qt_color_picker.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/gui/gui_tools/qt_file_handler.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/gui/gui_tools/qt_input_dialog.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/_common.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/_console_junk.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_base_logger.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_base_logger.pyi +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_buffer_logger.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_console_logger.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_console_logger.pyi +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_file_logger.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_level_sin.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_logger.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_sub_logger.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_sub_logger.pyi +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/loggers.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/monitoring/__init__.py +0 -0
- {bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/monitoring/host_monitor.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: bear-utils
|
3
|
-
Version: 0.7.
|
3
|
+
Version: 0.7.13
|
4
4
|
Summary: Various utilities for Bear programmers, including a rich logging utility, a disk cache, and a SQLite database wrapper amongst other things.
|
5
5
|
Author: chaz
|
6
6
|
Author-email: bright.lid5647@fastmail.com
|
@@ -8,6 +8,7 @@ Requires-Python: >=3.12
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
9
9
|
Classifier: Programming Language :: Python :: 3.12
|
10
10
|
Classifier: Programming Language :: Python :: 3.13
|
11
|
+
Requires-Dist: bear-epoch-time (>=1.0.1)
|
11
12
|
Requires-Dist: diskcache (>=5.6.3,<6.0.0)
|
12
13
|
Requires-Dist: httpx (>=0.28.1)
|
13
14
|
Requires-Dist: pathspec (>=0.12.1)
|
@@ -16,14 +17,13 @@ Requires-Dist: prompt-toolkit (>=3.0.51,<4.0.0)
|
|
16
17
|
Requires-Dist: pydantic (>=2.11.5)
|
17
18
|
Requires-Dist: pyglm (>=2.8.2,<3.0.0)
|
18
19
|
Requires-Dist: pyqt6 (>=6.9.0)
|
19
|
-
Requires-Dist: pytz (>=2025.2)
|
20
20
|
Requires-Dist: pyyaml (>=6.0.2)
|
21
21
|
Requires-Dist: rich (>=14.0.0,<15.0.0)
|
22
22
|
Requires-Dist: singleton-base (>=1.0.5)
|
23
23
|
Requires-Dist: sqlalchemy (>=2.0.40,<3.0.0)
|
24
24
|
Description-Content-Type: text/markdown
|
25
25
|
|
26
|
-
# Bear Utils v# Bear Utils v0.7.
|
26
|
+
# Bear Utils v# Bear Utils v0.7.13
|
27
27
|
|
28
28
|
Personal set of tools and utilities for Python projects, focusing on modularity and ease of use. This library includes components for caching, database management, logging, time handling, file operations, CLI prompts, image processing, clipboard interaction, gradient utilities, event systems, and async helpers.
|
29
29
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Bear Utils v# Bear Utils v0.7.
|
1
|
+
# Bear Utils v# Bear Utils v0.7.13
|
2
2
|
|
3
3
|
Personal set of tools and utilities for Python projects, focusing on modularity and ease of use. This library includes components for caching, database management, logging, time handling, file operations, CLI prompts, image processing, clipboard interaction, gradient utilities, event systems, and async helpers.
|
4
4
|
|
@@ -1,10 +1,8 @@
|
|
1
1
|
[project]
|
2
2
|
name = "bear-utils"
|
3
|
-
version = "0.7.
|
3
|
+
version = "0.7.13"
|
4
4
|
description = "Various utilities for Bear programmers, including a rich logging utility, a disk cache, and a SQLite database wrapper amongst other things."
|
5
|
-
authors = [
|
6
|
-
{ name = "chaz", email = "bright.lid5647@fastmail.com" }
|
7
|
-
]
|
5
|
+
authors = [{ name = "chaz", email = "bright.lid5647@fastmail.com" }]
|
8
6
|
readme = "README.md"
|
9
7
|
requires-python = ">=3.12"
|
10
8
|
dependencies = [
|
@@ -18,12 +16,11 @@ dependencies = [
|
|
18
16
|
"pydantic>=2.11.5",
|
19
17
|
"pathspec>=0.12.1",
|
20
18
|
"pyyaml>=6.0.2",
|
21
|
-
"pytz>=2025.2",
|
22
19
|
"singleton-base>=1.0.5",
|
23
20
|
"httpx>=0.28.1",
|
21
|
+
"bear-epoch-time>=1.0.1",
|
24
22
|
]
|
25
23
|
|
26
|
-
|
27
24
|
[build-system]
|
28
25
|
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
29
26
|
build-backend = "poetry.core.masonry.api"
|
@@ -36,7 +33,6 @@ dev = [
|
|
36
33
|
"twine>=6.1.0",
|
37
34
|
]
|
38
35
|
|
39
|
-
|
40
36
|
[tool.pytest.ini_options]
|
41
37
|
markers = [
|
42
38
|
"visual: marks tests as visual verification tests (deselect with '-m \"not visual\"')"
|
@@ -1,3 +1,7 @@
|
|
1
|
+
from importlib.metadata import version
|
2
|
+
|
3
|
+
from bear_epoch_time import EpochTimestamp, TimeTools
|
4
|
+
|
1
5
|
from .cache import CacheWrapper, cache, cache_factory
|
2
6
|
from .config.settings_manager import SettingsManager, get_settings_manager
|
3
7
|
from .constants.date_related import DATE_FORMAT, DATE_TIME_FORMAT
|
@@ -7,7 +11,5 @@ from .files.file_handlers.file_handler_factory import FileHandlerFactory
|
|
7
11
|
from .logging.logger_manager._common import VERBOSE_CONSOLE_FORMAT
|
8
12
|
from .logging.logger_manager._styles import VERBOSE
|
9
13
|
from .logging.loggers import BaseLogger, BufferLogger, ConsoleLogger, FileLogger
|
10
|
-
from .time._time_class import EpochTimestamp
|
11
|
-
from .time.time_manager import TimeTools
|
12
14
|
|
13
|
-
__version__
|
15
|
+
__version__: str = version("bear-utils")
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from bear_epoch_time.constants.date_related import (
|
2
|
+
DATE_FORMAT,
|
3
|
+
DATE_TIME_FORMAT,
|
4
|
+
DT_FORMAT_WITH_SECONDS,
|
5
|
+
DT_FORMAT_WITH_TZ,
|
6
|
+
DT_FORMAT_WITH_TZ_AND_SECONDS,
|
7
|
+
ET_TIME_ZONE,
|
8
|
+
PT_TIME_ZONE,
|
9
|
+
TIME_FORMAT_WITH_SECONDS,
|
10
|
+
UTC_TIME_ZONE,
|
11
|
+
)
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
"DATE_FORMAT",
|
15
|
+
"DATE_TIME_FORMAT",
|
16
|
+
"DT_FORMAT_WITH_SECONDS",
|
17
|
+
"DT_FORMAT_WITH_TZ",
|
18
|
+
"DT_FORMAT_WITH_TZ_AND_SECONDS",
|
19
|
+
"ET_TIME_ZONE",
|
20
|
+
"PT_TIME_ZONE",
|
21
|
+
"TIME_FORMAT_WITH_SECONDS",
|
22
|
+
"UTC_TIME_ZONE",
|
23
|
+
]
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from singleton_base import SingletonBase
|
2
|
+
|
1
3
|
from ._tools import ClipboardManager, clear_clipboard, copy_to_clipboard, fmt_header, paste_from_clipboard
|
2
4
|
from .platform_utils import OS, get_platform, is_linux, is_macos, is_windows
|
3
5
|
from .wrappers.add_methods import add_comparison_methods
|
@@ -14,4 +16,5 @@ __all__ = [
|
|
14
16
|
"clear_clipboard",
|
15
17
|
"fmt_header",
|
16
18
|
"add_comparison_methods",
|
19
|
+
"SingletonBase",
|
17
20
|
]
|
@@ -129,6 +129,20 @@ def copy_to_clipboard(output: str) -> int:
|
|
129
129
|
return loop.run_until_complete(clipboard_manager.copy(output))
|
130
130
|
|
131
131
|
|
132
|
+
async def copy_to_clipboard_async(output: str) -> int:
|
133
|
+
"""
|
134
|
+
Asynchronously copy the output to the clipboard.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
output (str): The output to copy to the clipboard.
|
138
|
+
|
139
|
+
Returns:
|
140
|
+
int: The return code of the command.
|
141
|
+
"""
|
142
|
+
clipboard_manager = ClipboardManager()
|
143
|
+
return await clipboard_manager.copy(output)
|
144
|
+
|
145
|
+
|
132
146
|
def paste_from_clipboard() -> str:
|
133
147
|
"""
|
134
148
|
Paste the output from the clipboard.
|
@@ -141,6 +155,17 @@ def paste_from_clipboard() -> str:
|
|
141
155
|
return loop.run_until_complete(clipboard_manager.paste())
|
142
156
|
|
143
157
|
|
158
|
+
async def paste_from_clipboard_async() -> str:
|
159
|
+
"""
|
160
|
+
Asynchronously paste the output from the clipboard.
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
str: The content of the clipboard.
|
164
|
+
"""
|
165
|
+
clipboard_manager = ClipboardManager()
|
166
|
+
return await clipboard_manager.paste()
|
167
|
+
|
168
|
+
|
144
169
|
def clear_clipboard() -> int:
|
145
170
|
"""
|
146
171
|
Clear the clipboard.
|
@@ -153,6 +178,17 @@ def clear_clipboard() -> int:
|
|
153
178
|
return loop.run_until_complete(clipboard_manager.clear())
|
154
179
|
|
155
180
|
|
181
|
+
async def clear_clipboard_async() -> int:
|
182
|
+
"""
|
183
|
+
Asynchronously clear the clipboard.
|
184
|
+
|
185
|
+
Returns:
|
186
|
+
int: The return code of the command.
|
187
|
+
"""
|
188
|
+
clipboard_manager = ClipboardManager()
|
189
|
+
return await clipboard_manager.clear()
|
190
|
+
|
191
|
+
|
156
192
|
def fmt_header(
|
157
193
|
title: str,
|
158
194
|
sep: str = "#",
|
@@ -85,7 +85,7 @@ def get_method(name: str) -> LoggerExtraInfo:
|
|
85
85
|
return LOGGER_METHODS[name]
|
86
86
|
|
87
87
|
|
88
|
-
DEFAULT_STYLES: dict[str, str] = {**{method: info["style"]
|
88
|
+
DEFAULT_STYLES: dict[str, str] = {**{method: info["style"] for method, info in LOGGER_METHODS.items()}}
|
89
89
|
"""Just the styles of the logger methods, used to create the theme."""
|
90
90
|
|
91
91
|
DEFAULT_THEME = Theme(styles=DEFAULT_STYLES)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
from bear_epoch_time import EpochTimestamp, TimerData, TimeTools, add_ord_suffix, create_timer, timer
|
2
|
+
from bear_epoch_time.constants.date_related import (
|
3
|
+
DATE_FORMAT,
|
4
|
+
DATE_TIME_FORMAT,
|
5
|
+
DT_FORMAT_WITH_SECONDS,
|
6
|
+
DT_FORMAT_WITH_TZ,
|
7
|
+
DT_FORMAT_WITH_TZ_AND_SECONDS,
|
8
|
+
ET_TIME_ZONE,
|
9
|
+
PT_TIME_ZONE,
|
10
|
+
TIME_FORMAT_WITH_SECONDS,
|
11
|
+
UTC_TIME_ZONE,
|
12
|
+
)
|
13
|
+
|
14
|
+
__all__ = [
|
15
|
+
"EpochTimestamp",
|
16
|
+
"TimerData",
|
17
|
+
"create_timer",
|
18
|
+
"timer",
|
19
|
+
"TimeTools",
|
20
|
+
"add_ord_suffix",
|
21
|
+
"DATE_FORMAT",
|
22
|
+
"DATE_TIME_FORMAT",
|
23
|
+
"DT_FORMAT_WITH_SECONDS",
|
24
|
+
"DT_FORMAT_WITH_TZ",
|
25
|
+
"DT_FORMAT_WITH_TZ_AND_SECONDS",
|
26
|
+
"ET_TIME_ZONE",
|
27
|
+
"PT_TIME_ZONE",
|
28
|
+
"TIME_FORMAT_WITH_SECONDS",
|
29
|
+
"UTC_TIME_ZONE",
|
30
|
+
]
|
@@ -1,36 +0,0 @@
|
|
1
|
-
from typing import LiteralString
|
2
|
-
|
3
|
-
from pytz import UTC, timezone
|
4
|
-
from pytz.tzinfo import BaseTzInfo, DstTzInfo, StaticTzInfo
|
5
|
-
|
6
|
-
TimeZoneType = BaseTzInfo | DstTzInfo | StaticTzInfo
|
7
|
-
|
8
|
-
DATE_FORMAT = "%m-%d-%Y"
|
9
|
-
"""Date format"""
|
10
|
-
|
11
|
-
TIME_FORMAT = "%I:%M %p"
|
12
|
-
"""Time format with 12 hour format"""
|
13
|
-
|
14
|
-
TIME_FORMAT_WITH_SECONDS: LiteralString = "%I:%M:%S %p"
|
15
|
-
"""Time format with 12 hour format and seconds"""
|
16
|
-
|
17
|
-
DATE_TIME_FORMAT: LiteralString = f"{DATE_FORMAT} {TIME_FORMAT}"
|
18
|
-
"""Datetime format with 12 hour format"""
|
19
|
-
|
20
|
-
DT_FORMAT_WITH_SECONDS: LiteralString = f"{DATE_FORMAT} {TIME_FORMAT_WITH_SECONDS}"
|
21
|
-
"""Datetime format with 12 hour format and seconds"""
|
22
|
-
|
23
|
-
DT_FORMAT_WITH_TZ: LiteralString = f"{DATE_TIME_FORMAT} %Z"
|
24
|
-
"""Datetime format with 12 hour format and timezone"""
|
25
|
-
|
26
|
-
DT_FORMAT_WITH_TZ_AND_SECONDS: LiteralString = f"{DT_FORMAT_WITH_SECONDS} %Z"
|
27
|
-
"""Datetime format with 12 hour format, seconds, and timezone"""
|
28
|
-
|
29
|
-
PT_TIME_ZONE: TimeZoneType = timezone("America/Los_Angeles")
|
30
|
-
"""Default timezone, a Pacific Time Zone using a pytz timezone object"""
|
31
|
-
|
32
|
-
UTC_TIME_ZONE: TimeZoneType = UTC
|
33
|
-
"""UTC timezone, a UTC timezone using a pytz timezone object"""
|
34
|
-
|
35
|
-
CEST_TIME_ZONE: TimeZoneType = timezone("Europe/Berlin") # Central European Summer Time, I GUESS!
|
36
|
-
"""Central European Summer Time timezone, a CEST timezone using a pytz timezone object"""
|
@@ -1,16 +0,0 @@
|
|
1
|
-
from ..constants.date_related import DATE_FORMAT, DATE_TIME_FORMAT
|
2
|
-
from ._time_class import EpochTimestamp
|
3
|
-
from ._timer import TimerData, create_timer, timer
|
4
|
-
from ._tools import add_ord_suffix
|
5
|
-
from .time_manager import TimeTools
|
6
|
-
|
7
|
-
__all__ = [
|
8
|
-
"EpochTimestamp",
|
9
|
-
"TimerData",
|
10
|
-
"create_timer",
|
11
|
-
"timer",
|
12
|
-
"TimeTools",
|
13
|
-
"add_ord_suffix",
|
14
|
-
"DATE_FORMAT",
|
15
|
-
"DATE_TIME_FORMAT",
|
16
|
-
]
|
@@ -1,91 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
from datetime import timedelta
|
3
|
-
|
4
|
-
from ..constants.time_related import SECONDS_IN_DAY, SECONDS_IN_HOUR, SECONDS_IN_MINUTE, SECONDS_IN_MONTH
|
5
|
-
|
6
|
-
|
7
|
-
def convert_to_seconds(time_str: str) -> int:
|
8
|
-
"""Convert a time string to seconds.
|
9
|
-
|
10
|
-
Examples
|
11
|
-
--------
|
12
|
-
>>> convert_to_seconds("1M 30m")
|
13
|
-
2610000
|
14
|
-
|
15
|
-
Notes
|
16
|
-
-----
|
17
|
-
* ``M`` or ``mo`` denotes **months**.
|
18
|
-
* ``m`` denotes **minutes**.
|
19
|
-
"""
|
20
|
-
|
21
|
-
time_parts: list[tuple[str, str]] = re.findall(r"(\d+)\s*(M|mo|[dhms])", time_str)
|
22
|
-
total_seconds = 0
|
23
|
-
for value, unit in time_parts:
|
24
|
-
if not value.isdigit():
|
25
|
-
raise ValueError(f"Invalid time value: {value}")
|
26
|
-
value = int(value)
|
27
|
-
|
28
|
-
if unit == "M" or unit.lower() == "mo":
|
29
|
-
total_seconds += value * SECONDS_IN_MONTH
|
30
|
-
elif unit == "d":
|
31
|
-
total_seconds += value * SECONDS_IN_DAY
|
32
|
-
elif unit == "h":
|
33
|
-
total_seconds += value * SECONDS_IN_HOUR
|
34
|
-
elif unit == "m":
|
35
|
-
total_seconds += value * SECONDS_IN_MINUTE
|
36
|
-
elif unit == "s":
|
37
|
-
total_seconds += value
|
38
|
-
else:
|
39
|
-
raise ValueError(f"Invalid time unit: {unit}")
|
40
|
-
return total_seconds
|
41
|
-
|
42
|
-
|
43
|
-
def timedelta_to_seconds(td: timedelta) -> int:
|
44
|
-
"""Convert a timedelta object to seconds."""
|
45
|
-
if not isinstance(td, timedelta):
|
46
|
-
raise ValueError("Input must be a timedelta object")
|
47
|
-
return int(td.total_seconds())
|
48
|
-
|
49
|
-
|
50
|
-
def convert_to_milliseconds(time_str: str) -> int:
|
51
|
-
return convert_to_seconds(time_str) * 1000
|
52
|
-
|
53
|
-
|
54
|
-
def milliseconds_to_time(milliseconds: int) -> str:
|
55
|
-
"""Convert milliseconds to a human-readable time string."""
|
56
|
-
if milliseconds < 0:
|
57
|
-
raise ValueError("Milliseconds cannot be negative")
|
58
|
-
seconds = milliseconds // 1000
|
59
|
-
return seconds_to_time(seconds)
|
60
|
-
|
61
|
-
|
62
|
-
def seconds_to_timedelta(seconds: int) -> timedelta:
|
63
|
-
"""Convert seconds to a timedelta object."""
|
64
|
-
if seconds < 0:
|
65
|
-
raise ValueError("Seconds cannot be negative")
|
66
|
-
return timedelta(seconds=seconds)
|
67
|
-
|
68
|
-
|
69
|
-
def seconds_to_time(seconds: int) -> str:
|
70
|
-
"""Convert seconds to a human-readable time string.
|
71
|
-
|
72
|
-
Months are represented with ``M`` while minutes use ``m``.
|
73
|
-
"""
|
74
|
-
if seconds < 0:
|
75
|
-
raise ValueError("Seconds cannot be negative")
|
76
|
-
months, reminder = divmod(seconds, SECONDS_IN_MONTH)
|
77
|
-
days, reminder = divmod(reminder, SECONDS_IN_DAY)
|
78
|
-
hours, reminder = divmod(reminder, SECONDS_IN_HOUR)
|
79
|
-
minutes, seconds = divmod(reminder, SECONDS_IN_MINUTE)
|
80
|
-
time_parts = []
|
81
|
-
if months > 0:
|
82
|
-
time_parts.append(f"{months}M")
|
83
|
-
if days > 0:
|
84
|
-
time_parts.append(f"{days}d")
|
85
|
-
if hours > 0:
|
86
|
-
time_parts.append(f"{hours}h")
|
87
|
-
if minutes > 0:
|
88
|
-
time_parts.append(f"{minutes}m")
|
89
|
-
if seconds > 0:
|
90
|
-
time_parts.append(f"{seconds}s")
|
91
|
-
return " ".join(time_parts)
|
@@ -1,316 +0,0 @@
|
|
1
|
-
from datetime import datetime
|
2
|
-
from typing import ClassVar, Literal, Self
|
3
|
-
|
4
|
-
from pytz import UTC
|
5
|
-
|
6
|
-
from ..constants.date_related import DATE_FORMAT, DT_FORMAT_WITH_TZ, PT_TIME_ZONE, TIME_FORMAT, TimeZoneType
|
7
|
-
|
8
|
-
REPR_CHOICES = Literal["int", "object", "datetime"]
|
9
|
-
MULT = Literal[1000, 1]
|
10
|
-
|
11
|
-
|
12
|
-
class EpochTimestamp(int):
|
13
|
-
"""
|
14
|
-
Custom class to represent epoch timestamps.
|
15
|
-
Inherits from int to allow direct arithmetic operations.
|
16
|
-
This class is used to represent time in seconds or milliseconds since the epoch (1970-01-01 00:00:00 UTC)
|
17
|
-
with it defaulting to ms since that is the most common use case.
|
18
|
-
|
19
|
-
Default value is the current epoch time in milliseconds. It is suggested to set the value to 0 if using it as
|
20
|
-
a placeholder value or call `now()` to get the current epoch time.
|
21
|
-
"""
|
22
|
-
|
23
|
-
_repr_style: ClassVar[REPR_CHOICES] = "int"
|
24
|
-
"""Three choices: int, object, or datetime.
|
25
|
-
Int is the default and is the most common use case.
|
26
|
-
Object will return the object representation of the class.
|
27
|
-
Datetime will return a human readable timestamp like "10-01-2025." """
|
28
|
-
_datefmt: ClassVar[str] = DATE_FORMAT
|
29
|
-
"""The format of the default date string. Default is "%m-%d-%Y"."""
|
30
|
-
_timefmt: ClassVar[str] = TIME_FORMAT
|
31
|
-
"""The format of the default time string. Default is "%I:%M %p"."""
|
32
|
-
_fullfmt: ClassVar[str] = DT_FORMAT_WITH_TZ
|
33
|
-
"""The format of the default datetime string. Default is "%m-%d-%Y %I:%M %p %Z"."""
|
34
|
-
_tz: ClassVar[TimeZoneType] = PT_TIME_ZONE
|
35
|
-
"""The default timezone for the class. Default is "America/Los_Angeles"."""
|
36
|
-
|
37
|
-
# region Class Methods
|
38
|
-
|
39
|
-
@classmethod
|
40
|
-
def set_repr_style(cls, repr_style: REPR_CHOICES) -> None:
|
41
|
-
"""
|
42
|
-
Set the plain representation of the class.
|
43
|
-
|
44
|
-
Args:
|
45
|
-
repr_style (str): The representation style ("int", "object", or "datetime")
|
46
|
-
"""
|
47
|
-
cls._repr_style = repr_style
|
48
|
-
|
49
|
-
@classmethod
|
50
|
-
def set_date_format(cls, datefmt: str) -> None:
|
51
|
-
"""
|
52
|
-
Set the default date format for the class.
|
53
|
-
|
54
|
-
Args:
|
55
|
-
datefmt (str): The format of the date string. Default is "%m-%d-%Y".
|
56
|
-
"""
|
57
|
-
cls._datefmt = datefmt
|
58
|
-
|
59
|
-
@classmethod
|
60
|
-
def set_time_format(cls, timefmt: str) -> None:
|
61
|
-
"""
|
62
|
-
Set the default time format for the class.
|
63
|
-
|
64
|
-
Args:
|
65
|
-
timefmt (str): The format of the time string. Default is "%I:%M %p".
|
66
|
-
"""
|
67
|
-
cls._timefmt = timefmt
|
68
|
-
|
69
|
-
@classmethod
|
70
|
-
def set_full_format(cls, fullfmt: str) -> None:
|
71
|
-
"""
|
72
|
-
Set the default datetime format for the class.
|
73
|
-
|
74
|
-
Args:
|
75
|
-
fullfmt (str): The format of the datetime string. Default is "%m-%d-%Y %I:%M %p %Z".
|
76
|
-
"""
|
77
|
-
cls._fullfmt = fullfmt
|
78
|
-
|
79
|
-
@classmethod
|
80
|
-
def set_timezone(cls, tz: TimeZoneType) -> None:
|
81
|
-
"""
|
82
|
-
Set the default timezone for the class.
|
83
|
-
|
84
|
-
Args:
|
85
|
-
tz (TimeZoneType): The timezone to set. Default is PT_TIME_ZONE.
|
86
|
-
"""
|
87
|
-
cls._tz = tz
|
88
|
-
|
89
|
-
@classmethod
|
90
|
-
def now(cls, milliseconds: bool = True) -> Self:
|
91
|
-
"""
|
92
|
-
Get the current epoch time in milliseconds or seconds in UTC.
|
93
|
-
|
94
|
-
Args:
|
95
|
-
milliseconds (bool): If True, return milliseconds. If False, return seconds. Default is True for milliseconds.
|
96
|
-
|
97
|
-
Returns:
|
98
|
-
EpochTimestamp: The current epoch time.
|
99
|
-
"""
|
100
|
-
multiplier: MULT = 1000 if milliseconds else 1
|
101
|
-
t: int = int(datetime.now(UTC).timestamp()) * multiplier
|
102
|
-
return cls(t, milliseconds=milliseconds)
|
103
|
-
|
104
|
-
@classmethod
|
105
|
-
def from_datetime(cls, dt: datetime, milliseconds: bool = True) -> Self:
|
106
|
-
"""
|
107
|
-
Convert a datetime object to an epoch timestamp.
|
108
|
-
|
109
|
-
Args:
|
110
|
-
dt (datetime): The datetime object to convert.
|
111
|
-
milliseconds (bool): If True, return milliseconds. If False, return seconds.
|
112
|
-
|
113
|
-
Returns:
|
114
|
-
EpochTimestamp: The epoch timestamp in milliseconds or seconds based on the milliseconds argument.
|
115
|
-
"""
|
116
|
-
multiplier: MULT = 1000 if milliseconds else 1
|
117
|
-
return cls(int(dt.astimezone(UTC).timestamp() * multiplier), milliseconds=milliseconds)
|
118
|
-
|
119
|
-
@classmethod
|
120
|
-
def from_dt_string(cls, dt_string: str, milliseconds: bool = True, fmt: str | None = None) -> Self:
|
121
|
-
"""
|
122
|
-
Convert a datetime string to an epoch timestamp.
|
123
|
-
|
124
|
-
Args:
|
125
|
-
dt_string (str): The datetime string to convert.
|
126
|
-
milliseconds (bool): If True, return milliseconds. If False, return seconds.
|
127
|
-
fmt (str): The format of the datetime string. Default is "%m-%d-%Y %I:%M %p".
|
128
|
-
|
129
|
-
Returns:
|
130
|
-
EpochTimestamp: The epoch timestamp in milliseconds or seconds based on the milliseconds argument.
|
131
|
-
"""
|
132
|
-
multiplier: MULT = 1000 if milliseconds else 1
|
133
|
-
dt: datetime = datetime.strptime(dt_string, fmt if fmt else cls._fullfmt)
|
134
|
-
return cls(int(dt.astimezone(UTC).timestamp() * multiplier))
|
135
|
-
|
136
|
-
def __new__(cls, value: int | None = None, milliseconds: bool = True) -> Self:
|
137
|
-
value = value if value is not None else cls.now(milliseconds)
|
138
|
-
return super().__new__(cls, value)
|
139
|
-
|
140
|
-
# endregion
|
141
|
-
|
142
|
-
# region Instance Methods
|
143
|
-
|
144
|
-
def __init__(self, value: int | None = None, milliseconds: bool = True):
|
145
|
-
self.milliseconds = milliseconds
|
146
|
-
self.multiplier: MULT = 1000 if self.milliseconds else 1
|
147
|
-
|
148
|
-
def __str__(self):
|
149
|
-
return int.__str__(self)
|
150
|
-
|
151
|
-
def __repr__(self) -> str:
|
152
|
-
if self.is_default:
|
153
|
-
return "EpochTimestamp(0) (Default Value)"
|
154
|
-
match self._repr_style:
|
155
|
-
case "int":
|
156
|
-
return f"{int(self)}"
|
157
|
-
case "object":
|
158
|
-
return f"EpochTimestamp({int(self)})"
|
159
|
-
case "datetime":
|
160
|
-
return f"{self.to_datetime.strftime(self._datefmt)}"
|
161
|
-
case _:
|
162
|
-
raise ValueError(f"Invalid repr style: {self._repr_style}")
|
163
|
-
|
164
|
-
def to_string(self, fmt: str | None = None, tz: TimeZoneType | None = None) -> str:
|
165
|
-
"""
|
166
|
-
Convert the epoch timestamp to a formatted string, taking into account the timezone and format.
|
167
|
-
|
168
|
-
Args:
|
169
|
-
fmt (str): The format of the datetime string. Default is "%m-%d-%Y %I:%M %p".
|
170
|
-
tz (TimeZoneType | None): The timezone to convert to. Default is PT_TIME_ZONE.
|
171
|
-
|
172
|
-
Returns:
|
173
|
-
str: The formatted date string.
|
174
|
-
"""
|
175
|
-
if self.is_default:
|
176
|
-
raise ValueError("Cannot convert default value to string.")
|
177
|
-
fmt = fmt if fmt else self._fullfmt
|
178
|
-
tz = tz if tz else self._tz
|
179
|
-
return self.to_datetime.astimezone(tz).strftime(fmt)
|
180
|
-
|
181
|
-
def date_str(self, tz: TimeZoneType | None = None) -> str:
|
182
|
-
"""
|
183
|
-
Convert the epoch timestamp to a date string in the format "%m-%d-%Y".
|
184
|
-
|
185
|
-
Args:
|
186
|
-
tz (TimeZoneType | None): The timezone to convert to. Default is PT_TIME_ZONE.
|
187
|
-
|
188
|
-
Returns:
|
189
|
-
str: The formatted date string.
|
190
|
-
"""
|
191
|
-
return self.to_string(fmt=self._datefmt, tz=tz if tz else self._tz)
|
192
|
-
|
193
|
-
def time_str(self, tz: TimeZoneType | None = None) -> str:
|
194
|
-
"""
|
195
|
-
Convert the epoch timestamp to a time string in the format "%I:%M %p".
|
196
|
-
|
197
|
-
Args:
|
198
|
-
tz (TimeZoneType | None): The timezone to convert to. Default is PT_TIME_ZONE.
|
199
|
-
|
200
|
-
Returns:
|
201
|
-
str: The formatted time string.
|
202
|
-
"""
|
203
|
-
return self.to_string(fmt=self._timefmt, tz=tz if tz else self._tz)
|
204
|
-
|
205
|
-
def add_timedelta(self, seconds: int = 0, milliseconds: int = 0) -> Self:
|
206
|
-
"""
|
207
|
-
Add a timedelta to the epoch timestamp.
|
208
|
-
|
209
|
-
Args:
|
210
|
-
seconds (int): The number of seconds to add. Default is 0.
|
211
|
-
milliseconds (int): The number of milliseconds to add. Default is 0.
|
212
|
-
|
213
|
-
Returns:
|
214
|
-
EpochTimestamp: The new epoch timestamp after adding the timedelta.
|
215
|
-
"""
|
216
|
-
total_seconds = seconds + (milliseconds / 1000)
|
217
|
-
new_timestamp = int((self.to_seconds + total_seconds) * self.multiplier)
|
218
|
-
new_ts: Self = type(self)(new_timestamp)
|
219
|
-
return new_ts
|
220
|
-
|
221
|
-
def start_of_day(self, tz: TimeZoneType | None = None) -> Self:
|
222
|
-
"""
|
223
|
-
Get the start of the day for the epoch timestamp, defaults to midnight of the day in UTC.
|
224
|
-
|
225
|
-
Args:
|
226
|
-
tz (TimeZoneType | None): The timezone to convert to. Will default to UTC if not provided.
|
227
|
-
|
228
|
-
Returns:
|
229
|
-
EpochTimestamp: The epoch timestamp at the start of the day.
|
230
|
-
"""
|
231
|
-
dt: datetime = self.to_datetime.astimezone(tz) if tz else self.to_datetime
|
232
|
-
dt = dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
233
|
-
return type(self).from_datetime(dt, milliseconds=self.milliseconds)
|
234
|
-
|
235
|
-
def end_of_day(self, tz: TimeZoneType | None = None) -> Self:
|
236
|
-
"""
|
237
|
-
Get the end of the day for the epoch timestamp, defaults to 23:59:59.999999 of the day in UTC.
|
238
|
-
|
239
|
-
Args:
|
240
|
-
tz (TimeZoneType | None): The timezone to convert to. Will default to UTC if not provided.
|
241
|
-
|
242
|
-
Returns:
|
243
|
-
EpochTimestamp: The epoch timestamp at the end of the day.
|
244
|
-
"""
|
245
|
-
dt: datetime = self.to_datetime.astimezone(tz) if tz else self.to_datetime
|
246
|
-
dt = dt.replace(hour=23, minute=59, second=59, microsecond=999999)
|
247
|
-
return type(self).from_datetime(dt, milliseconds=self.milliseconds)
|
248
|
-
|
249
|
-
# endregion
|
250
|
-
|
251
|
-
# region Properties
|
252
|
-
|
253
|
-
@property
|
254
|
-
def to_datetime(self) -> datetime:
|
255
|
-
"""
|
256
|
-
Convert the epoch timestamp to a datetime object in UTC.
|
257
|
-
|
258
|
-
Returns:
|
259
|
-
datetime: The datetime representation of the epoch timestamp.
|
260
|
-
"""
|
261
|
-
return datetime.fromtimestamp(self.to_seconds if self.milliseconds else self, tz=UTC)
|
262
|
-
|
263
|
-
@property
|
264
|
-
def to_seconds(self) -> int:
|
265
|
-
"""
|
266
|
-
Get the total seconds from the epoch timestamp, if the timestamp is in milliseconds, it converts it to seconds else
|
267
|
-
just returns the integer value.
|
268
|
-
|
269
|
-
Returns:
|
270
|
-
int: The total seconds since the epoch.
|
271
|
-
"""
|
272
|
-
return int(self // 1000) if self.milliseconds else int(self)
|
273
|
-
|
274
|
-
@property
|
275
|
-
def to_milliseconds(self) -> int:
|
276
|
-
"""
|
277
|
-
Get the total milliseconds from the epoch timestamp, if the timestamp is in seconds, it converts it to milliseconds else
|
278
|
-
just returns the integer value.
|
279
|
-
|
280
|
-
Returns:
|
281
|
-
int: The total milliseconds since the epoch.
|
282
|
-
"""
|
283
|
-
return int(self * 1000) if not self.milliseconds else int(self)
|
284
|
-
|
285
|
-
@property
|
286
|
-
def to_int(self) -> int:
|
287
|
-
"""
|
288
|
-
Converts the epoch timestamp to an integer value. Mostly used for type hinting since this *IS* an int.
|
289
|
-
|
290
|
-
Returns:
|
291
|
-
int: The total milliseconds since the epoch.
|
292
|
-
"""
|
293
|
-
return int(self)
|
294
|
-
|
295
|
-
@property
|
296
|
-
def is_default(self) -> bool:
|
297
|
-
"""
|
298
|
-
Check if the timestamp is zero, this is useful since zero is the default value.
|
299
|
-
|
300
|
-
Returns:
|
301
|
-
bool: True if the timestamp is zero, False otherwise.
|
302
|
-
"""
|
303
|
-
return self == 0
|
304
|
-
|
305
|
-
# endregion
|
306
|
-
|
307
|
-
|
308
|
-
# if __name__ == "__main__":
|
309
|
-
# # Example usage
|
310
|
-
# default_value = EpochTimestamp(0)
|
311
|
-
# ts = EpochTimestamp.now()
|
312
|
-
# t2 = EpochTimestamp.now(milliseconds=False)
|
313
|
-
|
314
|
-
# print(f"Default Zero Value = {default_value}")
|
315
|
-
# print(f"Current timestamp in milliseconds: {ts} {ts.milliseconds=}")
|
316
|
-
# print(f"Current timestamp in seconds: {t2} {t2.milliseconds=}")
|
@@ -1,80 +0,0 @@
|
|
1
|
-
from collections.abc import Callable
|
2
|
-
from contextlib import contextmanager
|
3
|
-
from functools import wraps
|
4
|
-
|
5
|
-
from ..logging import ConsoleLogger
|
6
|
-
from ._time_class import EpochTimestamp
|
7
|
-
|
8
|
-
|
9
|
-
def create_timer(**defaults):
|
10
|
-
"""A way to set defaults for a frequently used timer decorator."""
|
11
|
-
|
12
|
-
def timer_decorator(func):
|
13
|
-
@wraps(func)
|
14
|
-
def wrapper(*args, **kwargs):
|
15
|
-
defaults["name"] = func.__name__
|
16
|
-
with timer(**defaults):
|
17
|
-
return func(*args, **kwargs)
|
18
|
-
|
19
|
-
return wrapper
|
20
|
-
|
21
|
-
return timer_decorator
|
22
|
-
|
23
|
-
|
24
|
-
@contextmanager
|
25
|
-
def timer(**kwargs):
|
26
|
-
data: TimerData = kwargs.get("data", None) or TimerData(kwargs=kwargs)
|
27
|
-
data.start()
|
28
|
-
try:
|
29
|
-
yield data
|
30
|
-
finally:
|
31
|
-
data.stop()
|
32
|
-
|
33
|
-
|
34
|
-
class TimerData:
|
35
|
-
def __init__(self, **kwargs):
|
36
|
-
self.name: str = kwargs.get("name", "Default Timer")
|
37
|
-
self.start_time: EpochTimestamp = EpochTimestamp(0)
|
38
|
-
self.end_time: EpochTimestamp = EpochTimestamp(0)
|
39
|
-
self._raw_elapsed_time: EpochTimestamp = EpochTimestamp(0)
|
40
|
-
self.console: ConsoleLogger | None = self.get_console(kwargs.get("output", False))
|
41
|
-
self.callback: Callable | None = kwargs.get("callback", None)
|
42
|
-
self._style: str = kwargs.get("style", "bold green")
|
43
|
-
|
44
|
-
def get_console(self, to_console: bool) -> ConsoleLogger | None:
|
45
|
-
if to_console:
|
46
|
-
try:
|
47
|
-
console = ConsoleLogger.get_instance() # will crash if nothing else has initialized ConsoleLogger
|
48
|
-
except RuntimeError:
|
49
|
-
console = ConsoleLogger()
|
50
|
-
return console
|
51
|
-
|
52
|
-
def start(self):
|
53
|
-
self.start_time = EpochTimestamp.now()
|
54
|
-
|
55
|
-
def send_callback(self):
|
56
|
-
if self.callback is not None:
|
57
|
-
self.callback(self)
|
58
|
-
|
59
|
-
def stop(self):
|
60
|
-
self.end_time = EpochTimestamp.now()
|
61
|
-
self._raw_elapsed_time = EpochTimestamp(self.end_time - self.start_time)
|
62
|
-
if self.callback:
|
63
|
-
self.send_callback()
|
64
|
-
if self.console:
|
65
|
-
self.console.print(f"[{self.name}] Elapsed time: {self.elapsed_seconds:.2f} seconds", style=self._style)
|
66
|
-
|
67
|
-
@property
|
68
|
-
def elapsed_milliseconds(self) -> int:
|
69
|
-
if self._raw_elapsed_time:
|
70
|
-
return self._raw_elapsed_time.to_milliseconds
|
71
|
-
return -1
|
72
|
-
|
73
|
-
@property
|
74
|
-
def elapsed_seconds(self) -> int:
|
75
|
-
if self._raw_elapsed_time:
|
76
|
-
return self._raw_elapsed_time.to_seconds
|
77
|
-
return -1
|
78
|
-
|
79
|
-
|
80
|
-
__all__ = ["TimerData"]
|
@@ -1,17 +0,0 @@
|
|
1
|
-
def add_ord_suffix(number: int) -> str:
|
2
|
-
"""
|
3
|
-
Add an ordinal suffix to a given number, usually used for dates or rankings.
|
4
|
-
|
5
|
-
Parameters:
|
6
|
-
number: int - The number to add an ordinal suffix to.
|
7
|
-
|
8
|
-
Returns:
|
9
|
-
str - The number with its ordinal suffix.
|
10
|
-
"""
|
11
|
-
suffix = ["th", "st", "nd", "rd", "th"][min(number % 10, 4)]
|
12
|
-
if 11 <= (number % 100) <= 13:
|
13
|
-
suffix = "th"
|
14
|
-
return f"{number}{suffix}"
|
15
|
-
|
16
|
-
|
17
|
-
__all__ = ["add_ord_suffix"]
|
@@ -1,218 +0,0 @@
|
|
1
|
-
from datetime import UTC, datetime, timedelta
|
2
|
-
|
3
|
-
from ..constants.date_related import DATE_FORMAT, DT_FORMAT_WITH_TZ, PT_TIME_ZONE, TIME_FORMAT, TimeZoneType
|
4
|
-
from ._time_class import EpochTimestamp
|
5
|
-
|
6
|
-
|
7
|
-
class TimeTools:
|
8
|
-
"""
|
9
|
-
A utility class for managing time-related operations, including epoch timestamps, date formatting,
|
10
|
-
and timezone handling.
|
11
|
-
|
12
|
-
Attributes:
|
13
|
-
timezone (TimeZoneType): The timezone to use for date and time operations. Defaults to PT_TIME_ZONE.
|
14
|
-
datefmt (str): The format string for date and time formatting. Defaults to DT_FORMAT_WITH_TZ.
|
15
|
-
"""
|
16
|
-
|
17
|
-
def __init__(self, timezone=PT_TIME_ZONE, datefmt=DT_FORMAT_WITH_TZ):
|
18
|
-
self.timezone: TimeZoneType = timezone
|
19
|
-
self.datefmt: str = datefmt
|
20
|
-
|
21
|
-
def now(self, as_str: bool = False) -> EpochTimestamp | str:
|
22
|
-
"""
|
23
|
-
Get a UTC epoch timestamp in milliseconds or a formatted string of the current date and time.
|
24
|
-
|
25
|
-
Args:
|
26
|
-
as_str (bool): If True, return formatted string instead of timestamp.
|
27
|
-
|
28
|
-
Returns:
|
29
|
-
EpochTimestamp | str: The current epoch timestamp in milliseconds or formatted string.
|
30
|
-
"""
|
31
|
-
if as_str:
|
32
|
-
return self.format_now
|
33
|
-
return EpochTimestamp.now()
|
34
|
-
|
35
|
-
@property
|
36
|
-
def format_now(self) -> str:
|
37
|
-
"""
|
38
|
-
Get the current date and time as a formatted string.
|
39
|
-
|
40
|
-
Returns:
|
41
|
-
str: The current date and time as a formatted string.
|
42
|
-
"""
|
43
|
-
return EpochTimestamp.now().to_string(fmt=self.datefmt, tz=self.timezone)
|
44
|
-
|
45
|
-
def dt_to_ts(self, dt: datetime) -> EpochTimestamp:
|
46
|
-
"""
|
47
|
-
Convert a datetime object to an epoch timestamp in milliseconds.
|
48
|
-
|
49
|
-
Args:
|
50
|
-
dt (datetime): The datetime object to convert.
|
51
|
-
|
52
|
-
Returns:
|
53
|
-
EpochTimestamp: The epoch timestamp in milliseconds.
|
54
|
-
"""
|
55
|
-
dt_str = dt.strftime(self.datefmt)
|
56
|
-
return EpochTimestamp.from_dt_string(dt_str, milliseconds=True, fmt=self.datefmt)
|
57
|
-
|
58
|
-
def str_to_ts(self, date_str: str, fmt: str | None = None) -> EpochTimestamp:
|
59
|
-
"""
|
60
|
-
Convert a date string to an epoch timestamp in milliseconds.
|
61
|
-
|
62
|
-
Args:
|
63
|
-
date_str (str): The date string to convert.
|
64
|
-
fmt (str | None): Format string. Uses instance default if not provided.
|
65
|
-
|
66
|
-
Returns:
|
67
|
-
EpochTimestamp: The epoch timestamp in milliseconds.
|
68
|
-
"""
|
69
|
-
format_str = fmt or self.datefmt
|
70
|
-
return EpochTimestamp.from_dt_string(date_str, milliseconds=True, fmt=format_str)
|
71
|
-
|
72
|
-
def ts_to_str(self, ts: EpochTimestamp) -> str:
|
73
|
-
"""
|
74
|
-
Convert an epoch timestamp to a formatted date string.
|
75
|
-
|
76
|
-
Args:
|
77
|
-
ts (EpochTimestamp): The epoch timestamp to convert.
|
78
|
-
|
79
|
-
Returns:
|
80
|
-
str: The formatted date string.
|
81
|
-
"""
|
82
|
-
return ts.to_string(fmt=self.datefmt, tz=self.timezone)
|
83
|
-
|
84
|
-
def ts_to_dt(self, ts: EpochTimestamp) -> datetime:
|
85
|
-
"""
|
86
|
-
Convert an epoch timestamp to a datetime object.
|
87
|
-
|
88
|
-
Args:
|
89
|
-
ts (EpochTimestamp): The epoch timestamp to convert.
|
90
|
-
|
91
|
-
Returns:
|
92
|
-
datetime: The datetime object.
|
93
|
-
"""
|
94
|
-
return ts.to_datetime.astimezone(self.timezone)
|
95
|
-
|
96
|
-
def add_delta(
|
97
|
-
self,
|
98
|
-
ts: EpochTimestamp,
|
99
|
-
days: int = 0,
|
100
|
-
hours: int = 0,
|
101
|
-
minutes: int = 0,
|
102
|
-
seconds: int = 0,
|
103
|
-
dt_obj: timedelta | None = None,
|
104
|
-
) -> EpochTimestamp:
|
105
|
-
"""
|
106
|
-
Add a timedelta to an epoch timestamp.
|
107
|
-
|
108
|
-
Args:
|
109
|
-
ts (EpochTimestamp): The epoch timestamp to modify.
|
110
|
-
days (int): Number of days to add.
|
111
|
-
hours (int): Number of hours to add.
|
112
|
-
minutes (int): Number of minutes to add.
|
113
|
-
seconds (int): Number of seconds to add.
|
114
|
-
dt_obj (timedelta | None): A timedelta object to add (combined with other params).
|
115
|
-
|
116
|
-
Returns:
|
117
|
-
EpochTimestamp: The modified epoch timestamp.
|
118
|
-
"""
|
119
|
-
if dt_obj:
|
120
|
-
if not isinstance(dt_obj, timedelta):
|
121
|
-
raise TypeError("timedelta_obj must be an instance of datetime.timedelta")
|
122
|
-
days += dt_obj.days
|
123
|
-
seconds += int(dt_obj.seconds + (dt_obj.microseconds / 1_000_000))
|
124
|
-
else:
|
125
|
-
seconds = seconds + (minutes * 60) + (hours * 3600) + (days * 86400)
|
126
|
-
return ts.add_timedelta(seconds=seconds)
|
127
|
-
|
128
|
-
def get_day_range(self, ts: EpochTimestamp | None = None) -> tuple[EpochTimestamp, EpochTimestamp]:
|
129
|
-
"""
|
130
|
-
Get the start and end of a day from an epoch timestamp in the instance timezone, defaulting to now.
|
131
|
-
|
132
|
-
Args:
|
133
|
-
ts (EpochTimestamp): The epoch timestamp to convert (optional, defaults to now).
|
134
|
-
|
135
|
-
Returns:
|
136
|
-
tuple[EpochTimestamp, EpochTimestamp]: A tuple containing the start and end of the day as epoch timestamps.
|
137
|
-
"""
|
138
|
-
if ts is None:
|
139
|
-
ts = EpochTimestamp.now()
|
140
|
-
|
141
|
-
timestamp_start: EpochTimestamp = ts.start_of_day(tz=self.timezone)
|
142
|
-
timestamp_end: EpochTimestamp = ts.end_of_day(tz=self.timezone)
|
143
|
-
return timestamp_start, timestamp_end
|
144
|
-
|
145
|
-
def is_same_day(self, start_date: EpochTimestamp, end_date: EpochTimestamp) -> bool:
|
146
|
-
"""
|
147
|
-
Check if two epoch timestamps are on the same day.
|
148
|
-
|
149
|
-
Args:
|
150
|
-
start_date (EpochTimestamp): The first epoch timestamp.
|
151
|
-
end_date (EpochTimestamp): The second epoch timestamp.
|
152
|
-
|
153
|
-
Returns:
|
154
|
-
bool: True if both timestamps are on the same day, False otherwise.
|
155
|
-
"""
|
156
|
-
dt1: datetime = datetime.fromtimestamp(start_date.to_seconds, tz=UTC)
|
157
|
-
dt2: datetime = datetime.fromtimestamp(end_date.to_seconds, tz=UTC)
|
158
|
-
return dt1.date() == dt2.date()
|
159
|
-
|
160
|
-
def is_multi_day(self, start_date: str | datetime, end_date: str | datetime) -> bool:
|
161
|
-
"""Determines if the span between two dates covers multiple days.
|
162
|
-
|
163
|
-
Args:
|
164
|
-
start_date (str | datetime): The start date.
|
165
|
-
end_date (str | datetime): The end date.
|
166
|
-
|
167
|
-
Returns:
|
168
|
-
bool: If the span covers multiple days, return True. Else, return False.
|
169
|
-
"""
|
170
|
-
if isinstance(start_date, str):
|
171
|
-
start_date = datetime.strptime(start_date, self.datefmt)
|
172
|
-
if isinstance(end_date, str):
|
173
|
-
end_date = datetime.strptime(end_date, self.datefmt)
|
174
|
-
return start_date.date() != end_date.date()
|
175
|
-
|
176
|
-
def time_only(self, ts: EpochTimestamp) -> str:
|
177
|
-
"""
|
178
|
-
Get the time part of an epoch timestamp as a formatted string.
|
179
|
-
|
180
|
-
Args:
|
181
|
-
ts (EpochTimestamp): The epoch timestamp to convert.
|
182
|
-
|
183
|
-
Returns:
|
184
|
-
str: The time part of the timestamp.
|
185
|
-
"""
|
186
|
-
return ts.to_string(fmt=TIME_FORMAT, tz=self.timezone)
|
187
|
-
|
188
|
-
def date_only(self, ts: EpochTimestamp) -> str:
|
189
|
-
"""
|
190
|
-
Get the date part of an epoch timestamp as a formatted string.
|
191
|
-
|
192
|
-
Args:
|
193
|
-
ts (EpochTimestamp): The epoch timestamp to convert.
|
194
|
-
|
195
|
-
Returns:
|
196
|
-
str: The date part of the timestamp.
|
197
|
-
"""
|
198
|
-
return ts.to_string(fmt=DATE_FORMAT, tz=self.timezone)
|
199
|
-
|
200
|
-
|
201
|
-
# if __name__ == "__main__":
|
202
|
-
|
203
|
-
# # def example_callback(timer_data: TimerData):
|
204
|
-
# # print(f"Timer '{timer_data.name}' finished in {timer_data._raw_elapsed_time} ms")
|
205
|
-
|
206
|
-
# # # Example usage
|
207
|
-
# # with timer(
|
208
|
-
# # name="Tester Timer",
|
209
|
-
# # console=True,
|
210
|
-
# # ) as time:
|
211
|
-
# # sleep(2) # Simulate some work
|
212
|
-
# # data: TimerData = time
|
213
|
-
|
214
|
-
# # get start and end of day
|
215
|
-
# time_tools = TimeTools()
|
216
|
-
# start_of_day, end_of_day = time_tools.get_day_range()
|
217
|
-
# print(f"Start of day: {start_of_day.to_string()}")
|
218
|
-
# print(f"End of day: {end_of_day.to_string()}")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/_base_file_handler.py
RENAMED
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/file_handler_factory.py
RENAMED
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/json_file_handler.py
RENAMED
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/log_file_handler.py
RENAMED
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/txt_file_handler.py
RENAMED
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/files/file_handlers/yaml_file_handler.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/_console_junk.py
RENAMED
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_level_sin.py
RENAMED
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_logger.py
RENAMED
File without changes
|
{bear_utils-0.7.11 → bear_utils-0.7.13}/src/bear_utils/logging/logger_manager/loggers/_sub_logger.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|