ae-base 0.3.50__py3-none-any.whl → 0.3.51__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.
ae/base.py CHANGED
@@ -40,6 +40,9 @@ and :func:`write_file` are wrapping Python's built-in :func:`open` function and
40
40
 
41
41
  the function :func:`duplicates` returns the duplicates of an iterable type.
42
42
 
43
+ in order to hide/mask secrets like credit card numbers, passwords or tokens in deeply nested data structures,
44
+ before they get dumped e.g. to an app log file, the function :func:`mask_secrets` can be used.
45
+
43
46
  :func:`norm_line_sep` is converting any combination of line separators of a string to a single new-line character.
44
47
 
45
48
  :func:`norm_name` converts any string into a name that can be used e.g. as file name or as method/attribute name.
@@ -157,10 +160,10 @@ from contextlib import contextmanager
157
160
  from importlib.machinery import ModuleSpec
158
161
  from inspect import getinnerframes, getouterframes, getsourcefile
159
162
  from types import ModuleType
160
- from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple, Union, cast
163
+ from typing import Any, Callable, Generator, Iterable, Optional, Union, cast
161
164
 
162
165
 
163
- __version__ = '0.3.50'
166
+ __version__ = '0.3.51'
164
167
 
165
168
 
166
169
  os_path_abspath = os.path.abspath
@@ -272,7 +275,7 @@ def app_name_guess() -> str:
272
275
  return defuse(app_name)
273
276
 
274
277
 
275
- def build_config_variable_values(*names_defaults: Tuple[str, Any], section: str = 'app') -> Tuple[Any, ...]:
278
+ def build_config_variable_values(*names_defaults: tuple[str, Any], section: str = 'app') -> tuple[Any, ...]:
276
279
  """ determine build config variable values from the ``buildozer.spec`` file in the current directory.
277
280
 
278
281
  :param names_defaults: tuple of tuples of build config variable names and default values.
@@ -634,7 +637,7 @@ def load_env_var_defaults(start_dir: str):
634
637
  file_path = os_path_join(os_path_dirname(os_path_dirname(file_path)), DOTENV_FILE_NAME)
635
638
 
636
639
 
637
- def main_file_paths_parts(portion_name: str) -> Tuple[Tuple[str, ...], ...]:
640
+ def main_file_paths_parts(portion_name: str) -> tuple[tuple[str, ...], ...]:
638
641
  """ determine tuple of supported main/version file name path part tuples.
639
642
 
640
643
  :param portion_name: portion or package name.
@@ -650,6 +653,29 @@ def main_file_paths_parts(portion_name: str) -> Tuple[Tuple[str, ...], ...]:
650
653
  )
651
654
 
652
655
 
656
+ def mask_secrets(data: Union[dict, Iterable], fragments: Iterable[str] = ('password', 'pwd')) -> Union[dict, Iterable]:
657
+ """ partially-hide secret string values like passwords/credit-card-numbers in deeply nestable data structures.
658
+
659
+ :param data: iterable deep data structure wherein its item values get masked if their related dict
660
+ item key contains one of the fragments specified in :paramref:`~mask_secrets.fragments`.
661
+ :param fragments: dict key string fragments of which the related value will be masked. each fragment has
662
+ to be specified in lower case! defaults to ('password', 'pwd') if not passed.
663
+ :return: specified data structure with the secrets masked (¡in-place!).
664
+ """
665
+ is_dict = isinstance(data, dict)
666
+
667
+ for idx, val in tuple(data.items()) if is_dict else enumerate(data): # type: ignore # silly mypy not sees is_dict
668
+ val_is_str = isinstance(val, str)
669
+ if not val_is_str and isinstance(val, Iterable):
670
+ mask_secrets(val, fragments=fragments)
671
+ elif is_dict and val_is_str and isinstance(idx, str):
672
+ idx = idx.lower()
673
+ if any(_frag in idx for _frag in fragments):
674
+ data[idx] = val[:3] + "*" * 9 # type: ignore # silly mypy not sees is_dict
675
+
676
+ return data
677
+
678
+
653
679
  def module_attr(import_name: str, attr_name: str = "") -> Optional[Any]:
654
680
  """ determine dynamically a reference to a module or to any attribute (variable/func/class) declared in the module.
655
681
 
@@ -722,7 +748,7 @@ def norm_name(name: str, allow_num_prefix: bool = False) -> str:
722
748
  :param allow_num_prefix: pass True to allow leading digits in the returned normalized name.
723
749
  :return: cleaned/normalized/converted name string (e.g. for a variable-/method-/file-name).
724
750
  """
725
- str_parts: List[str] = []
751
+ str_parts: list[str] = []
726
752
  for char in name:
727
753
  if char.isalpha() or char.isalnum() and (allow_num_prefix or str_parts):
728
754
  str_parts.append(char)
@@ -855,13 +881,13 @@ def os_user_name() -> str:
855
881
  return getpass.getuser()
856
882
 
857
883
 
858
- def parse_dotenv(file_path: str) -> Dict[str, str]:
884
+ def parse_dotenv(file_path: str) -> dict[str, str]:
859
885
  """ parse ``.env`` file content and return environment variable names as dict keys and values as dict values.
860
886
 
861
887
  :param file_path: string with the name/path of an existing ``.env``/:data:`DOTENV_FILE_NAME` file.
862
888
  :return: dict with environment variable names and values
863
889
  """
864
- env_vars: Dict[str, str] = {}
890
+ env_vars: dict[str, str] = {}
865
891
  for line in cast(str, read_file(file_path)).splitlines():
866
892
  match = _env_line.search(line)
867
893
  if not match:
@@ -1017,7 +1043,7 @@ def stack_var(name: str, *skip_modules: str, scope: str = '', depth: int = 1) ->
1017
1043
 
1018
1044
  def stack_vars(*skip_modules: str,
1019
1045
  find_name: str = '', min_depth: int = 1, max_depth: int = 0, scope: str = ''
1020
- ) -> Tuple[Dict[str, Any], Dict[str, Any], int]:
1046
+ ) -> tuple[dict[str, Any], dict[str, Any], int]:
1021
1047
  """ determine all global and local variables in a calling stack/frames.
1022
1048
 
1023
1049
  :param skip_modules: module names to skip (def=see :data:`SKIPPED_MODULES` module constant).
@@ -1057,7 +1083,7 @@ def stack_vars(*skip_modules: str,
1057
1083
  return glo.copy(), loc, depth - 1
1058
1084
 
1059
1085
 
1060
- def sys_env_dict() -> Dict[str, Any]:
1086
+ def sys_env_dict() -> dict[str, Any]:
1061
1087
  """ returns dict with python system run-time environment values.
1062
1088
 
1063
1089
  :return: python system run-time environment values like python_ver, argv, cwd, executable,
@@ -1065,7 +1091,7 @@ def sys_env_dict() -> Dict[str, Any]:
1065
1091
 
1066
1092
  .. hint:: see also https://pyinstaller.readthedocs.io/en/stable/runtime-information.html
1067
1093
  """
1068
- sed: Dict[str, Any] = {
1094
+ sed: dict[str, Any] = {
1069
1095
  'python ver': sys.version.replace('\n', ' '),
1070
1096
  'platform': os_platform,
1071
1097
  'argv': sys.argv,
@@ -1076,7 +1102,7 @@ def sys_env_dict() -> Dict[str, Any]:
1076
1102
  'host name': os_host_name(),
1077
1103
  'device id': os_device_id,
1078
1104
  'app_name_guess': app_name_guess(),
1079
- 'os env': os.environ.copy(),
1105
+ 'os env': mask_secrets(os.environ.copy()),
1080
1106
  }
1081
1107
 
1082
1108
  if sed['frozen']:
@@ -1086,7 +1112,7 @@ def sys_env_dict() -> Dict[str, Any]:
1086
1112
 
1087
1113
 
1088
1114
  def sys_env_text(ind_ch: str = " ", ind_len: int = 12, key_ch: str = "=", key_len: int = 15,
1089
- extra_sys_env_dict: Optional[Dict[str, str]] = None) -> str:
1115
+ extra_sys_env_dict: Optional[dict[str, str]] = None) -> str:
1090
1116
  """ compile formatted text block with system environment info.
1091
1117
 
1092
1118
  :param ind_ch: indent character (defaults to " ").
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: ae_base
3
- Version: 0.3.50
3
+ Version: 0.3.51
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
@@ -61,6 +61,7 @@ Dynamic: description-content-type
61
61
  Dynamic: home-page
62
62
  Dynamic: keywords
63
63
  Dynamic: license
64
+ Dynamic: license-file
64
65
  Dynamic: project-url
65
66
  Dynamic: provides-extra
66
67
  Dynamic: requires-python
@@ -68,17 +69,17 @@ Dynamic: summary
68
69
 
69
70
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.95 -->
70
71
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->
71
- # base 0.3.50
72
+ # base 0.3.51
72
73
 
73
74
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](
74
75
  https://gitlab.com/ae-group/ae_base)
75
76
  [![LatestPyPIrelease](
76
- https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.49?logo=python)](
77
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.49)
77
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.50?logo=python)](
78
+ https://gitlab.com/ae-group/ae_base/-/tree/release0.3.50)
78
79
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](
79
80
  https://pypi.org/project/ae-base/#history)
80
81
 
81
- >ae_base module 0.3.50.
82
+ >ae_base module 0.3.51.
82
83
 
83
84
  [![Coverage](https://ae-group.gitlab.io/ae_base/coverage.svg)](
84
85
  https://ae-group.gitlab.io/ae_base/coverage/index.html)
@@ -0,0 +1,7 @@
1
+ ae/base.py,sha256=SeQfFkj2ODRqwpp2yUSLlkf0YC1dfaJQ9ZnBtZ760jo,64599
2
+ ae_base-0.3.51.dist-info/licenses/LICENSE.md,sha256=uoIIfORuk4V8ZeNh6SN0EUhiU79RC-indIMFqePKVhY,35002
3
+ ae_base-0.3.51.dist-info/METADATA,sha256=maz0cd02j373QhmJA1ZJ1VhKQJrFjTSxwO3f7M8N0tA,5658
4
+ ae_base-0.3.51.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
5
+ ae_base-0.3.51.dist-info/top_level.txt,sha256=vUdgAslSmhZLXWU48fm8AG2BjVnkOWLco8rzuW-5zY0,3
6
+ ae_base-0.3.51.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
7
+ ae_base-0.3.51.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.2)
2
+ Generator: setuptools (77.0.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,7 +0,0 @@
1
- ae/base.py,sha256=1me3TvKdrXFKVDI9qqXYzJ52d0d3qVw21rY643gymY0,62992
2
- ae_base-0.3.50.dist-info/LICENSE.md,sha256=uoIIfORuk4V8ZeNh6SN0EUhiU79RC-indIMFqePKVhY,35002
3
- ae_base-0.3.50.dist-info/METADATA,sha256=1YUr5FieYlbsSE_1atpH6N0uJmYfTRd4tcpxrtqmJRQ,5636
4
- ae_base-0.3.50.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
5
- ae_base-0.3.50.dist-info/top_level.txt,sha256=vUdgAslSmhZLXWU48fm8AG2BjVnkOWLco8rzuW-5zY0,3
6
- ae_base-0.3.50.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
7
- ae_base-0.3.50.dist-info/RECORD,,