pyutilities 2.4.2__tar.gz → 2.5.0__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.
- {pyutilities-2.4.2 → pyutilities-2.5.0}/PKG-INFO +29 -33
- pyutilities-2.5.0/README.md +42 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/pyproject.toml +12 -12
- pyutilities-2.5.0/src/pyutilities/utils/datetime_utils.py +148 -0
- pyutilities-2.5.0/src/pyutilities/utils/structures.py +62 -0
- pyutilities-2.4.2/docs/README-PUB.md +0 -46
- pyutilities-2.4.2/src/pyutilities/utils/datetime_utils.py +0 -78
- {pyutilities-2.4.2 → pyutilities-2.5.0}/LICENSE +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/__init__.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/cli/__init__.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/cli/fedit.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/cli/pyutils.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/config/__init__.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/config/configuration.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/defaults.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/exception.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/io/__init__.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/io/io_utils.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/log/__init__.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/log/log_manager.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/logging.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/sys/__init__.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/sys/sys_utils.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/utils/__init__.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/utils/common_utils.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/utils/decorators.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/utils/lambdas.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/utils/string_utils.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/web/__init__.py +0 -0
- {pyutilities-2.4.2 → pyutilities-2.5.0}/src/pyutilities/web/http_client.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyutilities
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
4
4
|
Summary: PyUtilities :: Useful python 3+ utilities library for various use cases.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -28,13 +28,13 @@ Requires-Dist: loguru (==0.7.3)
|
|
|
28
28
|
Requires-Dist: markdown (>=3.7,<4.0)
|
|
29
29
|
Requires-Dist: marshmallow (>=4.1,<5.0)
|
|
30
30
|
Requires-Dist: openpyxl (==3.1.5)
|
|
31
|
-
Requires-Dist: paramiko (==
|
|
31
|
+
Requires-Dist: paramiko (==5.*)
|
|
32
32
|
Requires-Dist: pendulum (>=3.2,<4.0)
|
|
33
33
|
Requires-Dist: prettytable (>=3.14,<4.0)
|
|
34
34
|
Requires-Dist: prettytable (>=3.17,<4.0)
|
|
35
35
|
Requires-Dist: pydantic (>=2.12.5,<3.0.0)
|
|
36
36
|
Requires-Dist: pydantic-settings (==2.*)
|
|
37
|
-
Requires-Dist: pydantic-yaml (
|
|
37
|
+
Requires-Dist: pydantic-yaml (>=1.6,<2.0)
|
|
38
38
|
Requires-Dist: pyfiglet (>=1.0,<2.0)
|
|
39
39
|
Requires-Dist: python-dateutil (>=2.9,<3.0)
|
|
40
40
|
Requires-Dist: python-dotenv (>=1.2,<2.0)
|
|
@@ -42,7 +42,7 @@ Requires-Dist: pytz (==2026.*)
|
|
|
42
42
|
Requires-Dist: pyyaml (==6.*)
|
|
43
43
|
Requires-Dist: requests (>=2.32,<3.0)
|
|
44
44
|
Requires-Dist: rich-pyfiglet (>=1.0,<2.0)
|
|
45
|
-
Requires-Dist: ruamel.yaml (==0.*)
|
|
45
|
+
Requires-Dist: ruamel.yaml (==0.18.*)
|
|
46
46
|
Requires-Dist: urllib3 (>=2.6,<3.0)
|
|
47
47
|
Requires-Dist: xlrd (>=2.0.1,<2.1.0)
|
|
48
48
|
Requires-Dist: xlwings (>=0.35,<1.0)
|
|
@@ -53,50 +53,46 @@ Project-URL: Homepage, https://pypi.org/project/pyutilities
|
|
|
53
53
|
Project-URL: Repository, https://github.com/dmitry-ed-gusev/pyutilities
|
|
54
54
|
Description-Content-Type: text/markdown
|
|
55
55
|
|
|
56
|
-
# Python Utilities Library
|
|
56
|
+
# Python Utilities Library (PyUtilities)
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
*Last update: 15.05.2026*
|
|
58
|
+
**Dmitrii Gusev, 2018-2026.**
|
|
60
59
|
|
|
61
60
|
## Project Description
|
|
62
61
|
|
|
63
|
-
Useful utilities functions for various needs for the python 3.10
|
|
62
|
+
Useful utilities functions for various needs for the **python 3.10+**. Containing many 'general purpose' functions for various areas. Using of this library may simplify/help with the development in various 'common' tasks.
|
|
64
63
|
|
|
65
|
-
##
|
|
64
|
+
## Installation
|
|
66
65
|
|
|
67
|
-
|
|
66
|
+
There are no special pre-requisites for the library to be installed, except **python 3.10+**
|
|
67
|
+
In order to install this library, use the following command:
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- added several useful string functions
|
|
73
|
-
- added LoggingManager component for loguru simple configuration
|
|
74
|
-
- v.2.4.1/v.2.4.2 - minor docs fixes
|
|
69
|
+
```bash
|
|
70
|
+
pip install pyutilities
|
|
71
|
+
```
|
|
75
72
|
|
|
76
|
-
|
|
73
|
+
**Note: versions 2.1.0, 2.1.1 are intended only for the python version = 3.10 and can be installed only for it!**
|
|
77
74
|
|
|
78
|
-
|
|
75
|
+
## Tech Details
|
|
79
76
|
|
|
80
|
-
###
|
|
77
|
+
### Project modules
|
|
81
78
|
|
|
82
|
-
|
|
79
|
+
- **cli** - Command Line Integration/Interface - module is under development now :)
|
|
80
|
+
- **config** - configuration module, can be used anywhere
|
|
81
|
+
- **io** - input/output utilities
|
|
82
|
+
- **log** - logging helper classes
|
|
83
|
+
- **sys** - system modules
|
|
84
|
+
- **utils** - various common utilities (common, strings, dates, structures, etc.)
|
|
85
|
+
- **web** - web client, simple web/http server
|
|
83
86
|
|
|
84
|
-
###
|
|
87
|
+
### Library Usage Examples
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
See folder **[examples]** in the project root repository.
|
|
87
90
|
|
|
88
|
-
|
|
91
|
+
### Development Environment Setup
|
|
89
92
|
|
|
90
|
-
|
|
93
|
+
There are various shell scripts in the root of the project repository, all of them are well-commented - see there.
|
|
91
94
|
|
|
92
|
-
|
|
95
|
+
### Publishing to PyPi Registry
|
|
93
96
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
- set of the 'minor' and 'experimental' releases
|
|
97
|
-
- various set of functions without consistency
|
|
98
|
-
- many 'experimental' functions without proper testing
|
|
99
|
-
- a lot of unnecessary code
|
|
100
|
-
- experiments with building/dependencies management tools - no tool, pipenv poetry
|
|
101
|
-
- unstable list of dependencies with obsolete versions
|
|
97
|
+
Look at the script **_deploy.sh** in the project repo root folder.
|
|
102
98
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Python Utilities Library (PyUtilities)
|
|
2
|
+
|
|
3
|
+
**Dmitrii Gusev, 2018-2026.**
|
|
4
|
+
|
|
5
|
+
## Project Description
|
|
6
|
+
|
|
7
|
+
Useful utilities functions for various needs for the **python 3.10+**. Containing many 'general purpose' functions for various areas. Using of this library may simplify/help with the development in various 'common' tasks.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
There are no special pre-requisites for the library to be installed, except **python 3.10+**
|
|
12
|
+
In order to install this library, use the following command:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install pyutilities
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Note: versions 2.1.0, 2.1.1 are intended only for the python version = 3.10 and can be installed only for it!**
|
|
19
|
+
|
|
20
|
+
## Tech Details
|
|
21
|
+
|
|
22
|
+
### Project modules
|
|
23
|
+
|
|
24
|
+
- **cli** - Command Line Integration/Interface - module is under development now :)
|
|
25
|
+
- **config** - configuration module, can be used anywhere
|
|
26
|
+
- **io** - input/output utilities
|
|
27
|
+
- **log** - logging helper classes
|
|
28
|
+
- **sys** - system modules
|
|
29
|
+
- **utils** - various common utilities (common, strings, dates, structures, etc.)
|
|
30
|
+
- **web** - web client, simple web/http server
|
|
31
|
+
|
|
32
|
+
### Library Usage Examples
|
|
33
|
+
|
|
34
|
+
See folder **[examples]** in the project root repository.
|
|
35
|
+
|
|
36
|
+
### Development Environment Setup
|
|
37
|
+
|
|
38
|
+
There are various shell scripts in the root of the project repository, all of them are well-commented - see there.
|
|
39
|
+
|
|
40
|
+
### Publishing to PyPi Registry
|
|
41
|
+
|
|
42
|
+
Look at the script **_deploy.sh** in the project repo root folder.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# - most of modules should be typed (used mypy stubs libraries)
|
|
9
9
|
#
|
|
10
10
|
# Created: Dmitrii Gusev, 30.05.2025
|
|
11
|
-
# Modified: Dmitrii Gusev,
|
|
11
|
+
# Modified: Dmitrii Gusev, 25.05.2026
|
|
12
12
|
#
|
|
13
13
|
####################################################################################################
|
|
14
14
|
|
|
@@ -20,13 +20,13 @@ build-backend = "poetry.core.masonry.api"
|
|
|
20
20
|
# -- project / poetry utility meta-information
|
|
21
21
|
[project]
|
|
22
22
|
name = "pyutilities"
|
|
23
|
-
version = "2.
|
|
23
|
+
version = "2.5.0"
|
|
24
24
|
description = "PyUtilities :: Useful python 3+ utilities library for various use cases."
|
|
25
25
|
authors = [
|
|
26
26
|
{name = "Dmitrii Gusev", email = "dmitry.ed.gusev@gmail.com"},
|
|
27
27
|
]
|
|
28
28
|
license = "MIT"
|
|
29
|
-
readme = "
|
|
29
|
+
readme = "README.md"
|
|
30
30
|
requires-python = ">=3.10,<4"
|
|
31
31
|
keywords = [
|
|
32
32
|
"Python Utilities", "Useful Functions", "String Utilities", "CLI Functions", "toolset", "library",
|
|
@@ -63,15 +63,15 @@ dependencies = [
|
|
|
63
63
|
|
|
64
64
|
# -- data validation and marshalling (JSON/YAML) --
|
|
65
65
|
"pydantic (>=2.12.5,<3.0.0)",
|
|
66
|
-
"pydantic-yaml
|
|
66
|
+
"pydantic-yaml ~=1.6",
|
|
67
67
|
"pydantic-settings ==2.*",
|
|
68
68
|
"marshmallow ~=4.1",
|
|
69
69
|
"pyyaml ==6.*",
|
|
70
|
-
"ruamel.yaml ==0.*",
|
|
70
|
+
"ruamel.yaml ==0.18.*",
|
|
71
71
|
|
|
72
72
|
# -- technical libraries
|
|
73
73
|
"urllib3~=2.6", # - allowed: >=2.3.0 <3.0.0
|
|
74
|
-
"paramiko==
|
|
74
|
+
"paramiko ==5.*",
|
|
75
75
|
"requests~=2.32", # - allowed: >=2.32.0 <3.0.0
|
|
76
76
|
"markdown~=3.7", # - allowed: >=3.7.0 <4.0.0
|
|
77
77
|
"prettytable~=3.14", # - allowed: >=3.14.0 <4.0.0
|
|
@@ -114,7 +114,7 @@ dev = [
|
|
|
114
114
|
"hypothesis ==6.*",
|
|
115
115
|
|
|
116
116
|
# -- typing libraries + typing stubs for runtime dependencies --
|
|
117
|
-
"mypy ==
|
|
117
|
+
"mypy ==2.*", # - typing library
|
|
118
118
|
"types-six ==1.*",
|
|
119
119
|
"types-mock ==5.*",
|
|
120
120
|
"types-paramiko ==4.*",
|
|
@@ -150,7 +150,7 @@ dev = [
|
|
|
150
150
|
"responses ==0.*", # - used by many testing/code quality libraries
|
|
151
151
|
|
|
152
152
|
# -- readline module depending on the platform
|
|
153
|
-
"pyreadline3 ==3
|
|
153
|
+
"pyreadline3 ==3.* ; sys_platform == 'win32' or sys_platform == 'cygwin'",
|
|
154
154
|
"gnureadline ==8.2.13 ; sys_platform != 'win32'"
|
|
155
155
|
|
|
156
156
|
]
|
|
@@ -165,11 +165,11 @@ research = [ # - research dependencies (Jupyter, etc.)
|
|
|
165
165
|
packages = [{include = "pyutilities", from = "src"}]
|
|
166
166
|
|
|
167
167
|
# -- poetry :: source repositories setup
|
|
168
|
-
[[tool.poetry.source]]
|
|
169
|
-
name = "severstal_repo"
|
|
170
|
-
url = "https://repo.severstal.severstalgroup.com/artifactory/api/pypi/pypi/simple/"
|
|
168
|
+
# [[tool.poetry.source]]
|
|
169
|
+
# name = "severstal_repo"
|
|
170
|
+
# url = "https://repo.severstal.severstalgroup.com/artifactory/api/pypi/pypi/simple/"
|
|
171
171
|
# priority = "primary" # - primary packages source
|
|
172
|
-
priority = "supplemental" # - packages source will be used when primary is not available...
|
|
172
|
+
# priority = "supplemental" # - packages source will be used when primary is not available...
|
|
173
173
|
|
|
174
174
|
[tool.poetry.dependencies]
|
|
175
175
|
python = ">=3.10,<4"
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Useful date/time utilities and functions.
|
|
5
|
+
|
|
6
|
+
Created: Dmitrii Gusev, 22.03.2026
|
|
7
|
+
Modified: Dmitrii Gusev, 25.05.2026
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import calendar
|
|
11
|
+
import logging
|
|
12
|
+
from datetime import datetime, timedelta, timezone
|
|
13
|
+
from functools import lru_cache
|
|
14
|
+
|
|
15
|
+
from pyutilities.defaults import MSG_MODULE_ISNT_RUNNABLE
|
|
16
|
+
|
|
17
|
+
# DATETIME :: timezones defaults
|
|
18
|
+
MSK_TIMEZONE: timezone = timezone(timedelta(hours=3), name="Moscow Timezone (GMT+3)")
|
|
19
|
+
MSK_TIMEZONE_NAME: str = "Europe/Moscow"
|
|
20
|
+
# - CACHE :: cache setup (size) for cached functions/methods
|
|
21
|
+
LRU_CACHE_SIZE: int = 128
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
log = logging.getLogger(__name__)
|
|
25
|
+
log.addHandler(logging.NullHandler())
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_timestamp(
|
|
29
|
+
current_timezone: timezone = MSK_TIMEZONE,
|
|
30
|
+
days: float = 0,
|
|
31
|
+
hours: float = 0,
|
|
32
|
+
minutes: float = 0,
|
|
33
|
+
seconds: float = 0,
|
|
34
|
+
) -> datetime:
|
|
35
|
+
"""Return timestamp: now (in the default timezone) +/- the specified time delta in hours / minutes /
|
|
36
|
+
seconds. Default timezone can be changed by the function argument."""
|
|
37
|
+
|
|
38
|
+
return datetime.now(current_timezone) + timedelta(
|
|
39
|
+
days=days, hours=hours, minutes=minutes, seconds=seconds
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@lru_cache(maxsize=LRU_CACHE_SIZE)
|
|
44
|
+
def get_timestampc(
|
|
45
|
+
current_timezone: timezone = MSK_TIMEZONE,
|
|
46
|
+
days: float = 0,
|
|
47
|
+
hours: float = 0,
|
|
48
|
+
minutes: float = 0,
|
|
49
|
+
seconds: float = 0,
|
|
50
|
+
) -> datetime:
|
|
51
|
+
"""CACHED. Cached version of the get_timestamp() method."""
|
|
52
|
+
|
|
53
|
+
return get_timestamp(current_timezone, days, hours, minutes, seconds)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_dates_range_before_date(date: datetime, tzinfo: timezone) -> tuple[int, int]:
|
|
57
|
+
"""Generates two dates range - date_from/date_to for the time period 'before today' - from the 1st day
|
|
58
|
+
of the current month till the today - 1 day (current month). In case today is 1st day - range for the
|
|
59
|
+
whole previous month, if today is 01.01.XXXX - range for 01.12.XXXX-1 - 31.12.XXXX-1.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
log.debug("get_dates_range_before_date(): the date [%s].", date)
|
|
63
|
+
|
|
64
|
+
tstamp_from: int = 0
|
|
65
|
+
tstamp_to: int = 0
|
|
66
|
+
|
|
67
|
+
if date: # if date is OK (not empty/None)
|
|
68
|
+
|
|
69
|
+
# - processing and calculating dates
|
|
70
|
+
if date.day == 1: # today - 1st day of month, we need report for the previous month
|
|
71
|
+
|
|
72
|
+
if date.month == 1: # we are at 01.01.XXXX - we need report for Dec.XXXX - 1
|
|
73
|
+
|
|
74
|
+
date_from = datetime(date.year - 1, 12, 1, tzinfo=tzinfo) # from: 01 Dec Year-1 (prev. year)
|
|
75
|
+
date_to = datetime(date.year - 1, 12, 31, tzinfo=tzinfo) # to: 31 Dec Year-1 (prev. year)
|
|
76
|
+
|
|
77
|
+
else: # we are at 01.XX.XXXX - we need report for previous month
|
|
78
|
+
|
|
79
|
+
# from: 01 Month-1 Year
|
|
80
|
+
date_from = datetime(date.year, date.month - 1, 1, tzinfo=tzinfo)
|
|
81
|
+
# last day of the previous month
|
|
82
|
+
_, last_day = calendar.monthrange(date.year, date.month - 1)
|
|
83
|
+
# to: Last Day Month-1 Year
|
|
84
|
+
date_to = datetime(date.year, date.month - 1, last_day, tzinfo=tzinfo)
|
|
85
|
+
|
|
86
|
+
else: # today isn't the 1st, we need report from 1st till yesterday
|
|
87
|
+
|
|
88
|
+
date_from = datetime(date.year, date.month, 1, tzinfo=tzinfo) # from: 01 Month Year
|
|
89
|
+
date_to = datetime(date.year, date.month, date.day - 1, tzinfo=tzinfo) # to: Day-1 Month Year
|
|
90
|
+
|
|
91
|
+
# - final date/time - date from: XX.XX.XX 00:00:00
|
|
92
|
+
tstamp_from = int(
|
|
93
|
+
datetime(
|
|
94
|
+
date_from.year, date_from.month, date_from.day, hour=0, minute=0, second=0, tzinfo=tzinfo
|
|
95
|
+
).timestamp()
|
|
96
|
+
)
|
|
97
|
+
# - final date/time - # date to: XX.XX.XXXX 23:59:59
|
|
98
|
+
tstamp_to = int(
|
|
99
|
+
datetime(
|
|
100
|
+
date_to.year, date_to.month, date_to.day, hour=23, minute=59, second=59, tzinfo=tzinfo
|
|
101
|
+
).timestamp()
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
log.debug("Timestamps for [%s]: from [%s], to [%s].", date, tstamp_from, tstamp_to)
|
|
105
|
+
|
|
106
|
+
# - return the tuple of values
|
|
107
|
+
return (tstamp_from, tstamp_to)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@lru_cache(maxsize=LRU_CACHE_SIZE)
|
|
111
|
+
def get_dates_range_before_datec(date: datetime, tzinfo: timezone) -> tuple[int, int]:
|
|
112
|
+
"""CACHED. Cached version of the get_dates_range_before_date()."""
|
|
113
|
+
|
|
114
|
+
return get_dates_range_before_date(date, tzinfo)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def human_readable_duration_seconds(duration_seconds):
|
|
118
|
+
"""Convert duration in seconds into human-readable string-duration."""
|
|
119
|
+
|
|
120
|
+
days = duration_seconds // (24 * 3600)
|
|
121
|
+
hours = (duration_seconds % (24 * 3600)) // 3600
|
|
122
|
+
minutes = (duration_seconds % (24 * 3600)) % 3600 // 60
|
|
123
|
+
seconds = duration_seconds % 3600 % 60
|
|
124
|
+
|
|
125
|
+
result = ""
|
|
126
|
+
if days > 0:
|
|
127
|
+
result += f"{days} д. "
|
|
128
|
+
if hours > 0:
|
|
129
|
+
result += f"{hours} ч. "
|
|
130
|
+
if minutes > 0:
|
|
131
|
+
result += f"{minutes:02d} мин. "
|
|
132
|
+
result += f"{seconds:02d} сек."
|
|
133
|
+
result = result.strip()
|
|
134
|
+
|
|
135
|
+
log.debug("Converted duration: [%s] into readable str: [%s].", duration_seconds, result)
|
|
136
|
+
|
|
137
|
+
return result
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@lru_cache(maxsize=LRU_CACHE_SIZE)
|
|
141
|
+
def human_readable_duration_secondsc(duration_seconds):
|
|
142
|
+
"""CACHED. Cached version of the human_readable_duration_seconds() method."""
|
|
143
|
+
|
|
144
|
+
return human_readable_duration_seconds(duration_seconds)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
if __name__ == "__main__":
|
|
148
|
+
print(MSG_MODULE_ISNT_RUNNABLE)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Structures module.
|
|
5
|
+
|
|
6
|
+
Created: Dmitrii Gusev, 21.05.2026
|
|
7
|
+
Modified: Dmitrii Gusev, 24.05.2026
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from collections import defaultdict
|
|
11
|
+
|
|
12
|
+
from pyutilities.utils.string_utils import is_empty
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _defaultdict_factory(key: str):
|
|
16
|
+
"""Return different default types for the defaultdict based on the key prefix.
|
|
17
|
+
This function is used a s a default factory for the class KeyAwareDefaultDict - see below.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
if isinstance(key, str) and not is_empty(key):
|
|
21
|
+
|
|
22
|
+
if key.startswith("count_"): # int type
|
|
23
|
+
return 0
|
|
24
|
+
|
|
25
|
+
if key.startswith("str_"): # string type
|
|
26
|
+
return ""
|
|
27
|
+
|
|
28
|
+
if key.startswith("items_"): # list type
|
|
29
|
+
return []
|
|
30
|
+
|
|
31
|
+
if key.startswith("set_"): # set type
|
|
32
|
+
return set()
|
|
33
|
+
|
|
34
|
+
if key.startswith("dict_"): # dictionary type
|
|
35
|
+
return {}
|
|
36
|
+
|
|
37
|
+
# unknown type - fallback for unknown keys
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class KeyAwareDefaultDict(defaultdict): # type: ignore[type-arg]
|
|
42
|
+
"""Extension of the default dictionary in python - 'key aware default dictionary', implementing
|
|
43
|
+
different types of the dictionary values, depending on the dictionary keys prefixes.
|
|
44
|
+
Prefixes are:
|
|
45
|
+
- count_* - int type
|
|
46
|
+
- str_* - str type
|
|
47
|
+
- items_* - list type
|
|
48
|
+
- set_* - set type
|
|
49
|
+
- dict_* - dict type
|
|
50
|
+
Usage example:
|
|
51
|
+
dynamic_dict = KeyAwareDefaultDict() # option I - default factory (see above)
|
|
52
|
+
dynamic_dict = KeyAwareDefaultDict(default_factory) # option II - use your custom factory function
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, default_factory=_defaultdict_factory):
|
|
56
|
+
super().__init__(default_factory)
|
|
57
|
+
|
|
58
|
+
def __missing__(self, key):
|
|
59
|
+
# call the factory with a key and save the result
|
|
60
|
+
result = self.default_factory(key) # type: ignore[call-arg, misc]
|
|
61
|
+
self[key] = result
|
|
62
|
+
return result
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# Python Utilities Library
|
|
2
|
-
|
|
3
|
-
Version 2.4.2, 2018 - 2026, Dmitrii Gusev
|
|
4
|
-
*Last update: 15.05.2026*
|
|
5
|
-
|
|
6
|
-
## Project Description
|
|
7
|
-
|
|
8
|
-
Useful utilities functions for various needs for the python 3.10+. Containing 'general purpose' functions.
|
|
9
|
-
|
|
10
|
-
## Versions history
|
|
11
|
-
|
|
12
|
-
### 2.4.0/2.4.1/2.4.2
|
|
13
|
-
|
|
14
|
-
- many refactorings and minor code improvements
|
|
15
|
-
- overall tests coverage now > 50%, working on improvements :)
|
|
16
|
-
- added new date/time function, several decorators
|
|
17
|
-
- added several useful string functions
|
|
18
|
-
- added LoggingManager component for loguru simple configuration
|
|
19
|
-
- v.2.4.1/v.2.4.2 - minor docs fixes
|
|
20
|
-
|
|
21
|
-
### 2.3.0
|
|
22
|
-
|
|
23
|
-
Intermediate version with improvements/refactorings.
|
|
24
|
-
|
|
25
|
-
### 2.2.0
|
|
26
|
-
|
|
27
|
-
Added several new functions - see sources.
|
|
28
|
-
|
|
29
|
-
### 2.1.2
|
|
30
|
-
|
|
31
|
-
Major release with complete set of useful 'general purpose' functions. Documentation 'is coming'...
|
|
32
|
-
|
|
33
|
-
**Warning! Versions 2.1.0, 2.1.1 are intended only for the python version = 3.10 and can be installed only for it!**
|
|
34
|
-
|
|
35
|
-
### Versions before 2.x.x
|
|
36
|
-
|
|
37
|
-
**It is strongly recommended: don't use versions prior to the 2.x.x!**
|
|
38
|
-
|
|
39
|
-
Main properties of the previous library versions:
|
|
40
|
-
|
|
41
|
-
- set of the 'minor' and 'experimental' releases
|
|
42
|
-
- various set of functions without consistency
|
|
43
|
-
- many 'experimental' functions without proper testing
|
|
44
|
-
- a lot of unnecessary code
|
|
45
|
-
- experiments with building/dependencies management tools - no tool, pipenv poetry
|
|
46
|
-
- unstable list of dependencies with obsolete versions
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Useful date/time utilities and functions.
|
|
5
|
-
|
|
6
|
-
Created: Dmitrii Gusev, 22.03.2026
|
|
7
|
-
Modified: Dmitrii Gusev, 10.05.2026
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from datetime import datetime, timedelta, timezone
|
|
11
|
-
|
|
12
|
-
import pendulum
|
|
13
|
-
from pendulum import Date
|
|
14
|
-
|
|
15
|
-
from pyutilities.defaults import MSG_MODULE_ISNT_RUNNABLE
|
|
16
|
-
|
|
17
|
-
MSK_TIMEZONE: timezone = timezone(timedelta(hours=3), name="Moscow Timezone (Russia)")
|
|
18
|
-
MSK_TIMEZONE_NAME: str = "Europe/Moscow"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def get_timestamp(
|
|
22
|
-
current_timezone: timezone = MSK_TIMEZONE,
|
|
23
|
-
days: float = 0,
|
|
24
|
-
hours: float = 0,
|
|
25
|
-
minutes: float = 0,
|
|
26
|
-
seconds: float = 0,
|
|
27
|
-
) -> datetime:
|
|
28
|
-
"""Return timestamp: now (in the default timezone) +/- the specified time delta in hours / minutes /
|
|
29
|
-
seconds. Default timezone can be changed by the function argument."""
|
|
30
|
-
|
|
31
|
-
return datetime.now(current_timezone) + timedelta(
|
|
32
|
-
days=days, hours=hours, minutes=minutes, seconds=seconds
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def get_dates_range_before_date(date: datetime) -> tuple[int, int]:
|
|
37
|
-
"""Generates two dates range - date_from/date_to for the time period 'before today' - from the 1st day
|
|
38
|
-
of the current month till the today - 1 day (current month). In case today is 1st day - range for the
|
|
39
|
-
whole previous month, if today is 01.01.XXXX - range for 01.12.XXXX-1 - 31.12.XXXX-1.
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
# - local variables
|
|
43
|
-
local_today: Date = Date(date.year, date.month, date.day)
|
|
44
|
-
date_from: Date
|
|
45
|
-
date_to: Date
|
|
46
|
-
|
|
47
|
-
# - processing and calculating dates
|
|
48
|
-
if local_today.day == 1: # today - 1st day of month, we need report for the previous month
|
|
49
|
-
|
|
50
|
-
if local_today.month == 1: # we are at 01.01.XXXX - we need report for Dec.XXXX - 1
|
|
51
|
-
|
|
52
|
-
date_from = pendulum.date(local_today.year - 1, 12, 1) # from: 01 Dec Year-1
|
|
53
|
-
date_to = pendulum.date(local_today.year - 1, 12, 31) # to: 31 Dec Year-1
|
|
54
|
-
|
|
55
|
-
else: # we are at 01.XX.XXXX - we need report for previous month
|
|
56
|
-
|
|
57
|
-
# from: 01 Month-1 Year
|
|
58
|
-
date_from = pendulum.date(local_today.year, local_today.month - 1, 1)
|
|
59
|
-
# to: Last Day Month-1 Year
|
|
60
|
-
date_to = pendulum.date(
|
|
61
|
-
local_today.year, local_today.month - 1, local_today.subtract(months=1).days_in_month
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
else: # today isn't the 1st, we need report from 1st till yesterday
|
|
65
|
-
|
|
66
|
-
date_from = pendulum.date(local_today.year, local_today.month, 1) # from: 01 Month Year
|
|
67
|
-
date_to = pendulum.date(local_today.year, local_today.month, date.day - 1) # to: Day-1 Month Year
|
|
68
|
-
|
|
69
|
-
# - generate from/to timestamps
|
|
70
|
-
tstamp_from = pendulum.datetime(date_from.year, date_from.month, date_from.day)
|
|
71
|
-
tstamp_to = pendulum.datetime(date_to.year, date_to.month, date_to.day)
|
|
72
|
-
|
|
73
|
-
# - return the tuple of values
|
|
74
|
-
return (tstamp_from.int_timestamp, tstamp_to.int_timestamp)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if __name__ == "__main__":
|
|
78
|
-
print(MSG_MODULE_ISNT_RUNNABLE)
|
|
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
|