ae-base 0.3.44__py3-none-any.whl → 0.3.46__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
@@ -9,10 +9,10 @@ functions, useful classes and context managers.
9
9
  base constants
10
10
  --------------
11
11
 
12
- ISO format strings for `date` and `datetime` values are provided by the constants :data:`DATE_ISO` and
12
+ ISO format strings for ``date`` and ``datetime`` values are provided by the constants :data:`DATE_ISO` and
13
13
  :data:`DATE_TIME_ISO`.
14
14
 
15
- the :data:`UNSET` constant is useful in cases where `None` is a valid data value and another special value is needed
15
+ the :data:`UNSET` constant is useful in cases where ``None`` is a valid data value and another special value is needed
16
16
  to specify that e.g. an argument or attribute has no (valid) value or did not get specified/passed.
17
17
 
18
18
  default values to compile file and folder names for a package or an app project are provided by the constants:
@@ -20,8 +20,8 @@ default values to compile file and folder names for a package or an app project
20
20
  :data:`PACKAGE_INCLUDE_FILES_PREFIX`, :data:`PY_EXT`, :data:`PY_INIT`, :data:`PY_MAIN`, :data:`CFG_EXT`
21
21
  and :data:`INI_EXT`.
22
22
 
23
- the constants :data:`PACKAGE_NAME`, :data:`PACKAGE_DOMAIN` and :data:`PERMISSIONS` are mainly used for apps running
24
- on mobile devices. to avoid redundancies, these values get loaded from the
23
+ the constants :data:`PACKAGE_NAME`, :data:`PACKAGE_DOMAIN` and :data:`PERMISSIONS` are mainly
24
+ used for apps running on mobile devices. to avoid redundancies, these values get loaded from the
25
25
  :data:`build config file <BUILD_CONFIG_FILE>` - if it exists in the current working directory.
26
26
 
27
27
  with the help of the format string constant :data:`NOW_STR_FORMAT` and the function :func:`now_str` you can create a
@@ -104,8 +104,8 @@ links to other android code and service examples and documentation:
104
104
  * `https://github.com/Android-for-Python/Android-for-Python-Users`__
105
105
  * `https://github.com/Android-for-Python/INDEX-of-Examples`__
106
106
 
107
- big thanks to `Robert Flatt <https://github.com/RobertFlatt>`_ for his investigations, findings and documentations to
108
- code and build Kivy apps for the Android OS, and to `Gabriel Pettier <https://github.com/tshirtman>`_ for his service
107
+ big thanks to `Robert Flatt <https://github.com/RobertFlatt>`__ for his investigations, findings and documentations to
108
+ code and build Kivy apps for the Android OS, and to `Gabriel Pettier <https://github.com/tshirtman>`__ for his service
109
109
  osc example.
110
110
 
111
111
 
@@ -113,9 +113,9 @@ types, classes and mixins
113
113
  -------------------------
114
114
 
115
115
  the :class:`UnsetType` class can be used e.g. for the declaration of optional function and method parameters,
116
- allowing also `None` is an accepted argument value.
116
+ allowing also ``None`` is an accepted argument value.
117
117
 
118
- to extend any class with an intelligent error message property, add the mixin :class:`ErrorMsgMixin` to it.
118
+ to extend any class with an intelligent error message handling, add the mixin :class:`ErrorMsgMixin` to it.
119
119
 
120
120
 
121
121
  generic context manager
@@ -173,7 +173,7 @@ from types import ModuleType
173
173
  from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple, Union, cast
174
174
 
175
175
 
176
- __version__ = '0.3.44'
176
+ __version__ = '0.3.46'
177
177
 
178
178
 
179
179
  os_path_abspath = os.path.abspath
@@ -265,7 +265,7 @@ class UnsetType:
265
265
  return 0
266
266
 
267
267
 
268
- UNSET = UnsetType() #: pseudo value used for attributes/arguments if `None` is needed as a valid value
268
+ UNSET = UnsetType() #: pseudo value used for attributes/arguments if ``None`` is needed as a valid value
269
269
 
270
270
 
271
271
  def app_name_guess() -> str:
@@ -363,9 +363,13 @@ ASCII_UNICODE = (
363
363
  ('%', '﹪'), # U+FE6A: Small Percent Sign
364
364
  ('^', '^'), # U+FF3E: Fullwidth Circumflex Accent
365
365
  (',', '﹐'), # U+FE50: Small Comma
366
- (' ', ' '), # U+3000: Ideographic Space; ' ' U+200A Hair Space; ' ' U+2007 Figure Space;
367
- # ' ' U+2009 Thin; ' ' U+2003 Em Space; '' U+2002 En Space; '' U+2008 Punctuation Space
368
- # ' ' U+00A0: No-Break Space (NBSP); '' U+202F: Narrow No-Break Space (NNBSP)
366
+ (' ', ''), # U+2423: Open Box; more see underneath and https://unicode-explorer.com/articles/space-characters:
367
+ # ' ' U+00A0: No-Break Space (NBSP); '?¿?' U+1680 Ogham Space Mark; ' ' U+2000 En Quad;
368
+ # ' ' U+2001 Em Quad; ' ' U+2002 En Space; '' U+2003 Em Space; ' ' U+2004 Three-Per-Em
369
+ # ' ' U+2005 Four-Per-Em; ' ' U+2006 Six-Per-Em; ' ' U+2007 Figure Space;
370
+ # ' ' U+2008 Punctuation Space; ' ' U+2009 Thin; ' ' U+200A Hair Space;
371
+ # ' ' U+202F: Narrow No-Break Space (NNBSP); ' ' U+205F Medium Mathematical Space;
372
+ # '␠' U+2420 symbol for space; '␣' U+2423 Open Box; ' ' U+3000: Ideographic Space
369
373
  (chr(127), '␡'), # U+2421: DELETE SYMBOL
370
374
  # ('_', '𛲖'), # U+1BC96: Duployan Affix Low Line; '_' U+FF3F Fullwidth Low Line
371
375
  )
@@ -401,10 +405,11 @@ def defuse(value: str) -> str:
401
405
 
402
406
  the ASCII character range 0..31 gets converted to the Unicode range U+2400 + ord(char): 0==U+2400 ... 31==U+241F.
403
407
 
404
- in *nix only / and \0 are not allowed characters in file names.
408
+ in most unix variants only the slash and the ASCII 0 characters are not allowed in file names.
405
409
 
406
- in MS Windows are not allowed: ASCII 0...31): / | \\ : * ? ” % < > ( ). some blogs recommend to also not allow
410
+ in MS Windows are not allowed: ASCII 0..31 / | \\ : * ? ” % < > ( ). some blogs recommend to also not allow
407
411
  (convert) the characters # and '.
412
+
408
413
  only old POSIX seems to be even more restricted (only allowing alphanumeric characters plus . - and _).
409
414
 
410
415
  more on allowed characters in file names in the answers of RedGrittyBrick on https://superuser.com/questions/358855
@@ -412,7 +417,7 @@ def defuse(value: str) -> str:
412
417
 
413
418
  file name length is not restricted/shortened by this function, although the maximum is 255 characters on most OSs.
414
419
 
415
- .. hint:: use :func:`dedefuse` to convert the defused string back to the corresponding URI/file-path.
420
+ .. hint:: use the :func:`dedefuse` function to convert the defused string back to the corresponding URI/file-path.
416
421
 
417
422
  """
418
423
  defused = ""
@@ -659,7 +664,7 @@ def module_file_path(local_object: Optional[Callable] = None) -> str:
659
664
  def module_name(*skip_modules: str, depth: int = 0) -> Optional[str]:
660
665
  """ find the first module in the call stack that is *not* in :paramref:`~module_name.skip_modules`.
661
666
 
662
- :param skip_modules: module names to skip (def=this ae.core module).
667
+ :param skip_modules: module names to skip (def=this and other core modules, see :data:`SKIPPED_MODULES`).
663
668
  :param depth: the calling level from which on to search. the default value 0 refers the frame and
664
669
  the module of the caller of this function.
665
670
  pass 1 or an even higher value if you want to get the module name of a function/method
@@ -847,12 +852,11 @@ def parse_dotenv(file_path: str) -> Dict[str, str]:
847
852
  delimiter = None
848
853
  if delimiter != "'":
849
854
  for parts in _env_variable.findall(var_val):
850
- if parts[0] == '\\':
851
- replace = "".join(parts[1:-1]) # don't replace escaped variables
852
- else:
853
- # substitute variables in a value, replace it with the value from the environment
854
- replace = env_vars.get(parts[-1], os.environ.get(parts[-1], ""))
855
- var_val = var_val.replace("".join(parts[0:-1]), replace)
855
+ # substitute env variables in a value with its value, if declared and not escaped
856
+ if parts[0] == '\\' or (replace := env_vars.get(parts[-1], os.environ.get(parts[-1], UNSET))) is UNSET:
857
+ replace = "".join(parts[1:-1]) # don't replace escaped/undeclared vars to prevent value cut at '$'
858
+
859
+ var_val = var_val.replace("".join(parts[0:-1]), cast(str, replace))
856
860
 
857
861
  env_vars[var_nam] = var_val
858
862
 
@@ -897,8 +901,8 @@ def read_file(file_path: str, extra_mode: str = "", encoding: Optional[str] = No
897
901
  read the content of a binary file returned as bytes array. in binary mode the argument
898
902
  passed in :paramref:`~read_file.error_handling` will be ignored.
899
903
  :param encoding: encoding used to load and convert/interpret the file content.
900
- :param error_handling: for files opened in text mode pass `'strict'` or `None` to return `None` (instead of an
901
- empty string) for the cases where either a decoding `ValueError` exception or any
904
+ :param error_handling: for files opened in text mode pass `'strict'` or ``None`` to return ``None`` (instead of
905
+ an empty string) for the cases where either a decoding `ValueError` exception or any
902
906
  `OSError`, `FileNotFoundError` or `PermissionError` exception got raised.
903
907
  the default value `'ignore'` will ignore any decoding errors (missing some characters)
904
908
  and will return an empty string on any file/os exception. this parameter will be ignored
@@ -1092,7 +1096,8 @@ def utc_datetime() -> datetime.datetime:
1092
1096
  return datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
1093
1097
 
1094
1098
 
1095
- def write_file(file_path: str, content: Union[str, bytes], extra_mode: str = "", encoding: Optional[str] = None):
1099
+ def write_file(file_path: str, content: Union[str, bytes],
1100
+ extra_mode: str = "", encoding: Optional[str] = None, make_dirs: bool = False):
1096
1101
  """ (over)write the file specified by :paramref:`~write_file.file_path` with text or binary/bytes content.
1097
1102
 
1098
1103
  :param file_path: file path/name to write the passed content into (overwriting any previous content!).
@@ -1105,21 +1110,26 @@ def write_file(file_path: str, content: Union[str, bytes], extra_mode: str = "",
1105
1110
  be automatically added to the `mode` argument of :func:`open` (if not already specified
1106
1111
  in this argument).
1107
1112
  :param encoding: encoding used to write/convert/interpret the file content to write.
1113
+ :param make_dirs: pass True to automatically create not existing folders specified in
1114
+ :paramref:`~write_file.file_path`.
1108
1115
  :raises FileExistsError: if file exists already and is write-protected.
1109
1116
  :raises FileNotFoundError: if parts of the file path do not exist.
1110
1117
  :raises OSError: if :paramref:`~write_file.file_path` is misspelled or contains invalid characters.
1111
1118
  :raises PermissionError: if current OS user account lacks permissions to read the file content.
1112
1119
  :raises ValueError: on decoding errors.
1113
1120
 
1114
- to extend this function for Android 14+ see https://github.com/beeware/toga/pull/1158#issuecomment-2254564657
1115
- and https://gist.github.com/neonankiti/05922cf0a44108a2e2732671ed9ef386
1121
+ to extend this function for Android 14+ see `<https://github.com/beeware/toga/pull/1158#issuecomment-2254564657>`__
1122
+ and `<https://gist.github.com/neonankiti/05922cf0a44108a2e2732671ed9ef386>`__
1116
1123
  Yes, to use ACTION_CREATE_DOCUMENT, you don't supply a URI in the intent. You wait for the intent result, and that
1117
1124
  will contain a URI which you can write to.
1118
- See #1158 (comment - https://github.com/beeware/toga/pull/1158#issuecomment-2254564657) for a link to a Java
1119
- example, and #1158 (comment - https://github.com/beeware/toga/pull/1158#issuecomment-1446196973) for how to wait
1120
- for an intent result.
1121
- Related german docs: https://developer.android.com/training/data-storage/shared/media?hl=de
1125
+ See #1158 (comment - `<https://github.com/beeware/toga/pull/1158#issuecomment-2254564657>`__) for a link to a Java
1126
+ example, and #1158 (comment - `<https://github.com/beeware/toga/pull/1158#issuecomment-1446196973>`__) for how to
1127
+ wait for an intent result.
1128
+ Related german docs: `<https://developer.android.com/training/data-storage/shared/media?hl=de>`__
1122
1129
  """
1130
+ if make_dirs and (dir_path := os_path_dirname(file_path)):
1131
+ os.makedirs(dir_path, exist_ok=True)
1132
+
1123
1133
  if isinstance(content, bytes) and 'b' not in extra_mode:
1124
1134
  extra_mode += 'b'
1125
1135
 
@@ -1131,9 +1141,33 @@ def write_file(file_path: str, content: Union[str, bytes], extra_mode: str = "",
1131
1141
 
1132
1142
 
1133
1143
  class ErrorMsgMixin:
1134
- """ mixin class providing error message """
1144
+ """ mixin class providing sophisticated error message handling. """
1135
1145
  _err_msg: str = ""
1136
1146
 
1147
+ cae = None
1148
+ po = print
1149
+ dpo = print
1150
+ vpo = print
1151
+
1152
+ def __init__(self):
1153
+ try:
1154
+ from ae.core import main_app_instance # type: ignore
1155
+
1156
+ self.cae = cae = main_app_instance()
1157
+ assert cae is not None, f"{self.__class__.__name__}.__init__() called too early; main app instance not"
1158
+
1159
+ self.po = cae.po
1160
+ self.dpo = cae.dpo
1161
+ self.vpo = cae.vpo
1162
+
1163
+ except (ImportError, AssertionError, Exception) as exc:
1164
+ print(f"{self.__class__.__name__}.__init__() raised {exc}; using print() instead of main app error loggers")
1165
+
1166
+ # self.cae = None
1167
+ # self.po = print
1168
+ # self.dpo = print
1169
+ # self.vpo = print
1170
+
1137
1171
  @property
1138
1172
  def error_message(self) -> str:
1139
1173
  """ error message string if an error occurred or an empty string if not.
@@ -1147,14 +1181,19 @@ class ErrorMsgMixin:
1147
1181
  @error_message.setter
1148
1182
  def error_message(self, next_err_msg: str):
1149
1183
  if next_err_msg:
1184
+ if "WARNING" in next_err_msg.upper():
1185
+ self.vpo(f" .::. {next_err_msg}")
1186
+ else:
1187
+ self.dpo(f" .::. {next_err_msg}")
1150
1188
  self._err_msg += ("\n\n" if self._err_msg else "") + next_err_msg
1151
1189
  else:
1152
1190
  self._err_msg = ""
1153
1191
 
1154
1192
 
1155
- PACKAGE_NAME = stack_var('__name__') or 'unspecified_package'
1156
- PACKAGE_DOMAIN = 'org.test'
1157
- PERMISSIONS = "INTERNET, VIBRATE, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE"
1193
+ # package and permissions handling defaults for all other platforms and frameworks
1194
+ PACKAGE_NAME = stack_var('__name__') or 'unspecified_package' #: package name default
1195
+ PACKAGE_DOMAIN = 'org.test' #: package domain default
1196
+ PERMISSIONS = "INTERNET, VIBRATE, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE" #: permissions default
1158
1197
  if os_path_isfile(BUILD_CONFIG_FILE): # pragma: no cover
1159
1198
  PACKAGE_NAME, PACKAGE_DOMAIN, PERMISSIONS = build_config_variable_values(
1160
1199
  ('package.name', PACKAGE_NAME),
@@ -1170,8 +1209,8 @@ elif os_platform == 'android': # pragma: no cov
1170
1209
 
1171
1210
  if os_platform == 'android': # pragma: no cover
1172
1211
  # monkey patch the :func:`shutil.copystat` and :func:`shutil.copymode` helper functions, which are crashing on
1173
- # 'android' (see # https://bugs.python.org/issue28141 and https://bugs.python.org/issue32073). these functions are
1174
- # used by shutil.copy2/copy/copytree/move to copy OS-specific file attributes.
1212
+ # 'android' (see # `<https://bugs.python.org/issue28141>`__ and `<https://bugs.python.org/issue32073>`__). these
1213
+ # functions are used by shutil.copy2/copy/copytree/move to copy OS-specific file attributes.
1175
1214
  # although shutil.copytree() and shutil.move() are copying/moving the files correctly when the copy_function
1176
1215
  # arg is set to :func:`shutil.copyfile`, they will finally also crash afterward when they try to set the attributes
1177
1216
  # on the destination root directory.
@@ -1203,8 +1242,8 @@ if os_platform == 'android': # pragma: no cov
1203
1242
  :param service_arg: string value to be assigned to environment variable PYTHON_SERVICE_ARGUMENT on start.
1204
1243
  :return: service instance.
1205
1244
 
1206
- see https://github.com/tshirtman/kivy_service_osc/blob/master/src/main.py
1207
- and https://python-for-android.readthedocs.io/en/latest/services/#arbitrary-scripts-services
1245
+ see `<https://github.com/tshirtman/kivy_service_osc/blob/master/src/main.py>`__
1246
+ and `<https://python-for-android.readthedocs.io/en/latest/services/#arbitrary-scripts-services>`__
1208
1247
  """
1209
1248
  service_instance = autoclass(f"{PACKAGE_DOMAIN}.{PACKAGE_NAME}.Service{PACKAGE_NAME.capitalize()}")
1210
1249
  activity = autoclass('org.kivy.android.PythonActivity').mActivity
@@ -1,4 +1,4 @@
1
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_project V0.3.31 -->
1
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_project V0.3.32 -->
2
2
  ### GNU GENERAL PUBLIC LICENSE
3
3
 
4
4
  Version 3, 29 June 2007
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ae_base
3
- Version: 0.3.44
3
+ Version: 0.3.46
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
7
7
  Author-email: aecker2@gmail.com
8
8
  License: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
9
+ Project-URL: Bug Tracker, https://gitlab.com/ae-group/ae_base/-/issues
9
10
  Project-URL: Documentation, https://ae.readthedocs.io/en/latest/_autosummary/ae.base.html
10
11
  Project-URL: Repository, https://gitlab.com/ae-group/ae_base
11
12
  Project-URL: Source, https://ae.readthedocs.io/en/latest/_modules/ae/base.html
@@ -22,11 +23,11 @@ Requires-Python: >=3.9
22
23
  Description-Content-Type: text/markdown
23
24
  License-File: LICENSE.md
24
25
  Provides-Extra: dev
25
- Requires-Dist: aedev-tpl-project; extra == "dev"
26
- Requires-Dist: ae-ae; extra == "dev"
26
+ Requires-Dist: aedev_tpl_project; extra == "dev"
27
+ Requires-Dist: ae_ae; extra == "dev"
27
28
  Requires-Dist: anybadge; extra == "dev"
28
29
  Requires-Dist: coverage-badge; extra == "dev"
29
- Requires-Dist: aedev-git-repo-manager; extra == "dev"
30
+ Requires-Dist: aedev_git_repo_manager; extra == "dev"
30
31
  Requires-Dist: flake8; extra == "dev"
31
32
  Requires-Dist: mypy; extra == "dev"
32
33
  Requires-Dist: pylint; extra == "dev"
@@ -41,7 +42,7 @@ Provides-Extra: docs
41
42
  Provides-Extra: tests
42
43
  Requires-Dist: anybadge; extra == "tests"
43
44
  Requires-Dist: coverage-badge; extra == "tests"
44
- Requires-Dist: aedev-git-repo-manager; extra == "tests"
45
+ Requires-Dist: aedev_git_repo_manager; extra == "tests"
45
46
  Requires-Dist: flake8; extra == "tests"
46
47
  Requires-Dist: mypy; extra == "tests"
47
48
  Requires-Dist: pylint; extra == "tests"
@@ -53,19 +54,19 @@ Requires-Dist: types-setuptools; extra == "tests"
53
54
  Requires-Dist: wheel; extra == "tests"
54
55
  Requires-Dist: twine; extra == "tests"
55
56
 
56
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.94 -->
57
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.95 -->
57
58
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->
58
- # base 0.3.44
59
+ # base 0.3.46
59
60
 
60
61
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](
61
62
  https://gitlab.com/ae-group/ae_base)
62
63
  [![LatestPyPIrelease](
63
- https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.43?logo=python)](
64
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.43)
64
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.45?logo=python)](
65
+ https://gitlab.com/ae-group/ae_base/-/tree/release0.3.45)
65
66
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](
66
67
  https://pypi.org/project/ae-base/#history)
67
68
 
68
- >ae_base module 0.3.44.
69
+ >ae_base module 0.3.46.
69
70
 
70
71
  [![Coverage](https://ae-group.gitlab.io/ae_base/coverage.svg)](
71
72
  https://ae-group.gitlab.io/ae_base/coverage/index.html)
@@ -0,0 +1,7 @@
1
+ ae/base.py,sha256=Hx4PBK--rmdM7lclaq93bTTvP6fbtyZDu7juT4DkHRQ,62973
2
+ ae_base-0.3.46.dist-info/LICENSE.md,sha256=uoIIfORuk4V8ZeNh6SN0EUhiU79RC-indIMFqePKVhY,35002
3
+ ae_base-0.3.46.dist-info/METADATA,sha256=ChOaoCeYPuX4vTx6k8W8odqE5RAPGmbwqxtDVWJfDsQ,5382
4
+ ae_base-0.3.46.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
5
+ ae_base-0.3.46.dist-info/top_level.txt,sha256=vUdgAslSmhZLXWU48fm8AG2BjVnkOWLco8rzuW-5zY0,3
6
+ ae_base-0.3.46.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
7
+ ae_base-0.3.46.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,7 +0,0 @@
1
- ae/base.py,sha256=QByzHC7yJb-vSrTfX0C1U5AQsQK0J105ZiclDnJTMzs,60890
2
- ae_base-0.3.44.dist-info/LICENSE.md,sha256=eHVr16LWo8bsm2NbdFOBcQp-F_3MUXo9I922sABpsMQ,35002
3
- ae_base-0.3.44.dist-info/METADATA,sha256=x5tlK4rJO-YdGoCtz1OyaELmV0k4CqBt3UHiZdo9TEQ,5311
4
- ae_base-0.3.44.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
5
- ae_base-0.3.44.dist-info/top_level.txt,sha256=vUdgAslSmhZLXWU48fm8AG2BjVnkOWLco8rzuW-5zY0,3
6
- ae_base-0.3.44.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
7
- ae_base-0.3.44.dist-info/RECORD,,