python-backpack 1.1.4__tar.gz → 2.0.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.
- {python_backpack-1.1.4 → python_backpack-2.0.0}/PKG-INFO +5 -5
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/cache.py +14 -11
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/json_user_settings.py +7 -4
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/strings.py +32 -17
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/test_utils.py +1 -1
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/version.py +4 -3
- {python_backpack-1.1.4 → python_backpack-2.0.0}/pyproject.toml +7 -8
- {python_backpack-1.1.4 → python_backpack-2.0.0}/LICENSE +0 -0
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/__init__.py +0 -0
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/custom_errors.py +0 -0
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/file_utils.py +0 -0
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/folder_utils.py +0 -0
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/json_metadata.py +0 -0
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/json_utils.py +0 -0
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/logger.py +0 -0
- {python_backpack-1.1.4 → python_backpack-2.0.0}/backpack/patterns.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: python-backpack
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: A collection of personal scripts for json, File/Folder Operations, String Validation, Custom Errors, Cache and stuff.
|
|
5
|
+
License-File: LICENSE
|
|
5
6
|
Author: Maximiliano Rocamora
|
|
6
|
-
Requires-Python: >=3.
|
|
7
|
+
Requires-Python: >=3.11,<4.0
|
|
7
8
|
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
10
9
|
Classifier: Programming Language :: Python :: 3.11
|
|
11
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
@@ -5,13 +5,16 @@
|
|
|
5
5
|
# ----------------------------------------------------------------------------------------
|
|
6
6
|
from datetime import datetime, timedelta, timezone
|
|
7
7
|
from functools import lru_cache, wraps
|
|
8
|
+
from typing import Any, Callable, TypeVar, cast
|
|
8
9
|
|
|
9
10
|
from backpack.logger import get_logger
|
|
10
11
|
|
|
11
12
|
log = get_logger('Python Backpack - Cache')
|
|
12
13
|
|
|
14
|
+
F = TypeVar('F', bound=Callable[..., Any])
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
|
|
17
|
+
def timed_lru_cache(seconds: int, maxsize: int = 128) -> Callable[[F], F]:
|
|
15
18
|
"""Lru_cache with expiration time.
|
|
16
19
|
|
|
17
20
|
Args:
|
|
@@ -36,10 +39,10 @@ def timed_lru_cache(seconds: int, maxsize: int = 128):
|
|
|
36
39
|
|
|
37
40
|
"""
|
|
38
41
|
|
|
39
|
-
def wrapper_cache(func):
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
def wrapper_cache(func: F) -> F:
|
|
43
|
+
cached_func = cast(Any, lru_cache(maxsize=maxsize)(func))
|
|
44
|
+
cached_func.lifetime = timedelta(seconds=seconds)
|
|
45
|
+
cached_func.expiration = datetime.now(timezone.utc) + cached_func.lifetime
|
|
43
46
|
|
|
44
47
|
@wraps(func)
|
|
45
48
|
def wrapped_func(*args, force_clear: bool = False, show_log: bool = False, **kwargs):
|
|
@@ -54,15 +57,15 @@ def timed_lru_cache(seconds: int, maxsize: int = 128):
|
|
|
54
57
|
function result
|
|
55
58
|
"""
|
|
56
59
|
|
|
57
|
-
if force_clear or datetime.now(timezone.utc) >=
|
|
60
|
+
if force_clear or datetime.now(timezone.utc) >= cached_func.expiration:
|
|
58
61
|
if show_log:
|
|
59
|
-
log.debug(f'Cache cleared for {
|
|
62
|
+
log.debug(f'Cache cleared for {cached_func.__name__}')
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
cached_func.cache_clear()
|
|
65
|
+
cached_func.expiration = datetime.now(timezone.utc) + cached_func.lifetime
|
|
63
66
|
|
|
64
|
-
return
|
|
67
|
+
return cached_func(*args, **kwargs)
|
|
65
68
|
|
|
66
|
-
return wrapped_func
|
|
69
|
+
return cast(F, wrapped_func)
|
|
67
70
|
|
|
68
71
|
return wrapper_cache
|
|
@@ -9,6 +9,7 @@ us.save(someDict)
|
|
|
9
9
|
data = us.load()
|
|
10
10
|
|
|
11
11
|
"""
|
|
12
|
+
|
|
12
13
|
# ----------------------------------------------------------------------------------------
|
|
13
14
|
import os
|
|
14
15
|
|
|
@@ -59,14 +60,16 @@ class JsonUserSettings:
|
|
|
59
60
|
|
|
60
61
|
return True
|
|
61
62
|
|
|
62
|
-
def save_settings(self, data=
|
|
63
|
+
def save_settings(self, data: dict | None = None) -> bool | None:
|
|
63
64
|
"""Saves a dictionary into a json file (os user path).
|
|
64
65
|
|
|
65
66
|
Args:
|
|
66
|
-
data (dictionary)
|
|
67
|
+
data (dictionary): info dictionary to save, if not provided,
|
|
67
68
|
saves instead local self.user_data property
|
|
69
|
+
Returns:
|
|
70
|
+
bool | None: True if file was saved, False if error, None if no data to save.
|
|
68
71
|
"""
|
|
69
|
-
if
|
|
72
|
+
if data is None:
|
|
70
73
|
data = self.user_data
|
|
71
74
|
|
|
72
75
|
r = json_save(data, self.filepath)
|
|
@@ -74,7 +77,7 @@ class JsonUserSettings:
|
|
|
74
77
|
log.info('json settings file saved! [%s]', self.filepath)
|
|
75
78
|
return r
|
|
76
79
|
|
|
77
|
-
def load_settings(self) -> dict:
|
|
80
|
+
def load_settings(self) -> dict | bool:
|
|
78
81
|
"""Load json file from path and returns its contents."""
|
|
79
82
|
try:
|
|
80
83
|
return json_load(self.filepath)
|
|
@@ -8,8 +8,11 @@ import contextlib
|
|
|
8
8
|
import re
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def
|
|
12
|
-
input_string: str,
|
|
11
|
+
def normalize_input_string(
|
|
12
|
+
input_string: str,
|
|
13
|
+
under_spaces: bool = True,
|
|
14
|
+
under_hyphen: bool = True,
|
|
15
|
+
replacer: str = '_',
|
|
13
16
|
) -> str:
|
|
14
17
|
"""Reformat the user input string.
|
|
15
18
|
|
|
@@ -20,6 +23,7 @@ def reformat_input_string(
|
|
|
20
23
|
input_string (str): input string to reformat
|
|
21
24
|
under_spaces (bool, optional): replaces spaces. Defaults to True.
|
|
22
25
|
under_hyphen (bool, optional): replaces hyphens. Defaults to True.
|
|
26
|
+
replacer (str, optional): char to replace spaces and hyphens. Defaults to '_'.
|
|
23
27
|
|
|
24
28
|
Returns:
|
|
25
29
|
str: reformatted string
|
|
@@ -30,13 +34,13 @@ def reformat_input_string(
|
|
|
30
34
|
regex = re.sub('[^A-Za-z0-9 _-]+', '', input_string)
|
|
31
35
|
|
|
32
36
|
for char in regex:
|
|
33
|
-
# replacing " " for
|
|
37
|
+
# replacing " " for replacer
|
|
34
38
|
if under_spaces and char == ' ':
|
|
35
|
-
regex = regex.replace(' ',
|
|
39
|
+
regex = regex.replace(' ', replacer)
|
|
36
40
|
|
|
37
|
-
# replacing "-" for
|
|
41
|
+
# replacing "-" for replacer
|
|
38
42
|
if under_hyphen and char == '-':
|
|
39
|
-
regex = regex.replace('-',
|
|
43
|
+
regex = regex.replace('-', replacer)
|
|
40
44
|
|
|
41
45
|
return regex
|
|
42
46
|
|
|
@@ -85,6 +89,7 @@ def camelcase_to_snakecase(input_string: str) -> str:
|
|
|
85
89
|
Examples:
|
|
86
90
|
OneDayCaseChar > one_day_case_char
|
|
87
91
|
oneCamelCaseChar > one_camel_case_char
|
|
92
|
+
HTTPServer > http_server
|
|
88
93
|
_TwoCamel_CaseChar > _two_camel_case_char
|
|
89
94
|
_LeadingUnderscore_case_ > _leading_underscore_case_
|
|
90
95
|
"""
|
|
@@ -97,18 +102,28 @@ def camelcase_to_snakecase(input_string: str) -> str:
|
|
|
97
102
|
snake_str += char
|
|
98
103
|
continue
|
|
99
104
|
|
|
100
|
-
if char.isupper()
|
|
101
|
-
snake_str += char
|
|
102
|
-
continue
|
|
103
|
-
|
|
104
|
-
if char.isupper():
|
|
105
|
-
if input_string[index - 1] != '_':
|
|
106
|
-
snake_str += '_' + char.lower()
|
|
107
|
-
else:
|
|
108
|
-
snake_str += char.lower()
|
|
109
|
-
|
|
105
|
+
if not char.isupper():
|
|
106
|
+
snake_str += char
|
|
110
107
|
continue
|
|
111
108
|
|
|
112
|
-
|
|
109
|
+
prev_char = input_string[index - 1] if index > 0 else ''
|
|
110
|
+
next_char = input_string[index + 1] if index + 1 < len(input_string) else ''
|
|
111
|
+
|
|
112
|
+
# Add underscore only at real word boundaries.
|
|
113
|
+
# This keeps acronyms together: HTTPServer -> http_server.
|
|
114
|
+
should_add_underscore = (
|
|
115
|
+
index > 0
|
|
116
|
+
and prev_char != '_'
|
|
117
|
+
and (
|
|
118
|
+
prev_char.islower()
|
|
119
|
+
or prev_char.isdigit()
|
|
120
|
+
or (prev_char.isupper() and next_char.islower())
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if should_add_underscore:
|
|
125
|
+
snake_str += '_'
|
|
126
|
+
|
|
127
|
+
snake_str += char.lower()
|
|
113
128
|
|
|
114
129
|
return snake_str
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
# 1.1.2 07/2025 - Update actions versions, remove unused badge from README
|
|
10
10
|
# 1.1.3 07/2025 - Improve test class names and docstrings for clarity, ruff formatting
|
|
11
11
|
# 1.1.4 07/2025 - Moved from pipenv to poetry for dependency management.toml
|
|
12
|
+
# 2.0.0 03/2026 - Remove tox workflow and setup.py, standardize Poetry + coverage tooling
|
|
12
13
|
# ----------------------------------------------------------------------------------------
|
|
13
14
|
|
|
14
|
-
VERSION_MAJOR =
|
|
15
|
-
VERSION_MINOR =
|
|
16
|
-
VERSION_PATCH =
|
|
15
|
+
VERSION_MAJOR = 2
|
|
16
|
+
VERSION_MINOR = 0
|
|
17
|
+
VERSION_PATCH = 0
|
|
17
18
|
|
|
18
19
|
version = f'{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_PATCH}'
|
|
19
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-backpack"
|
|
3
|
-
version = "
|
|
3
|
+
version = "2.0.0"
|
|
4
4
|
description = "A collection of personal scripts for json, File/Folder Operations, String Validation, Custom Errors, Cache and stuff."
|
|
5
5
|
authors = ["Maximiliano Rocamora"]
|
|
6
6
|
packages = [
|
|
@@ -8,16 +8,15 @@ packages = [
|
|
|
8
8
|
]
|
|
9
9
|
|
|
10
10
|
[tool.poetry.dependencies]
|
|
11
|
-
python = "^3.
|
|
11
|
+
python = "^3.11"
|
|
12
12
|
|
|
13
13
|
[tool.poetry.group.dev.dependencies]
|
|
14
|
-
|
|
15
|
-
ruff = "^0.0.289"
|
|
14
|
+
ruff = "^0.15.8"
|
|
16
15
|
mock = "^5.2.0"
|
|
17
|
-
coverage = "^7.
|
|
18
|
-
pytest
|
|
19
|
-
|
|
16
|
+
coverage = "^7.13.5"
|
|
17
|
+
pytest = "^8.4.2"
|
|
18
|
+
pytest-cov = "^7.1.0"
|
|
20
19
|
|
|
21
20
|
[build-system]
|
|
22
|
-
requires = ["poetry-core>=
|
|
21
|
+
requires = ["poetry-core>=2.3.2"]
|
|
23
22
|
build-backend = "poetry.core.masonry.api"
|
|
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
|