ae-base 0.3.48__py3-none-any.whl → 0.3.50__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
@@ -100,6 +100,9 @@ allowing also ``None`` is an accepted argument value.
100
100
 
101
101
  to extend any class with an intelligent error message handling, add the mixin :class:`ErrorMsgMixin` to it.
102
102
 
103
+ the classes :class:`UnformattedValue` and :class:`GivenFormatter` can be used to format strings with placeholders
104
+ enclosed in curly brackets. the function :func:`format_given` is using them to format templates with placeholders.
105
+
103
106
 
104
107
  generic context manager
105
108
  -----------------------
@@ -144,6 +147,7 @@ import platform
144
147
  import re
145
148
  import shutil
146
149
  import socket
150
+ import string
147
151
  import sys
148
152
  import unicodedata
149
153
  import warnings
@@ -156,7 +160,7 @@ from types import ModuleType
156
160
  from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple, Union, cast
157
161
 
158
162
 
159
- __version__ = '0.3.48'
163
+ __version__ = '0.3.50'
160
164
 
161
165
 
162
166
  os_path_abspath = os.path.abspath
@@ -469,6 +473,50 @@ def force_encoding(text: Union[str, bytes], encoding: str = DEF_ENCODING, errors
469
473
  return enc_str.decode(encoding=encoding)
470
474
 
471
475
 
476
+ class UnformattedValue:
477
+ """ helper class for :func:`~ae.base.format_given` to keep placeholder with format unchanged if not found. """
478
+ def __init__(self, key: str):
479
+ self.key = key
480
+
481
+ def __format__(self, format_spec: str):
482
+ """ overriding Python object class method to return placeholder unchanged including the curly brackets. """
483
+ return "{{{}{}}}".format(self.key, ":" + format_spec if format_spec else "")
484
+
485
+
486
+ class GivenFormatter(string.Formatter):
487
+ """ helper class for :func:`~ae.base.format_given` to keep placeholder with format unchanged if not found. """
488
+ def get_value(self, key, args, kwargs):
489
+ """ overriding to keep placeholder unchanged if not found """
490
+ try:
491
+ return super().get_value(key, args, kwargs)
492
+ except KeyError:
493
+ return UnformattedValue(key)
494
+
495
+
496
+ def format_given(text: str, placeholder_map: dict[str, Any], strict: bool = False):
497
+ """ replacement for Python's str.format_map(), keeping intact placeholders that are not in the specified mapping.
498
+
499
+ :param text: text/template in which the given/specified placeholders will get replaced. in contrary
500
+ to str.format_map() no KeyError will be raised for placeholders not specified in
501
+ :paramref:`~format_given.placeholder_map`.
502
+ :param placeholder_map: dict with placeholder keys to be replaced in :paramref:`~format_given.text` argument.
503
+ :param strict: pass True to raise error for text templates containing unpaired curly brackets.
504
+ :return: the specified :paramref:`~format_given.text` with only the placeholders specified in
505
+ :paramref:`~format_given.placeholder_map` replaced with their respective map value.
506
+ additionally any ValueError that would be thrown by str.format_map(), e.g. if the
507
+
508
+
509
+ inspired by the answer of CodeManX in `https://stackoverflow.com/questions/3536303`__
510
+ """
511
+ formatter = GivenFormatter()
512
+ try:
513
+ return formatter.vformat(text, (), placeholder_map)
514
+ except (ValueError, Exception) as ex:
515
+ if strict:
516
+ raise ex
517
+ return text
518
+
519
+
472
520
  def full_stack_trace(ex: Exception) -> str:
473
521
  """ get full stack trace from an exception.
474
522
 
@@ -1018,15 +1066,17 @@ def sys_env_dict() -> Dict[str, Any]:
1018
1066
  .. hint:: see also https://pyinstaller.readthedocs.io/en/stable/runtime-information.html
1019
1067
  """
1020
1068
  sed: Dict[str, Any] = {
1021
- 'python_ver': sys.version.replace('\n', ' '),
1069
+ 'python ver': sys.version.replace('\n', ' '),
1022
1070
  'platform': os_platform,
1023
1071
  'argv': sys.argv,
1024
1072
  'executable': sys.executable,
1025
1073
  'cwd': os.getcwd(),
1026
1074
  'frozen': getattr(sys, 'frozen', False),
1027
- 'user_name': os_user_name(),
1028
- 'host_name': os_host_name(),
1075
+ 'user name': os_user_name(),
1076
+ 'host name': os_host_name(),
1077
+ 'device id': os_device_id,
1029
1078
  'app_name_guess': app_name_guess(),
1079
+ 'os env': os.environ.copy(),
1030
1080
  }
1031
1081
 
1032
1082
  if sed['frozen']:
@@ -1172,7 +1222,39 @@ class ErrorMsgMixin:
1172
1222
  self._err_msg = ""
1173
1223
 
1174
1224
 
1175
- if os_platform == 'android': # pragma: no cover
1225
+ # platform-specific patches
1226
+ os_device_id = os_host_name()
1227
+ """ user-definable id/name of the device, defaults to os_host_name() on most platforms, alternatives are:
1228
+
1229
+ on all platforms:
1230
+ - socket.gethostname()
1231
+ on Android (check with adb shell 'settings get global device_name' and adb shell 'settings list global'):
1232
+ - Settings.Global.DEVICE_NAME (Settings.Global.getString(context.getContentResolver(), "device_name"))
1233
+ - android.os.Build.DEVICE/.MANUFACTURER/.BRAND/.HOST
1234
+ - DeviceName.getDeviceName()
1235
+ on MS Windows:
1236
+ - os.environ['COMPUTERNAME']
1237
+ """
1238
+ if os_platform == 'android': # pragma: no cover
1239
+ # determine Android device id because os_host_name() returns mostly 'localhost' and not the user-definable device id
1240
+ from jnius import autoclass # type: ignore
1241
+
1242
+ # noinspection PyBroadException
1243
+ try:
1244
+ Settings = autoclass('android.provider.Settings$Global')
1245
+ PythonActivity = autoclass('org.kivy.android.PythonActivity')
1246
+
1247
+ # mActivity inherits from Context so no need to cast('android.content.Context',..) neither get app context
1248
+ # _Context = autoclass('android.content.Context')
1249
+ # context = cast('android.content.Context', PythonActivity.mActivity)
1250
+ # context = PythonActivity.mActivity.getApplicationContext()
1251
+ context = PythonActivity.mActivity
1252
+ if _dev_id := Settings.getString(context.getContentResolver(), 'device_name'):
1253
+ os_device_id = defuse(_dev_id)
1254
+
1255
+ except Exception:
1256
+ pass
1257
+
1176
1258
  # monkey patch the :func:`shutil.copystat` and :func:`shutil.copymode` helper functions, which are crashing on
1177
1259
  # 'android' (see # `<https://bugs.python.org/issue28141>`__ and `<https://bugs.python.org/issue32073>`__). these
1178
1260
  # functions are used by shutil.copy2/copy/copytree/move to copy OS-specific file attributes.
@@ -1181,3 +1263,8 @@ if os_platform == 'android': # pragma: no cov
1181
1263
  # on the destination root directory.
1182
1264
  shutil.copymode = dummy_function
1183
1265
  shutil.copystat = dummy_function
1266
+
1267
+
1268
+ elif os_platform in ('win32', 'cygwin'): # pragma: no cover
1269
+ if _dev_id := os.environ.get('COMPUTERNAME'):
1270
+ os_device_id = defuse(_dev_id)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ae_base
3
- Version: 0.3.48
3
+ Version: 0.3.50
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
@@ -68,17 +68,17 @@ Dynamic: summary
68
68
 
69
69
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.95 -->
70
70
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->
71
- # base 0.3.48
71
+ # base 0.3.50
72
72
 
73
73
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](
74
74
  https://gitlab.com/ae-group/ae_base)
75
75
  [![LatestPyPIrelease](
76
- https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.47?logo=python)](
77
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.47)
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)
78
78
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](
79
79
  https://pypi.org/project/ae-base/#history)
80
80
 
81
- >ae_base module 0.3.48.
81
+ >ae_base module 0.3.50.
82
82
 
83
83
  [![Coverage](https://ae-group.gitlab.io/ae_base/coverage.svg)](
84
84
  https://ae-group.gitlab.io/ae_base/coverage/index.html)
@@ -0,0 +1,7 @@
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,7 +0,0 @@
1
- ae/base.py,sha256=oZBQxpBifv7BEcygj_JmsEMebDnEBaZiL5v1DCUxPOE,58770
2
- ae_base-0.3.48.dist-info/LICENSE.md,sha256=uoIIfORuk4V8ZeNh6SN0EUhiU79RC-indIMFqePKVhY,35002
3
- ae_base-0.3.48.dist-info/METADATA,sha256=HEFW7mCBlpRR8EHFK0B0ZgIEuCD1lXSVA73Bb9kRE_4,5636
4
- ae_base-0.3.48.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
5
- ae_base-0.3.48.dist-info/top_level.txt,sha256=vUdgAslSmhZLXWU48fm8AG2BjVnkOWLco8rzuW-5zY0,3
6
- ae_base-0.3.48.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
7
- ae_base-0.3.48.dist-info/RECORD,,