ae-base 0.3.52__tar.gz → 0.3.54__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.
- {ae_base-0.3.52/ae_base.egg-info → ae_base-0.3.54}/PKG-INFO +5 -5
- {ae_base-0.3.52 → ae_base-0.3.54}/README.md +4 -4
- {ae_base-0.3.52 → ae_base-0.3.54}/ae/base.py +37 -11
- {ae_base-0.3.52 → ae_base-0.3.54/ae_base.egg-info}/PKG-INFO +5 -5
- {ae_base-0.3.52 → ae_base-0.3.54}/tests/test_base.py +43 -7
- {ae_base-0.3.52 → ae_base-0.3.54}/LICENSE.md +0 -0
- {ae_base-0.3.52 → ae_base-0.3.54}/ae_base.egg-info/SOURCES.txt +0 -0
- {ae_base-0.3.52 → ae_base-0.3.54}/ae_base.egg-info/dependency_links.txt +0 -0
- {ae_base-0.3.52 → ae_base-0.3.54}/ae_base.egg-info/requires.txt +0 -0
- {ae_base-0.3.52 → ae_base-0.3.54}/ae_base.egg-info/top_level.txt +0 -0
- {ae_base-0.3.52 → ae_base-0.3.54}/ae_base.egg-info/zip-safe +0 -0
- {ae_base-0.3.52 → ae_base-0.3.54}/setup.cfg +0 -0
- {ae_base-0.3.52 → ae_base-0.3.54}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ae_base
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.54
|
|
4
4
|
Summary: ae namespace module portion base: basic constants, helper functions and context manager
|
|
5
5
|
Home-page: https://gitlab.com/ae-group/ae_base
|
|
6
6
|
Author: AndiEcker
|
|
@@ -69,17 +69,17 @@ Dynamic: summary
|
|
|
69
69
|
|
|
70
70
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.95 -->
|
|
71
71
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->
|
|
72
|
-
# base 0.3.
|
|
72
|
+
# base 0.3.54
|
|
73
73
|
|
|
74
74
|
[](
|
|
75
75
|
https://gitlab.com/ae-group/ae_base)
|
|
76
76
|
[](
|
|
78
|
+
https://gitlab.com/ae-group/ae_base/-/tree/release0.3.53)
|
|
79
79
|
[](
|
|
80
80
|
https://pypi.org/project/ae-base/#history)
|
|
81
81
|
|
|
82
|
-
>ae_base module 0.3.
|
|
82
|
+
>ae_base module 0.3.54.
|
|
83
83
|
|
|
84
84
|
[](
|
|
85
85
|
https://ae-group.gitlab.io/ae_base/coverage/index.html)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.95 -->
|
|
2
2
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->
|
|
3
|
-
# base 0.3.
|
|
3
|
+
# base 0.3.54
|
|
4
4
|
|
|
5
5
|
[](
|
|
6
6
|
https://gitlab.com/ae-group/ae_base)
|
|
7
7
|
[](
|
|
9
|
+
https://gitlab.com/ae-group/ae_base/-/tree/release0.3.53)
|
|
10
10
|
[](
|
|
11
11
|
https://pypi.org/project/ae-base/#history)
|
|
12
12
|
|
|
13
|
-
>ae_base module 0.3.
|
|
13
|
+
>ae_base module 0.3.54.
|
|
14
14
|
|
|
15
15
|
[](
|
|
16
16
|
https://ae-group.gitlab.io/ae_base/coverage/index.html)
|
|
@@ -32,6 +32,9 @@ sortable and compact string from a timestamp.
|
|
|
32
32
|
base helper functions
|
|
33
33
|
---------------------
|
|
34
34
|
|
|
35
|
+
in order to convert and transfer Unicode character outside the 7-bit ASCII range via internet transport protocols,
|
|
36
|
+
like http, use the helper functions :func:`ascii_str` and :func:`str_ascii`.
|
|
37
|
+
|
|
35
38
|
:func:`now_str` creates a timestamp string with the actual UTC date and time. the :func:`utc_datetime` provides the
|
|
36
39
|
actual UTC date and time as datetime object.
|
|
37
40
|
|
|
@@ -155,6 +158,7 @@ import sys
|
|
|
155
158
|
import unicodedata
|
|
156
159
|
import warnings
|
|
157
160
|
|
|
161
|
+
from ast import literal_eval
|
|
158
162
|
from configparser import ConfigParser, ExtendedInterpolation
|
|
159
163
|
from contextlib import contextmanager
|
|
160
164
|
from importlib.machinery import ModuleSpec
|
|
@@ -163,7 +167,7 @@ from types import ModuleType
|
|
|
163
167
|
from typing import Any, Callable, Generator, Iterable, Optional, Union, cast
|
|
164
168
|
|
|
165
169
|
|
|
166
|
-
__version__ = '0.3.
|
|
170
|
+
__version__ = '0.3.54'
|
|
167
171
|
|
|
168
172
|
|
|
169
173
|
os_path_abspath = os.path.abspath
|
|
@@ -176,7 +180,7 @@ os_path_join = os.path.join
|
|
|
176
180
|
os_path_normpath = os.path.normpath
|
|
177
181
|
os_path_realpath = os.path.realpath
|
|
178
182
|
os_path_relpath = os.path.relpath
|
|
179
|
-
os_path_sep = os.path.sep
|
|
183
|
+
os_path_sep = os.path.sep # pylint: disable=invalid-name
|
|
180
184
|
os_path_splitext = os.path.splitext
|
|
181
185
|
|
|
182
186
|
|
|
@@ -275,6 +279,24 @@ def app_name_guess() -> str:
|
|
|
275
279
|
return defuse(app_name)
|
|
276
280
|
|
|
277
281
|
|
|
282
|
+
def ascii_str(unicode_str: str) -> str:
|
|
283
|
+
""" convert non-ASCII chars in str object to a revertible 7-bit/ASCII representation, e.g. to put in a http header.
|
|
284
|
+
|
|
285
|
+
:param unicode_str: string to encode/convert.
|
|
286
|
+
:return: revertible representation of the specified string, using only ASCII characters.
|
|
287
|
+
"""
|
|
288
|
+
return repr(unicode_str.encode())
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def str_ascii(encoded_str: str) -> str:
|
|
292
|
+
""" convert non-ASCII chars in str object encoded with :func:`ascii_str` back to their corresponding Unicode chars.
|
|
293
|
+
|
|
294
|
+
:param encoded_str: string to decode (covert contained ASCII-encoded characters back Unicode chars).
|
|
295
|
+
:return: decoded string.
|
|
296
|
+
"""
|
|
297
|
+
return literal_eval(encoded_str).decode()
|
|
298
|
+
|
|
299
|
+
|
|
278
300
|
def build_config_variable_values(*names_defaults: tuple[str, Any], section: str = 'app') -> tuple[Any, ...]:
|
|
279
301
|
""" determine build config variable values from the ``buildozer.spec`` file in the current directory.
|
|
280
302
|
|
|
@@ -342,6 +364,8 @@ ASCII_UNICODE = (
|
|
|
342
364
|
(')', '⟯'), # U+27EF: MATHEMATICAL RIGHT FLATTENED PARENTHESIS
|
|
343
365
|
('[', '⟦'), # U+27E6: MATHEMATICAL LEFT WHITE SQUARE BRACKET
|
|
344
366
|
(']', '⟧'), # U+27E7: MATHEMATICAL RIGHT WHITE SQUARE BRACKET
|
|
367
|
+
('{', '﹛'), # U+FE5B: Small Left Curly Bracket
|
|
368
|
+
('}', '﹜'), # U+FE5C: Small Right Curly Bracket
|
|
345
369
|
('#', '﹟'), # U+FE5F: Small Number Sign
|
|
346
370
|
(';', '﹔'), # U+FE54: Small Semicolon
|
|
347
371
|
('@', '﹫'), # U+FE6B: Small Commercial At
|
|
@@ -476,13 +500,14 @@ def force_encoding(text: Union[str, bytes], encoding: str = DEF_ENCODING, errors
|
|
|
476
500
|
return enc_str.decode(encoding=encoding)
|
|
477
501
|
|
|
478
502
|
|
|
479
|
-
class UnformattedValue:
|
|
503
|
+
class UnformattedValue: # pylint: disable=too-few-public-methods
|
|
480
504
|
""" helper class for :func:`~ae.base.format_given` to keep placeholder with format unchanged if not found. """
|
|
481
505
|
def __init__(self, key: str):
|
|
482
506
|
self.key = key
|
|
483
507
|
|
|
484
508
|
def __format__(self, format_spec: str):
|
|
485
509
|
""" overriding Python object class method to return placeholder unchanged including the curly brackets. """
|
|
510
|
+
# pylint: disable=consider-using-f-string
|
|
486
511
|
return "{{{}{}}}".format(self.key, ":" + format_spec if format_spec else "")
|
|
487
512
|
|
|
488
513
|
|
|
@@ -514,7 +539,7 @@ def format_given(text: str, placeholder_map: dict[str, Any], strict: bool = Fals
|
|
|
514
539
|
formatter = GivenFormatter()
|
|
515
540
|
try:
|
|
516
541
|
return formatter.vformat(text, (), placeholder_map)
|
|
517
|
-
except (ValueError, Exception) as ex:
|
|
542
|
+
except (ValueError, Exception) as ex: # pylint: disable=broad-except
|
|
518
543
|
if strict:
|
|
519
544
|
raise ex
|
|
520
545
|
return text
|
|
@@ -817,6 +842,7 @@ def os_host_name() -> str:
|
|
|
817
842
|
return defuse(platform.node()) or "indeterminableHostName"
|
|
818
843
|
|
|
819
844
|
|
|
845
|
+
# noinspection PyTypeChecker
|
|
820
846
|
def os_local_ip() -> str:
|
|
821
847
|
""" determine ip address of this system/machine in the local network (LAN or WLAN).
|
|
822
848
|
|
|
@@ -827,16 +853,16 @@ def os_local_ip() -> str:
|
|
|
827
853
|
"""
|
|
828
854
|
socket1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
829
855
|
try:
|
|
830
|
-
socket1.connect(('10.255.255.255', 1))
|
|
856
|
+
socket1.connect(('10.255.255.255', 1)) # doesn't even have to be reachable
|
|
831
857
|
ip_address = socket1.getsockname()[0]
|
|
832
|
-
except (OSError, IOError):
|
|
858
|
+
except (OSError, IOError, Exception): # pylint: disable=broad-except # pragma: no cover
|
|
833
859
|
# ConnectionAbortedError, ConnectionError, ConnectionRefusedError, ConnectionResetError inherit from OSError
|
|
834
860
|
socket2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
835
861
|
try:
|
|
836
862
|
socket2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|
837
863
|
socket2.connect(('<broadcast>', 0))
|
|
838
864
|
ip_address = socket2.getsockname()[0]
|
|
839
|
-
except (OSError, IOError):
|
|
865
|
+
except (OSError, IOError, Exception): # pylint: disable=broad-except
|
|
840
866
|
ip_address = ""
|
|
841
867
|
finally:
|
|
842
868
|
socket2.close()
|
|
@@ -1198,7 +1224,7 @@ def write_file(file_path: str, content: Union[str, bytes],
|
|
|
1198
1224
|
file_handle.write(content)
|
|
1199
1225
|
|
|
1200
1226
|
|
|
1201
|
-
class ErrorMsgMixin:
|
|
1227
|
+
class ErrorMsgMixin: # pylint: disable=too-few-public-methods
|
|
1202
1228
|
""" mixin class providing sophisticated error message handling. """
|
|
1203
1229
|
_err_msg: str = ""
|
|
1204
1230
|
|
|
@@ -1209,7 +1235,7 @@ class ErrorMsgMixin:
|
|
|
1209
1235
|
|
|
1210
1236
|
def __init__(self):
|
|
1211
1237
|
try:
|
|
1212
|
-
from ae.core import main_app_instance # type: ignore
|
|
1238
|
+
from ae.core import main_app_instance # type: ignore # pylint: disable=import-outside-toplevel
|
|
1213
1239
|
|
|
1214
1240
|
self.cae = cae = main_app_instance()
|
|
1215
1241
|
assert cae is not None, f"{self.__class__.__name__}.__init__() called too early; main app instance not"
|
|
@@ -1218,7 +1244,7 @@ class ErrorMsgMixin:
|
|
|
1218
1244
|
self.dpo = cae.dpo
|
|
1219
1245
|
self.vpo = cae.vpo
|
|
1220
1246
|
|
|
1221
|
-
except (ImportError, AssertionError, Exception) as exc:
|
|
1247
|
+
except (ImportError, AssertionError, Exception) as exc: # pylint: disable=broad-except
|
|
1222
1248
|
print(f"{self.__class__.__name__}.__init__() raised {exc}; using print() instead of main app error loggers")
|
|
1223
1249
|
|
|
1224
1250
|
# self.cae = None
|
|
@@ -1278,7 +1304,7 @@ if os_platform == 'android': # pragma: no
|
|
|
1278
1304
|
if _dev_id := Settings.getString(context.getContentResolver(), 'device_name'):
|
|
1279
1305
|
os_device_id = defuse(_dev_id)
|
|
1280
1306
|
|
|
1281
|
-
except Exception:
|
|
1307
|
+
except Exception: # pylint: disable=broad-except
|
|
1282
1308
|
pass
|
|
1283
1309
|
|
|
1284
1310
|
# monkey patch the :func:`shutil.copystat` and :func:`shutil.copymode` helper functions, which are crashing on
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ae_base
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.54
|
|
4
4
|
Summary: ae namespace module portion base: basic constants, helper functions and context manager
|
|
5
5
|
Home-page: https://gitlab.com/ae-group/ae_base
|
|
6
6
|
Author: AndiEcker
|
|
@@ -69,17 +69,17 @@ Dynamic: summary
|
|
|
69
69
|
|
|
70
70
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.95 -->
|
|
71
71
|
<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->
|
|
72
|
-
# base 0.3.
|
|
72
|
+
# base 0.3.54
|
|
73
73
|
|
|
74
74
|
[](
|
|
75
75
|
https://gitlab.com/ae-group/ae_base)
|
|
76
76
|
[](
|
|
78
|
+
https://gitlab.com/ae-group/ae_base/-/tree/release0.3.53)
|
|
79
79
|
[](
|
|
80
80
|
https://pypi.org/project/ae-base/#history)
|
|
81
81
|
|
|
82
|
-
>ae_base module 0.3.
|
|
82
|
+
>ae_base module 0.3.54.
|
|
83
83
|
|
|
84
84
|
[](
|
|
85
85
|
https://ae-group.gitlab.io/ae_base/coverage/index.html)
|
|
@@ -19,18 +19,19 @@ from typing import cast
|
|
|
19
19
|
from ae.base import (
|
|
20
20
|
ASCII_TO_UNICODE, BUILD_CONFIG_FILE, DOTENV_FILE_NAME, PY_EXT, PY_INIT, PY_MAIN, TESTS_FOLDER, UNICODE_TO_ASCII,
|
|
21
21
|
UNSET,
|
|
22
|
-
URI_SEP_CHAR, app_name_guess, build_config_variable_values, camel_to_snake,
|
|
23
|
-
duplicates, env_str,
|
|
24
|
-
|
|
22
|
+
URI_SEP_CHAR, app_name_guess, ascii_str, build_config_variable_values, camel_to_snake,
|
|
23
|
+
dedefuse, deep_dict_update, defuse, dummy_function, duplicates, env_str,
|
|
24
|
+
force_encoding, format_given, full_stack_trace, import_module, instantiate_config_parser, in_wd,
|
|
25
25
|
load_env_var_defaults, load_dotenvs, main_file_paths_parts, mask_secrets, module_attr,
|
|
26
26
|
module_file_path, module_name, norm_line_sep, norm_name, norm_path, now_str,
|
|
27
27
|
os_host_name, os_local_ip, _os_platform, os_user_name,
|
|
28
28
|
parse_dotenv, project_main_file, read_file, round_traditional, snake_to_camel, stack_frames, stack_var, stack_vars,
|
|
29
|
-
sys_env_dict, sys_env_text, to_ascii,
|
|
29
|
+
str_ascii, sys_env_dict, sys_env_text, to_ascii, utc_datetime, write_file,
|
|
30
|
+
ErrorMsgMixin)
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
tst_uri1 = "schema://user:pwd@domain/path_root/path_sub\\path+file% Üml?ä|ït.path_ext*\"<>|*'()[]{}#^;&=$,~" + chr(127)
|
|
33
|
-
tst_fna1 = "schema⫻user﹕pwd﹫domain⁄path_root⁄path_sub﹨path﹢file﹪␣Üml﹖ä।ït.path_ext
|
|
34
|
+
tst_fna1 = "schema⫻user﹕pwd﹫domain⁄path_root⁄path_sub﹨path﹢file﹪␣Üml﹖ä।ït.path_ext﹡"⟨⟩।﹡‘⟮⟯⟦⟧﹛﹜﹟^﹔﹠﹦﹩﹐~␡"
|
|
34
35
|
tst_uri2 = "test control chars" + "".join(chr(_) for _ in range(1, 32))
|
|
35
36
|
tst_fna2 = "test␣control␣chars␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟"
|
|
36
37
|
|
|
@@ -145,6 +146,41 @@ class TestBaseHelpers:
|
|
|
145
146
|
assert app_name_guess() != 'main'
|
|
146
147
|
assert app_name_guess() == 'unguessable'
|
|
147
148
|
|
|
149
|
+
def test_ascii_str(self):
|
|
150
|
+
assert isinstance(ascii_str(""), str)
|
|
151
|
+
|
|
152
|
+
uni_str = "äÄßéÉíÍñÑòÒùÙ"
|
|
153
|
+
assert all(ord(_) >= 128 for _ in uni_str)
|
|
154
|
+
assert all(ord(_) < 128 for _ in ascii_str(uni_str))
|
|
155
|
+
|
|
156
|
+
uni_str = "".join(UNICODE_TO_ASCII.keys())
|
|
157
|
+
assert any(ord(_) >= 128 for _ in uni_str)
|
|
158
|
+
assert all(ord(_) < 128 for _ in ascii_str(uni_str))
|
|
159
|
+
|
|
160
|
+
asc_str = "".join(ASCII_TO_UNICODE.keys())
|
|
161
|
+
assert any(ord(_) < 128 for _ in asc_str)
|
|
162
|
+
assert all(ord(_) < 128 for _ in ascii_str(asc_str))
|
|
163
|
+
|
|
164
|
+
def test_str_ascii(self):
|
|
165
|
+
assert isinstance(str_ascii(ascii_str("tst")), str)
|
|
166
|
+
|
|
167
|
+
assert str_ascii(ascii_str("tst")) == "tst"
|
|
168
|
+
uni_str = "äÄßéÉíÍñÑòÒùÙ"
|
|
169
|
+
assert str_ascii(ascii_str(uni_str)) == uni_str
|
|
170
|
+
|
|
171
|
+
uni_str = "".join(UNICODE_TO_ASCII.keys())
|
|
172
|
+
assert str_ascii(ascii_str(uni_str)) == uni_str
|
|
173
|
+
|
|
174
|
+
asc_str = "".join(ASCII_TO_UNICODE.keys())
|
|
175
|
+
assert str_ascii(ascii_str(asc_str)) == asc_str
|
|
176
|
+
|
|
177
|
+
def test_str_ascii_errors(self):
|
|
178
|
+
with pytest.raises(SyntaxError):
|
|
179
|
+
str_ascii("")
|
|
180
|
+
|
|
181
|
+
with pytest.raises(SyntaxError):
|
|
182
|
+
str_ascii("any tst string not encoded/converted via ascii_str()")
|
|
183
|
+
|
|
148
184
|
def test_build_config_variable_values_with_spec(self):
|
|
149
185
|
try:
|
|
150
186
|
with open(BUILD_CONFIG_FILE, "w") as file_handle:
|
|
@@ -344,9 +380,9 @@ class TestBaseHelpers:
|
|
|
344
380
|
|
|
345
381
|
def test_format_given_err(self):
|
|
346
382
|
with pytest.raises(ValueError):
|
|
347
|
-
format_given("test text with {placeholder", {}, strict=True) #
|
|
383
|
+
format_given("test text with {placeholder", {}, strict=True) # missing closing curly bracket
|
|
348
384
|
with pytest.raises(ValueError):
|
|
349
|
-
format_given("test text with placeholder}", {}, strict=True) #
|
|
385
|
+
format_given("test text with placeholder}", {}, strict=True) # missing opening curly bracket
|
|
350
386
|
|
|
351
387
|
def test_import_module_ae_base(self):
|
|
352
388
|
mod_ref = import_module('ae.base')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|