python-backpack 1.0.5__py3-none-any.whl → 2.0.0__py3-none-any.whl
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.
- backpack/cache.py +23 -19
- backpack/custom_errors.py +8 -7
- backpack/file_utils.py +27 -19
- backpack/folder_utils.py +14 -13
- backpack/json_metadata.py +32 -35
- backpack/json_user_settings.py +24 -18
- backpack/json_utils.py +14 -10
- backpack/logger.py +2 -2
- backpack/patterns.py +5 -3
- backpack/strings.py +45 -31
- backpack/test_utils.py +5 -5
- backpack/version.py +8 -2
- python_backpack-2.0.0.dist-info/METADATA +12 -0
- python_backpack-2.0.0.dist-info/RECORD +17 -0
- {python_backpack-1.0.5.dist-info → python_backpack-2.0.0.dist-info}/WHEEL +1 -2
- python_backpack-1.0.5.dist-info/METADATA +0 -74
- python_backpack-1.0.5.dist-info/RECORD +0 -29
- python_backpack-1.0.5.dist-info/top_level.txt +0 -2
- tests/__init__.py +0 -0
- tests/test_cache.py +0 -27
- tests/test_errors.py +0 -50
- tests/test_file_utils.py +0 -49
- tests/test_folder_utils.py +0 -96
- tests/test_json_user_settings.py +0 -76
- tests/test_json_utils.py +0 -46
- tests/test_jsonmd.py +0 -90
- tests/test_misc.py +0 -54
- tests/test_strings.py +0 -94
- tests/test_test_utils.py +0 -45
- {python_backpack-1.0.5.dist-info → python_backpack-2.0.0.dist-info/licenses}/LICENSE +0 -0
backpack/strings.py
CHANGED
|
@@ -8,63 +8,67 @@ import contextlib
|
|
|
8
8
|
import re
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
def normalize_input_string(
|
|
12
|
+
input_string: str,
|
|
13
|
+
under_spaces: bool = True,
|
|
14
|
+
under_hyphen: bool = True,
|
|
15
|
+
replacer: str = '_',
|
|
16
|
+
) -> str:
|
|
17
|
+
"""Reformat the user input string.
|
|
18
|
+
|
|
19
|
+
leaves only alphanumeric chars
|
|
20
|
+
replaces spaces and hyphens for underscores.
|
|
17
21
|
|
|
18
22
|
Args:
|
|
19
23
|
input_string (str): input string to reformat
|
|
20
24
|
under_spaces (bool, optional): replaces spaces. Defaults to True.
|
|
21
25
|
under_hyphen (bool, optional): replaces hyphens. Defaults to True.
|
|
26
|
+
replacer (str, optional): char to replace spaces and hyphens. Defaults to '_'.
|
|
22
27
|
|
|
23
28
|
Returns:
|
|
24
29
|
str: reformatted string
|
|
25
|
-
|
|
30
|
+
"""
|
|
26
31
|
|
|
27
32
|
# re-encode string to valid chars
|
|
28
33
|
with contextlib.suppress(UnicodeDecodeError):
|
|
29
34
|
regex = re.sub('[^A-Za-z0-9 _-]+', '', input_string)
|
|
30
35
|
|
|
31
36
|
for char in regex:
|
|
32
|
-
|
|
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
|
|
|
43
47
|
|
|
44
48
|
def begin_or_end_with_numbers(input_string: str) -> bool:
|
|
45
|
-
|
|
49
|
+
"""Returns true if the input string begins or ends with number."""
|
|
46
50
|
return _char_is_number(input_string[0]) or _char_is_number(input_string[-1])
|
|
47
51
|
|
|
48
52
|
|
|
49
53
|
def begin_with_number(input_string: str) -> bool:
|
|
50
|
-
|
|
54
|
+
"""Returns true if the input string begins with numbers."""
|
|
51
55
|
return _char_is_number(input_string[0])
|
|
52
56
|
|
|
53
57
|
|
|
54
58
|
def has_numbers(input_string: str) -> bool:
|
|
55
|
-
|
|
59
|
+
"""Returns true if the input string has numbers."""
|
|
56
60
|
return any(_char_is_number(char) for char in input_string)
|
|
57
61
|
|
|
58
62
|
|
|
59
63
|
def _char_is_number(char: str) -> bool:
|
|
60
|
-
|
|
64
|
+
"""Check if a string is a number.
|
|
61
65
|
|
|
62
66
|
Args:
|
|
63
67
|
char (str): character to evaluate
|
|
64
68
|
|
|
65
69
|
Returns:
|
|
66
70
|
bool: True if is a int
|
|
67
|
-
|
|
71
|
+
"""
|
|
68
72
|
|
|
69
73
|
try:
|
|
70
74
|
int(char)
|
|
@@ -74,7 +78,7 @@ def _char_is_number(char: str) -> bool:
|
|
|
74
78
|
|
|
75
79
|
|
|
76
80
|
def camelcase_to_snakecase(input_string: str) -> str:
|
|
77
|
-
|
|
81
|
+
"""Convert a CamelCase string to snake_case string.
|
|
78
82
|
|
|
79
83
|
Args:
|
|
80
84
|
input_string (str): The CamelCase string to be converted.
|
|
@@ -85,31 +89,41 @@ 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
|
+
"""
|
|
91
96
|
|
|
92
97
|
snake_str = ''
|
|
93
98
|
|
|
94
99
|
# iterate over the string
|
|
95
100
|
for index, char in enumerate(input_string):
|
|
96
|
-
|
|
97
101
|
if not char.isalnum():
|
|
98
102
|
snake_str += char
|
|
99
103
|
continue
|
|
100
104
|
|
|
101
|
-
if char.isupper()
|
|
102
|
-
snake_str += char
|
|
103
|
-
continue
|
|
104
|
-
|
|
105
|
-
if char.isupper():
|
|
106
|
-
if input_string[index - 1] != '_':
|
|
107
|
-
snake_str += '_' + char.lower()
|
|
108
|
-
else:
|
|
109
|
-
snake_str += char.lower()
|
|
110
|
-
|
|
105
|
+
if not char.isupper():
|
|
106
|
+
snake_str += char
|
|
111
107
|
continue
|
|
112
108
|
|
|
113
|
-
|
|
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()
|
|
114
128
|
|
|
115
129
|
return snake_str
|
backpack/test_utils.py
CHANGED
|
@@ -3,31 +3,31 @@
|
|
|
3
3
|
# Maximiliano Rocamora / maxirocamora@gmail.com
|
|
4
4
|
# https://github.com/MaxRocamora/python-backpack
|
|
5
5
|
# ----------------------------------------------------------------------------------------
|
|
6
|
-
import time
|
|
7
6
|
import random
|
|
8
7
|
import string
|
|
8
|
+
import time
|
|
9
9
|
|
|
10
10
|
from backpack.logger import get_logger
|
|
11
11
|
|
|
12
12
|
log = get_logger('Python Backpack - TestUtils')
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
def random_string(length:
|
|
16
|
-
|
|
15
|
+
def random_string(length: int = 10) -> str:
|
|
16
|
+
"""Generates a random string of fixed length.
|
|
17
17
|
|
|
18
18
|
Args:
|
|
19
19
|
length (int, optional): max string length. Defaults to 10.
|
|
20
20
|
|
|
21
21
|
Returns:
|
|
22
22
|
str: random string
|
|
23
|
-
|
|
23
|
+
"""
|
|
24
24
|
|
|
25
25
|
letters = string.ascii_lowercase
|
|
26
26
|
return ''.join(random.choice(letters) for _ in range(length))
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def time_function_decorator(method: type):
|
|
30
|
-
|
|
30
|
+
"""Decorator to measure methods execution time."""
|
|
31
31
|
|
|
32
32
|
def timed(*args, **kw):
|
|
33
33
|
ts = time.time()
|
backpack/version.py
CHANGED
|
@@ -4,11 +4,17 @@
|
|
|
4
4
|
# 1.0.3 07/2022 - JsonMetaFile, JsonUserSettings
|
|
5
5
|
# 1.0.4 04/2023 - Added camelcase_to_snakecase function
|
|
6
6
|
# 1.0.5 05/2023 - Refactor JsonMetaFile, Added Cache, Some type hints / docstrings
|
|
7
|
+
# 1.1.0 01/2024 - Ruff Formatting
|
|
8
|
+
# 1.1.1 07/2025 - Update Python version matrix to include 3.10 and 3.11, update actions versions
|
|
9
|
+
# 1.1.2 07/2025 - Update actions versions, remove unused badge from README
|
|
10
|
+
# 1.1.3 07/2025 - Improve test class names and docstrings for clarity, ruff formatting
|
|
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
|
|
7
13
|
# ----------------------------------------------------------------------------------------
|
|
8
14
|
|
|
9
|
-
VERSION_MAJOR =
|
|
15
|
+
VERSION_MAJOR = 2
|
|
10
16
|
VERSION_MINOR = 0
|
|
11
|
-
VERSION_PATCH =
|
|
17
|
+
VERSION_PATCH = 0
|
|
12
18
|
|
|
13
19
|
version = f'{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_PATCH}'
|
|
14
20
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-backpack
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: A collection of personal scripts for json, File/Folder Operations, String Validation, Custom Errors, Cache and stuff.
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Author: Maximiliano Rocamora
|
|
7
|
+
Requires-Python: >=3.11,<4.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
backpack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
backpack/cache.py,sha256=NlKyeGSXHaA9-RFLSN9Dblt0s7kL9fKzqQhGPHpgGbM,2508
|
|
3
|
+
backpack/custom_errors.py,sha256=tkn0AnV-Ihnge9X197nPeRpCFD6Feu9lLntejNTNpik,1358
|
|
4
|
+
backpack/file_utils.py,sha256=neJN9PL866H8gNFJMbWe06PqENY9UKO61YQa39ujjgY,2743
|
|
5
|
+
backpack/folder_utils.py,sha256=RxfVHBLDTL2EdU2w_EMOWsdtCQh-f5BHMzGIRo3UEI8,2983
|
|
6
|
+
backpack/json_metadata.py,sha256=KHsXTCDcrKa68p_HgtQfy_AjXmDCxiA99NIuZfKn2I8,4561
|
|
7
|
+
backpack/json_user_settings.py,sha256=RwdxIZYD4jkcIrWxMn7ZrlKejaGIYOt2TXTGob7nCUg,2676
|
|
8
|
+
backpack/json_utils.py,sha256=ZMl_aGb6oU9sQByOqT5OFTdgAKL2iB-DxsVkVuSCOjA,1324
|
|
9
|
+
backpack/logger.py,sha256=yoo4_4Ok9MAdd3GSTeeSGaIKJ4c-KwdhI6q7lg_39oo,518
|
|
10
|
+
backpack/patterns.py,sha256=qBwgbpfzMrap4KHtLLsg1CJmsmstGGXfzYLpkuUdbMI,889
|
|
11
|
+
backpack/strings.py,sha256=boYfBi1wPtfkngpb2uIAxiJC2yo32EaL5wUD_3JjWGo,3811
|
|
12
|
+
backpack/test_utils.py,sha256=0VqVZB6snc_XM6MsmIanlFGWo5T2zswFq9Cn-HpZntE,1165
|
|
13
|
+
backpack/version.py,sha256=WBEIf90Avless1yHQdpQSg-8LGK2ekKoGI1aSbhFXvs,1073
|
|
14
|
+
python_backpack-2.0.0.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
|
15
|
+
python_backpack-2.0.0.dist-info/METADATA,sha256=Tx9wVjs9b5jS_296ngOXGCHkiRdGIxjgUNTGx4B2TbU,518
|
|
16
|
+
python_backpack-2.0.0.dist-info/WHEEL,sha256=Vz2fHgx6HFtSwhs8KvkHLqH5Ea4w1_rner5uNVGCeIE,88
|
|
17
|
+
python_backpack-2.0.0.dist-info/RECORD,,
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: python-backpack
|
|
3
|
-
Version: 1.0.5
|
|
4
|
-
Summary: Python Utilities
|
|
5
|
-
Home-page: https://github.com/MaxRocamora/python-backpack
|
|
6
|
-
Author: Maximiliano Rocamora
|
|
7
|
-
Author-email: maxirocamora@gmail.com
|
|
8
|
-
License: GNU GENERAL PUBLIC LICENSE
|
|
9
|
-
Project-URL: Source, https://github.com/MaxRocamora/python-backpack
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Classifier: License :: OSI Approved :: GNU General Public License (GPL)
|
|
15
|
-
Classifier: Operating System :: OS Independent
|
|
16
|
-
Classifier: Intended Audience :: Developers
|
|
17
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
-
Requires-Python: >=3.7
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
20
|
-
License-File: LICENSE
|
|
21
|
-
|
|
22
|
-
[](https://pypi.python.org/pypi/python-backpack/)
|
|
23
|
-
[](https://badge.fury.io/py/python-backpack)
|
|
24
|
-
[](https://badge.fury.io/gh/MaxRocamora%2Fpython-backpack)
|
|
25
|
-
[](https://codecov.io/gh/MaxRocamora/python-backpack)
|
|
26
|
-
[](https://github.com/MaxRocamora/python-backpack)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
# Python-Backpack
|
|
30
|
-
A collection of personal scripts for JSON, File/Folder Operations, String Validation, Custom Errors, Cache and stuff.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
## Json
|
|
34
|
-
+ json_load()
|
|
35
|
-
+ json_save()
|
|
36
|
-
+ jsonMetaFile()
|
|
37
|
-
+ jsonUserSettings()
|
|
38
|
-
|
|
39
|
-
## Files & Folders
|
|
40
|
-
+ browse_folder()
|
|
41
|
-
+ create_folders()
|
|
42
|
-
+ create_folder()
|
|
43
|
-
+ remove_files_in_dir()
|
|
44
|
-
+ recursive_dir_copy()
|
|
45
|
-
+ replace_strings_in_file()
|
|
46
|
-
+ remove_line_from_file()
|
|
47
|
-
+ file_is_writeable()
|
|
48
|
-
|
|
49
|
-
## String Validation
|
|
50
|
-
+ reformat_input_string()
|
|
51
|
-
+ begin_or_end_with_numbers()
|
|
52
|
-
+ begin_with_number()
|
|
53
|
-
+ has_numbers()
|
|
54
|
-
+ camelcase_to_snakecase()
|
|
55
|
-
|
|
56
|
-
## Custom Errors
|
|
57
|
-
+ EnvironmentVariableNotFound()
|
|
58
|
-
+ ApplicationNotFound()
|
|
59
|
-
|
|
60
|
-
## Cache
|
|
61
|
-
+ timed_lru_cache
|
|
62
|
-
|
|
63
|
-
## Test Utils
|
|
64
|
-
+ time_function_decorator()
|
|
65
|
-
+ random_string()
|
|
66
|
-
|
|
67
|
-
## Others / Patterns
|
|
68
|
-
+ Singleton()
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
### pip install
|
|
73
|
-
pip install python-backpack
|
|
74
|
-
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
backpack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
backpack/cache.py,sha256=2B3umkkhBfsn4dFpZ79o-uvsmefA8qcQgXGKRggP0Ms,2219
|
|
3
|
-
backpack/custom_errors.py,sha256=51Eq89WmOvCPyBO4mEBJKsgAEFKK3WTO7v83LJeGEkg,1268
|
|
4
|
-
backpack/file_utils.py,sha256=nz3SAGA4fH9xNwJvrpYhiSsXyyk-7JZopk_cMtgz4Ew,2519
|
|
5
|
-
backpack/folder_utils.py,sha256=6ccbMWE6ldHEMh1_EYWn_jkp5TMRksYB31yLyvGipUw,2975
|
|
6
|
-
backpack/json_metadata.py,sha256=5mi21S4ly15S_vDVe_aOGLMHHos-CI2x0CbGsnbULlI,4599
|
|
7
|
-
backpack/json_user_settings.py,sha256=9X-uhkVw12YeejRx0_43cRvcXTjJGByFWcfknXwKBsI,2539
|
|
8
|
-
backpack/json_utils.py,sha256=DL7guKwYnzJYwQFrBmS9GG1paG9sdOx9i89ev_P3UbA,1301
|
|
9
|
-
backpack/logger.py,sha256=Qln0FVcpBfotT2JBhSKOV58cQ4Hao4pcQijCpZ7F4V0,464
|
|
10
|
-
backpack/patterns.py,sha256=jYIjMVLqObq6XtXIcA9DV5im3rI7PSrtgrT3GpotZ1g,848
|
|
11
|
-
backpack/strings.py,sha256=JP9-2S3nZ5Jho3uYb8NeCPHV7J_nt8-7QvHt6Ws4LN8,3289
|
|
12
|
-
backpack/test_utils.py,sha256=5LStFAKbB5pnvghhcyiGX7yahKj0vBcJQ9_eqcguULo,1165
|
|
13
|
-
backpack/version.py,sha256=RzYPFfZCrgYlVntohAkBo_r2ki4pgAgdDqWMYZ3hEyo,607
|
|
14
|
-
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
tests/test_cache.py,sha256=BXRileSg4S2Im7TkdzcjswNEifvOo064eicYfwedHKQ,888
|
|
16
|
-
tests/test_errors.py,sha256=eoX7RBejDhMYDrCOBqs53_W0fQrv1JJp3R-9CcTjU1E,1580
|
|
17
|
-
tests/test_file_utils.py,sha256=El-YyQf-88MOjimCc9vhkYEca10qi9UioLNmDyFzWNc,1836
|
|
18
|
-
tests/test_folder_utils.py,sha256=M9z6GZ7XUbCWJaq9TShIEY0-owkrKUHi3lBUKdYX5BQ,3123
|
|
19
|
-
tests/test_json_user_settings.py,sha256=CDgJUOWliKTiBFct7moLf5nvkr274aBX0BJ0YIbfvv0,2224
|
|
20
|
-
tests/test_json_utils.py,sha256=HYexm7xGx3cff9pYJ7RgR2HwAj_m_-JyC1CZsr4R7o0,1616
|
|
21
|
-
tests/test_jsonmd.py,sha256=nlUvu34nQ3Wk7oLIQ9GxHxAeF-pSwxeEVYYMIbzKdv4,2551
|
|
22
|
-
tests/test_misc.py,sha256=McfYUEg1da4kAwKC0Jh1oGyyUXCj4RG0cR2fC5l7SqM,1675
|
|
23
|
-
tests/test_strings.py,sha256=69wWWF5Rn33Eg6osm6JxiFOk0t6x545bGPP6j8k-Ync,3704
|
|
24
|
-
tests/test_test_utils.py,sha256=upFG5qN-WVB7t6sHurTQLdyEvZ24TT_Rl4qugnKt-RQ,1191
|
|
25
|
-
python_backpack-1.0.5.dist-info/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
|
26
|
-
python_backpack-1.0.5.dist-info/METADATA,sha256=Nx-GbdFgI72qwLwdvFBKuyJqn_64DTyBOihKh1Pc_jk,2511
|
|
27
|
-
python_backpack-1.0.5.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
28
|
-
python_backpack-1.0.5.dist-info/top_level.txt,sha256=2w70HD8s6Z74zVMHouhcZ093sMqEMvQLvejexStCMLE,15
|
|
29
|
-
python_backpack-1.0.5.dist-info/RECORD,,
|
tests/__init__.py
DELETED
|
File without changes
|
tests/test_cache.py
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# ----------------------------------------------------------------------------------------
|
|
2
|
-
# Python-Backpack - Custom Exceptions UnitTest
|
|
3
|
-
# Maximiliano Rocamora / maxirocamora@gmail.com
|
|
4
|
-
# https://github.com/MaxRocamora/python-backpack
|
|
5
|
-
# ----------------------------------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
import unittest
|
|
8
|
-
|
|
9
|
-
from backpack.cache import timed_lru_cache
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class Test_Cache(unittest.TestCase):
|
|
13
|
-
|
|
14
|
-
@timed_lru_cache(seconds=1)
|
|
15
|
-
def test_function(self):
|
|
16
|
-
# some heavy process here to be cached
|
|
17
|
-
return True
|
|
18
|
-
|
|
19
|
-
def test_cache(self):
|
|
20
|
-
''' testing module '''
|
|
21
|
-
self.assertTrue(self.test_function())
|
|
22
|
-
self.assertEqual(True, self.test_function(force_clear=True))
|
|
23
|
-
self.assertEqual(True, self.test_function(force_clear=True, show_log=True))
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if __name__ == '__main__':
|
|
27
|
-
unittest.main()
|
tests/test_errors.py
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# ----------------------------------------------------------------------------------------
|
|
2
|
-
# Python-Backpack - Custom Exceptions UnitTest
|
|
3
|
-
# Maximiliano Rocamora / maxirocamora@gmail.com
|
|
4
|
-
# https://github.com/MaxRocamora/python-backpack
|
|
5
|
-
# ----------------------------------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
import sys
|
|
9
|
-
import unittest
|
|
10
|
-
|
|
11
|
-
from backpack.custom_errors import EnvironmentVariableNotFound
|
|
12
|
-
from backpack.custom_errors import ApplicationNotFound
|
|
13
|
-
|
|
14
|
-
mod_path = os.path.dirname(__file__)
|
|
15
|
-
if mod_path not in sys.path:
|
|
16
|
-
sys.path.append(mod_path)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def get_env_var(name: str):
|
|
20
|
-
''' call for an env var or raise EnvironmentVariableNotFound '''
|
|
21
|
-
try:
|
|
22
|
-
value = os.environ[name]
|
|
23
|
-
except KeyError as e:
|
|
24
|
-
raise EnvironmentVariableNotFound(name) from e
|
|
25
|
-
return value
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def get_app(name: str):
|
|
29
|
-
''' raisers error '''
|
|
30
|
-
raise ApplicationNotFound(f'Background executable not found {name}')
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class Test_Errors(unittest.TestCase):
|
|
34
|
-
|
|
35
|
-
def test_env_var_error(self):
|
|
36
|
-
''' testing module '''
|
|
37
|
-
self.assertRaises(EnvironmentVariableNotFound, get_env_var, 'my_env_var')
|
|
38
|
-
error = EnvironmentVariableNotFound('my_env_var')
|
|
39
|
-
self.assertEqual(str(error), error.message)
|
|
40
|
-
|
|
41
|
-
def test_env_app_error(self):
|
|
42
|
-
''' testing module '''
|
|
43
|
-
self.assertRaises(ApplicationNotFound, get_app, 'my_app.exe')
|
|
44
|
-
|
|
45
|
-
error = ApplicationNotFound('my_app.exe')
|
|
46
|
-
self.assertEqual(str(error), error.message)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if __name__ == '__main__':
|
|
50
|
-
unittest.main()
|
tests/test_file_utils.py
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# ----------------------------------------------------------------------------------------
|
|
2
|
-
# Python-Backpack - FolderUtils Tests
|
|
3
|
-
# Maximiliano Rocamora / maxirocamora@gmail.com
|
|
4
|
-
# https://github.com/MaxRocamora/python-backpack
|
|
5
|
-
# ----------------------------------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
import sys
|
|
9
|
-
import unittest
|
|
10
|
-
import shutil
|
|
11
|
-
|
|
12
|
-
from backpack.file_utils import replace_strings_in_file, remove_line_from_file
|
|
13
|
-
from backpack.file_utils import file_is_writeable
|
|
14
|
-
|
|
15
|
-
mod_path = os.path.dirname(__file__)
|
|
16
|
-
if mod_path not in sys.path:
|
|
17
|
-
sys.path.append(mod_path)
|
|
18
|
-
|
|
19
|
-
# test folders
|
|
20
|
-
BASE_FILE = os.path.join(mod_path, 'test_files', 'origin.txt')
|
|
21
|
-
EDITED_FILE = os.path.join(mod_path, 'test_files', 'edited.txt')
|
|
22
|
-
STRINGS = ['to be replaced!', 'also replaced']
|
|
23
|
-
NEW_STRING = 'REPLACED'
|
|
24
|
-
LOCKED_FILE = os.path.join(mod_path, 'test_files', 'locked_file.txt')
|
|
25
|
-
UNLOCKED_FILE = os.path.join(mod_path, 'test_files', 'unlocked_file.txt')
|
|
26
|
-
NO_FILE = os.path.join(mod_path, 'test_files', 'no_file.txt')
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class Test_Errors(unittest.TestCase):
|
|
30
|
-
|
|
31
|
-
def test_replace_strings_in_file(self):
|
|
32
|
-
''' testing module '''
|
|
33
|
-
shutil.copy(BASE_FILE, EDITED_FILE)
|
|
34
|
-
replace_strings_in_file(EDITED_FILE, STRINGS, NEW_STRING)
|
|
35
|
-
|
|
36
|
-
def test_remove_line_from_file(self):
|
|
37
|
-
''' testing module '''
|
|
38
|
-
source_file = os.path.join(mod_path, 'test_files', 'origin_remove.txt')
|
|
39
|
-
test_file = os.path.join(mod_path, 'test_files', 'edited_remove.txt')
|
|
40
|
-
shutil.copy(source_file, test_file)
|
|
41
|
-
remove_line_from_file(test_file, ['REMOVE_ME', 'to be replaced!'])
|
|
42
|
-
|
|
43
|
-
def test_locked_file(self):
|
|
44
|
-
self.assertTrue(file_is_writeable(UNLOCKED_FILE))
|
|
45
|
-
self.assertFalse(file_is_writeable(NO_FILE))
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if __name__ == '__main__':
|
|
49
|
-
unittest.main()
|
tests/test_folder_utils.py
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# ----------------------------------------------------------------------------------------
|
|
2
|
-
# Python-Backpack - FolderUtils Tests
|
|
3
|
-
# Maximiliano Rocamora / maxirocamora@gmail.com
|
|
4
|
-
# https://github.com/MaxRocamora/python-backpack
|
|
5
|
-
# ----------------------------------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
import sys
|
|
9
|
-
import unittest
|
|
10
|
-
import mock
|
|
11
|
-
|
|
12
|
-
from backpack.folder_utils import create_folders, browse_folder, create_folder
|
|
13
|
-
from backpack.folder_utils import remove_files_in_dir, recursive_dir_copy
|
|
14
|
-
|
|
15
|
-
mod_path = os.path.dirname(__file__)
|
|
16
|
-
if mod_path not in sys.path:
|
|
17
|
-
sys.path.append(mod_path)
|
|
18
|
-
|
|
19
|
-
# test folders
|
|
20
|
-
BASE_PATH = os.path.join(mod_path, 'test_folder')
|
|
21
|
-
FOLDERS = [os.path.join(BASE_PATH, 'ALPHA'),
|
|
22
|
-
os.path.join(BASE_PATH, 'BETA'),
|
|
23
|
-
]
|
|
24
|
-
FOLDER_FILES = os.path.join(BASE_PATH, 'files')
|
|
25
|
-
FILES = ['readme.txt']
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def create_file(path):
|
|
29
|
-
''' creates a temp txt file '''
|
|
30
|
-
with open(os.path.join(path, 'temp.txt'), 'w'):
|
|
31
|
-
pass
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class Test_Errors(unittest.TestCase):
|
|
35
|
-
|
|
36
|
-
def setUp(self):
|
|
37
|
-
pass
|
|
38
|
-
|
|
39
|
-
def test_create_folders(self):
|
|
40
|
-
''' testing module '''
|
|
41
|
-
create_folders(FOLDERS, verbose=True)
|
|
42
|
-
# check folders and files exists
|
|
43
|
-
for f in FOLDERS:
|
|
44
|
-
self.assertEqual(os.path.exists(f), True)
|
|
45
|
-
|
|
46
|
-
# delete folders
|
|
47
|
-
remove_files_in_dir(BASE_PATH)
|
|
48
|
-
|
|
49
|
-
create_folders(FOLDERS, verbose=True, force_empty=True)
|
|
50
|
-
# check folders and files exists
|
|
51
|
-
for f in FOLDERS:
|
|
52
|
-
self.assertEqual(os.path.exists(f), True)
|
|
53
|
-
|
|
54
|
-
# test osError
|
|
55
|
-
create_folder('X:/tests/force_oserror')
|
|
56
|
-
|
|
57
|
-
# test force_empty, calling twice to ensure folder existence
|
|
58
|
-
create_folders(FOLDERS, verbose=True, force_empty=False)
|
|
59
|
-
create_folders(FOLDERS, verbose=True, force_empty=True)
|
|
60
|
-
|
|
61
|
-
# delete folders
|
|
62
|
-
remove_files_in_dir(BASE_PATH)
|
|
63
|
-
|
|
64
|
-
@mock.patch('subprocess.Popen')
|
|
65
|
-
def test_browse(self, mock_browse):
|
|
66
|
-
# mocked Popen, create folder, browse, delete
|
|
67
|
-
create_folder(FOLDERS[0])
|
|
68
|
-
browse_folder(FOLDERS[0])
|
|
69
|
-
# force false
|
|
70
|
-
browse_folder(None)
|
|
71
|
-
|
|
72
|
-
def test_remove_dir(self):
|
|
73
|
-
''' creates a folder with files and remove it '''
|
|
74
|
-
test_dir = os.path.join(BASE_PATH, 'remove_dir')
|
|
75
|
-
create_folder(test_dir)
|
|
76
|
-
create_file(test_dir)
|
|
77
|
-
remove_files_in_dir(test_dir)
|
|
78
|
-
|
|
79
|
-
def test_recursive_dir(self):
|
|
80
|
-
''' creates a dir with sub dirs and files and copy them '''
|
|
81
|
-
test_dir = os.path.join(BASE_PATH, 'recursive_dir')
|
|
82
|
-
create_folder(test_dir)
|
|
83
|
-
create_file(test_dir)
|
|
84
|
-
sub_dir = os.path.join(test_dir, 'recursive_sub_dir')
|
|
85
|
-
create_folder(sub_dir)
|
|
86
|
-
create_file(sub_dir)
|
|
87
|
-
target_dir = os.path.join(BASE_PATH, 'recursive_target')
|
|
88
|
-
recursive_dir_copy(test_dir, target_dir)
|
|
89
|
-
# clear everything
|
|
90
|
-
remove_files_in_dir(test_dir)
|
|
91
|
-
remove_files_in_dir(sub_dir)
|
|
92
|
-
remove_files_in_dir(target_dir)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if __name__ == '__main__':
|
|
96
|
-
unittest.main()
|
tests/test_json_user_settings.py
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# ----------------------------------------------------------------------------------------
|
|
2
|
-
# Python-Backpack - json user settings Tests
|
|
3
|
-
# Maximiliano Rocamora / maxirocamora@gmail.com
|
|
4
|
-
# https://github.com/MaxRocamora/python-backpack
|
|
5
|
-
# ----------------------------------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
import contextlib
|
|
8
|
-
from backpack.json_user_settings import JsonUserSettings
|
|
9
|
-
|
|
10
|
-
import unittest
|
|
11
|
-
import os
|
|
12
|
-
import sys
|
|
13
|
-
|
|
14
|
-
mod_path = os.path.dirname(__file__)
|
|
15
|
-
if mod_path not in sys.path:
|
|
16
|
-
sys.path.append(mod_path)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# test path & name
|
|
20
|
-
FOLDER = 'tox_test_folder'
|
|
21
|
-
TEST_FOLDER = os.path.join(os.path.expanduser('~'), FOLDER)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class Test_windows(unittest.TestCase):
|
|
25
|
-
|
|
26
|
-
@classmethod
|
|
27
|
-
def setUp(cls):
|
|
28
|
-
# remove test files
|
|
29
|
-
with contextlib.suppress(OSError):
|
|
30
|
-
os.remove(TEST_FOLDER)
|
|
31
|
-
|
|
32
|
-
@classmethod
|
|
33
|
-
def tearDownClass(cls):
|
|
34
|
-
# remove test files
|
|
35
|
-
with contextlib.suppress(OSError):
|
|
36
|
-
os.remove(TEST_FOLDER)
|
|
37
|
-
|
|
38
|
-
def test_json_user_settings(self):
|
|
39
|
-
|
|
40
|
-
# make sure folder does not exist
|
|
41
|
-
with contextlib.suppress(PermissionError, OSError):
|
|
42
|
-
if os.path.exists(TEST_FOLDER):
|
|
43
|
-
os.removedirs(TEST_FOLDER)
|
|
44
|
-
|
|
45
|
-
# class and properties
|
|
46
|
-
js = JsonUserSettings(FOLDER, 'user')
|
|
47
|
-
assert (js.filepath)
|
|
48
|
-
assert (os.path.exists(js.os_user_folder))
|
|
49
|
-
assert (isinstance(js.user_data, dict))
|
|
50
|
-
|
|
51
|
-
# load from a missing file
|
|
52
|
-
js.filename = 'random_file'
|
|
53
|
-
self.assertFalse(js.load_settings())
|
|
54
|
-
|
|
55
|
-
def test_json_settings_save(self):
|
|
56
|
-
''' test json settings: save '''
|
|
57
|
-
|
|
58
|
-
# save a setting
|
|
59
|
-
js = JsonUserSettings(FOLDER, 'tox')
|
|
60
|
-
data = {'age': 99}
|
|
61
|
-
assert (js.save_settings(data))
|
|
62
|
-
|
|
63
|
-
# load it back
|
|
64
|
-
js = JsonUserSettings(FOLDER, 'tox')
|
|
65
|
-
data = js.load_settings()
|
|
66
|
-
assert (data['age'] == 99)
|
|
67
|
-
# save custom setting
|
|
68
|
-
js.user_data = {'custom': 'value'}
|
|
69
|
-
assert (js.save_settings())
|
|
70
|
-
# load it back
|
|
71
|
-
data = js.load_settings()
|
|
72
|
-
assert (data['custom'] == 'value')
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if __name__ == '__main__':
|
|
76
|
-
unittest.main()
|