ae-base 0.3.70__tar.gz → 0.3.71__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ae_base
3
- Version: 0.3.70
3
+ Version: 0.3.71
4
4
  Summary: ae namespace module portion base: basic constants, helper functions and context managers
5
5
  Home-page: https://gitlab.com/ae-group/ae_base
6
6
  Author: AndiEcker
@@ -65,13 +65,13 @@ Dynamic: summary
65
65
 
66
66
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.97 -->
67
67
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.19 -->
68
- # base 0.3.70
68
+ # base 0.3.71
69
69
 
70
70
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](
71
71
  https://gitlab.com/ae-group/ae_base)
72
72
  [![LatestPyPIrelease](
73
- https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.70?logo=python)](
74
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.70)
73
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.71?logo=python)](
74
+ https://gitlab.com/ae-group/ae_base/-/tree/release0.3.71)
75
75
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](
76
76
  https://pypi.org/project/ae-base/#history)
77
77
 
@@ -1,12 +1,12 @@
1
1
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.97 -->
2
2
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.19 -->
3
- # base 0.3.70
3
+ # base 0.3.71
4
4
 
5
5
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](
6
6
  https://gitlab.com/ae-group/ae_base)
7
7
  [![LatestPyPIrelease](
8
- https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.70?logo=python)](
9
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.70)
8
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.71?logo=python)](
9
+ https://gitlab.com/ae-group/ae_base/-/tree/release0.3.71)
10
10
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](
11
11
  https://pypi.org/project/ae-base/#history)
12
12
 
@@ -246,7 +246,7 @@ from types import ModuleType
246
246
  from typing import Any, Callable, Generator, Iterable, MutableMapping, Optional, Union, cast
247
247
 
248
248
 
249
- __version__ = '0.3.70'
249
+ __version__ = '0.3.71'
250
250
 
251
251
 
252
252
  os_path_abspath = os.path.abspath
@@ -1362,17 +1362,20 @@ def url_failure(url: str, token: str = "", username: str = "", password: str = "
1362
1362
  return f"{exception.code} {mask_url(url)} raised HTTPError {exception.reason=}"
1363
1363
 
1364
1364
  except URLError as exception:
1365
- err_prefix = f"996 {mask_url(url)} raised {exception.errno=} {exception.reason=};"
1365
+ err_msg = f" {mask_url(url)} raised {exception.errno=} {exception.reason=};"
1366
1366
  if isinstance(exception.reason, socket.gaierror):
1367
- return f"{err_prefix} could not resolve hostname"
1368
- if isinstance(exception.reason, socket.timeout):
1369
- return f"{err_prefix} connection timed out after {timeout} seconds"
1367
+ return '995' + f"{err_msg} could not resolve hostname"
1370
1368
  if isinstance(exception.reason, ssl.SSLCertVerificationError):
1371
- return f"{err_prefix} SSL certificate verification failed"
1372
- return f"{err_prefix} could not reach the server"
1369
+ return '996' + f"{err_msg} SSL certificate verification failed"
1370
+ if isinstance(exception.reason, socket.timeout):
1371
+ return '997' + f"{err_msg} connection timed out after {timeout} seconds"
1372
+ return '998' + f"{err_msg} could not reach the server"
1373
+
1374
+ except socket.timeout as _exception: # noqa: F841 # str(_exception) could contain password|token
1375
+ return '997' + f" {mask_url(url)} raised socket-timeout exception after {timeout} seconds"
1373
1376
 
1374
- except Exception: # pylint: disable=broad-exception-caught
1375
- return f"999 {mask_url(url)} raised unexpected exception" # NOT put str(_exception) because contains password
1377
+ except Exception as _exception: # noqa: F841 # pylint: disable=broad-exception-caught
1378
+ return '999' + f" {mask_url(url)} raised unexpected exception" # str(_exception) COULD contain password
1376
1379
 
1377
1380
 
1378
1381
  def utc_datetime() -> datetime.datetime:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ae_base
3
- Version: 0.3.70
3
+ Version: 0.3.71
4
4
  Summary: ae namespace module portion base: basic constants, helper functions and context managers
5
5
  Home-page: https://gitlab.com/ae-group/ae_base
6
6
  Author: AndiEcker
@@ -65,13 +65,13 @@ Dynamic: summary
65
65
 
66
66
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.97 -->
67
67
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.19 -->
68
- # base 0.3.70
68
+ # base 0.3.71
69
69
 
70
70
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](
71
71
  https://gitlab.com/ae-group/ae_base)
72
72
  [![LatestPyPIrelease](
73
- https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.70?logo=python)](
74
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.70)
73
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.71?logo=python)](
74
+ https://gitlab.com/ae-group/ae_base/-/tree/release0.3.71)
75
75
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](
76
76
  https://pypi.org/project/ae-base/#history)
77
77
 
@@ -25,13 +25,13 @@ setup_kwargs = {
25
25
  'license': 'GPL-3.0-or-later',
26
26
  'long_description': ('<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.97 -->\n'
27
27
  '<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.19 -->\n'
28
- '# base 0.3.70\n'
28
+ '# base 0.3.71\n'
29
29
  '\n'
30
30
  '[![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](\n'
31
31
  ' https://gitlab.com/ae-group/ae_base)\n'
32
32
  '[![LatestPyPIrelease](\n'
33
- ' https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.70?logo=python)](\n'
34
- ' https://gitlab.com/ae-group/ae_base/-/tree/release0.3.70)\n'
33
+ ' https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.71?logo=python)](\n'
34
+ ' https://gitlab.com/ae-group/ae_base/-/tree/release0.3.71)\n'
35
35
  '[![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](\n'
36
36
  ' https://pypi.org/project/ae-base/#history)\n'
37
37
  '\n'
@@ -108,7 +108,7 @@ setup_kwargs = {
108
108
  'Source': 'https://ae.readthedocs.io/en/latest/_modules/ae/base.html'},
109
109
  'python_requires': '>=3.9',
110
110
  'url': 'https://gitlab.com/ae-group/ae_base',
111
- 'version': '0.3.70',
111
+ 'version': '0.3.71',
112
112
  'zip_safe': True,
113
113
  }
114
114
 
@@ -1,9 +1,6 @@
1
1
  """ ae.base unit tests """
2
2
  import datetime
3
3
  import os
4
- import time
5
-
6
- import pytest
7
4
  import shutil
8
5
  import socket
9
6
  import ssl
@@ -11,16 +8,20 @@ import string
11
8
  import sys
12
9
  import tempfile
13
10
  import textwrap
11
+ import time
12
+ import timeit
14
13
 
15
14
  from collections import OrderedDict
16
15
  from configparser import ConfigParser
17
16
  # noinspection PyProtectedMember
18
17
  from http.client import HTTPMessage
19
18
  from types import ModuleType
20
- from typing import cast, Any
19
+ from typing import cast, Any, Optional
21
20
  from unittest.mock import patch
22
21
  from urllib.error import HTTPError, URLError
23
22
 
23
+ import pytest
24
+
24
25
  # noinspection PyProtectedMember
25
26
  from ae.base import (
26
27
  ASCII_TO_UNICODE, ASCII_UNICODE, BUILD_CONFIG_FILE, DOTENV_FILE_NAME, PY_EXT, PY_INIT, PY_MAIN, TESTS_FOLDER,
@@ -69,15 +70,32 @@ def os_env_test_env():
69
70
  module_test_var = 'module_test_var_val' # used for stack_var()/try_exec() tests
70
71
 
71
72
 
72
- def test_unset_truthiness():
73
+ def test_unset_truthiness_and_null_length():
73
74
  assert not UNSET
74
75
  assert bool(UNSET) is False
75
76
 
76
-
77
- def test_unset_null_length():
78
77
  assert len(UNSET) == 0
79
78
 
80
79
 
80
+ def test_proof_os_path_shortcuts_performance_win():
81
+ att_call_setup = textwrap.dedent("""
82
+ import os
83
+ path1, path2, path3 = "folder1", "folder2", "file.tst"
84
+ """)
85
+ sho_call_setup = att_call_setup + textwrap.dedent("""
86
+ os_path_join = os.path.join
87
+ """)
88
+
89
+ att_call_code = "os.path.join(path1, path2, path3)"
90
+ sho_call_code = "os_path_join(path1, path2, path3)"
91
+
92
+ time_att = timeit.timeit(att_call_code, setup=att_call_setup, number=3_000_000)
93
+ time_sho = timeit.timeit(sho_call_code, setup=sho_call_setup, number=3_000_000)
94
+
95
+ assert time_sho < time_att
96
+ print(f"\n¡!¡!¡! os_path_* shortcuts are ~{((time_att - time_sho) / time_att) * 100:.2f}% faster")
97
+
98
+
81
99
  class TestErrorMsgMixin:
82
100
  def test_instantiation(self):
83
101
  ins = ErrorMsgMixin()
@@ -1069,6 +1087,17 @@ class TestBaseHelpers:
1069
1087
  assert to_ascii('ß') == 'ss'
1070
1088
  assert to_ascii('€') == 'Euro'
1071
1089
 
1090
+ @staticmethod
1091
+ def url_failure_httpbin_503_retryer(url: str, timeout: Optional[float] = None) -> tuple[str, str]:
1092
+ retries = 9
1093
+ while True:
1094
+ err_msg = url_failure(url, timeout=timeout)
1095
+ if not err_msg or int(err_msg[:3]) != 503 or retries == 0:
1096
+ break
1097
+ time.sleep(3)
1098
+ retries -= 1
1099
+ return err_msg, f"url_failure({url=}, {timeout=}) httpbin is sometimes unavailable/503. retry later; {err_msg=}"
1100
+
1072
1101
  def test_url_failure(self):
1073
1102
  assert not url_failure("https://gitlab.com/ae-group/ae_base")
1074
1103
 
@@ -1078,14 +1107,8 @@ class TestBaseHelpers:
1078
1107
 
1079
1108
  assert not url_failure("https://www.google.com")
1080
1109
 
1081
- retries = 9
1082
- while True:
1083
- err_msg = url_failure(f"https://httpbin.org/status/200")
1084
- if not err_msg or retries == 0:
1085
- break
1086
- time.sleep(3)
1087
- retries -= 1
1088
- assert not err_msg, f"httpbin is sometimes unavailable with error 503 - retry later; {err_msg=}"
1110
+ ret, message = self.url_failure_httpbin_503_retryer("https://httpbin.org/status/200")
1111
+ assert not ret, message
1089
1112
 
1090
1113
  def test_url_failure_authentication_errors(self):
1091
1114
  password, domain, path = "toBeMaskedPassword", "any-not_existing-host_domain.zzz", "any/not/existing/url/path"
@@ -1215,19 +1238,19 @@ class TestBaseHelpers:
1215
1238
  assert int(ret[:3]) > 0
1216
1239
 
1217
1240
  def test_url_failure_timeout_errors(self):
1218
- ret = url_failure(f"https://httpbin.org/delay/3", timeout=0.9)
1241
+ ret, message = self.url_failure_httpbin_503_retryer("https://httpbin.org/delay/3", timeout=0.9)
1219
1242
 
1220
- assert ret
1221
- assert int(ret[:3]) > 0
1243
+ assert ret, message
1244
+ assert ret[:3] == '997', message
1222
1245
 
1223
1246
  def test_url_failure_url_errors(self):
1224
1247
  assert url_failure("")
1225
1248
 
1226
- ret = url_failure(url2 := f"https://httpbin.org/status/504")
1249
+ ret, message = self.url_failure_httpbin_503_retryer(url2 := "https://httpbin.org/status/504")
1227
1250
 
1228
- assert ret
1229
- assert int(ret[:3]) == 504
1230
- assert ret[4:].startswith(mask_url(url2))
1251
+ assert ret, message
1252
+ assert ret[:3] == '504', message
1253
+ assert ret[4:].startswith(mask_url(url2)), message
1231
1254
 
1232
1255
  with pytest.raises(AttributeError):
1233
1256
  url_failure(cast(str, 123456))
File without changes
File without changes
File without changes