ae-base 0.3.55__tar.gz → 0.3.57__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,4 +1,4 @@
1
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_project V0.3.32 -->
1
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_project V0.3.35 -->
2
2
  ### GNU GENERAL PUBLIC LICENSE
3
3
 
4
4
  Version 3, 29 June 2007
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ae_base
3
- Version: 0.3.55
3
+ Version: 0.3.57
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
@@ -67,19 +67,19 @@ Dynamic: provides-extra
67
67
  Dynamic: requires-python
68
68
  Dynamic: summary
69
69
 
70
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.95 -->
70
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.96 -->
71
71
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->
72
- # base 0.3.55
72
+ # base 0.3.57
73
73
 
74
74
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](
75
75
  https://gitlab.com/ae-group/ae_base)
76
76
  [![LatestPyPIrelease](
77
- https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.54?logo=python)](
78
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.54)
77
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.56?logo=python)](
78
+ https://gitlab.com/ae-group/ae_base/-/tree/release0.3.56)
79
79
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](
80
80
  https://pypi.org/project/ae-base/#history)
81
81
 
82
- >ae_base module 0.3.55.
82
+ >ae namespace module portion base: basic constants, helper functions and context manager.
83
83
 
84
84
  [![Coverage](https://ae-group.gitlab.io/ae_base/coverage.svg)](
85
85
  https://ae-group.gitlab.io/ae_base/coverage/index.html)
@@ -1,16 +1,16 @@
1
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.95 -->
1
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.96 -->
2
2
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->
3
- # base 0.3.55
3
+ # base 0.3.57
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.54?logo=python)](
9
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.54)
8
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.56?logo=python)](
9
+ https://gitlab.com/ae-group/ae_base/-/tree/release0.3.56)
10
10
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](
11
11
  https://pypi.org/project/ae-base/#history)
12
12
 
13
- >ae_base module 0.3.55.
13
+ >ae namespace module portion base: basic constants, helper functions and context manager.
14
14
 
15
15
  [![Coverage](https://ae-group.gitlab.io/ae_base/coverage.svg)](
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
+ most programming languages providing a function to determine the sign of a number. the :func:`sign` functino,
36
+ provided by this module/portion is filling this gap in Python.
37
+
35
38
  in order to convert and transfer Unicode character outside the 7-bit ASCII range via internet transport protocols,
36
39
  like http, use the helper functions :func:`ascii_str` and :func:`str_ascii`.
37
40
 
@@ -165,10 +168,10 @@ from contextlib import contextmanager
165
168
  from importlib.machinery import ModuleSpec
166
169
  from inspect import getinnerframes, getouterframes, getsourcefile
167
170
  from types import ModuleType
168
- from typing import Any, Callable, Generator, Iterable, Optional, Union, cast
171
+ from typing import Any, Callable, Generator, Iterable, MutableMapping, Optional, Union, cast
169
172
 
170
173
 
171
- __version__ = '0.3.55'
174
+ __version__ = '0.3.57'
172
175
 
173
176
 
174
177
  os_path_abspath = os.path.abspath
@@ -630,24 +633,24 @@ def load_dotenvs():
630
633
 
631
634
  .. hint:: call from the main module of project/app in order to also load ``.env`` files in/above the project folder.
632
635
  """
633
- load_env_var_defaults(os.getcwd())
636
+ env_vars = os.environ
637
+ load_env_var_defaults(os.getcwd(), env_vars)
634
638
  if file_name := stack_var('__file__'):
635
- load_env_var_defaults(os_path_dirname(os_path_abspath(file_name)))
639
+ load_env_var_defaults(os_path_dirname(os_path_abspath(file_name)), env_vars)
636
640
 
637
641
 
638
- def load_env_var_defaults(start_dir: str):
639
- """ detect and load a chain of ``.env`` files starting in the specified folder or one above.
642
+ def load_env_var_defaults(start_dir: str, env_vars: MutableMapping[str, str]):
643
+ """ load undeclared env var defaults from a chain of ``.env`` files starting in the specified folder or its parent.
640
644
 
641
- :param start_dir: folder to start search of an ``.env`` file, if not found, then checks the parent folder.
642
- if the first ``.env `` file got found, then load their shell environment variables
643
- into Python's :data:`os.environ`. after loading the first one, it repeats to check for
645
+ :param start_dir: folder to start search of an ``.env`` file, if not found, then also checks the parent
646
+ folder. if an ``.env `` file got found, then put their shell environment variable values
647
+ into the specified :paramref:`~load_env_var_defaults.env_vars` mapping if they are not
648
+ already there. after processing the first ``.env`` file, it repeats to check for
644
649
  further ``.env`` files in the parent folder to load them too, until either detecting
645
650
  a folder without an ``.env`` file or until an ``.env`` got loaded from the root folder.
646
-
647
- .. note::
648
- only variables that are not declared in :data:`os.environ` will be added (with the
649
- value specified in the ``.env`` file to be loaded). the variable values declared in the subfolders
650
- are having preference over the values declared in the parent folders.
651
+ :param env_vars: environment variables mapping to be amended with env variable values from any
652
+ found ``.env`` file. pass Python's :data:`os.environ` to amend this mapping directly
653
+ with all the already not declared environment variables.
651
654
  """
652
655
  file_path = os_path_abspath(os_path_join(start_dir, DOTENV_FILE_NAME))
653
656
  if not os_path_isfile(file_path):
@@ -655,8 +658,8 @@ def load_env_var_defaults(start_dir: str):
655
658
 
656
659
  while os_path_isfile(file_path):
657
660
  for var_nam, var_val in parse_dotenv(file_path).items():
658
- if var_nam not in os.environ:
659
- os.environ[var_nam] = var_val
661
+ if var_nam not in env_vars:
662
+ env_vars[var_nam] = var_val
660
663
 
661
664
  if os.sep not in file_path:
662
665
  break # pragma: no cover # prevent endless-loop for ``.env`` file in root dir (os.sep == '/')
@@ -1018,6 +1021,15 @@ def round_traditional(num_value: float, num_digits: int = 0) -> float:
1018
1021
  return round(num_value + 10 ** (-len(str(num_value)) - 1), num_digits)
1019
1022
 
1020
1023
 
1024
+ def sign(number: float) -> int:
1025
+ """ return ths sign (-1, 0, 1) of a number.
1026
+
1027
+ :param number: any number of type float or int.
1028
+ :return: -1 if the number is negative, 0 if it is zero, or 1 if it is positive.
1029
+ """
1030
+ return (number > 0) - (number < 0)
1031
+
1032
+
1021
1033
  def snake_to_camel(name: str, back_convertible: bool = False) -> str:
1022
1034
  """ convert name from snake_case to CamelCase.
1023
1035
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ae_base
3
- Version: 0.3.55
3
+ Version: 0.3.57
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
@@ -67,19 +67,19 @@ Dynamic: provides-extra
67
67
  Dynamic: requires-python
68
68
  Dynamic: summary
69
69
 
70
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.95 -->
70
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.96 -->
71
71
  <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->
72
- # base 0.3.55
72
+ # base 0.3.57
73
73
 
74
74
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](
75
75
  https://gitlab.com/ae-group/ae_base)
76
76
  [![LatestPyPIrelease](
77
- https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.54?logo=python)](
78
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.54)
77
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.56?logo=python)](
78
+ https://gitlab.com/ae-group/ae_base/-/tree/release0.3.56)
79
79
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](
80
80
  https://pypi.org/project/ae-base/#history)
81
81
 
82
- >ae_base module 0.3.55.
82
+ >ae namespace module portion base: basic constants, helper functions and context manager.
83
83
 
84
84
  [![Coverage](https://ae-group.gitlab.io/ae_base/coverage.svg)](
85
85
  https://ae-group.gitlab.io/ae_base/coverage/index.html)
@@ -0,0 +1,33 @@
1
+ # THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_project V0.3.35
2
+ """ setup of ae namespace module portion base: basic constants, helper functions and context manager. """
3
+
4
+
5
+
6
+ # noinspection PyUnresolvedReferences
7
+ import setuptools
8
+
9
+ setup_kwargs = {
10
+ 'author': 'AndiEcker',
11
+ 'author_email': 'aecker2@gmail.com',
12
+ 'classifiers': ['Development Status :: 3 - Alpha', 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.9', 'Topic :: Software Development :: Libraries :: Python Modules'],
13
+ 'description': 'ae namespace module portion base: basic constants, helper functions and context manager',
14
+ 'extras_require': {'dev': ['aedev_tpl_project', 'ae_ae', 'anybadge', 'coverage-badge', 'aedev_git_repo_manager', 'flake8', 'mypy', 'pylint', 'pytest', 'pytest-cov', 'pytest-django', 'typing', 'types-setuptools', 'wheel', 'twine'], 'docs': [], 'tests': ['anybadge', 'coverage-badge', 'aedev_git_repo_manager', 'flake8', 'mypy', 'pylint', 'pytest', 'pytest-cov', 'pytest-django', 'typing', 'types-setuptools', 'wheel', 'twine']},
15
+ 'install_requires': [],
16
+ 'keywords': ['configuration', 'development', 'environment', 'productivity'],
17
+ 'license': 'OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
18
+ 'long_description': '<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae V0.3.96 -->\n<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_namespace_root V0.3.14 -->\n# base 0.3.57\n\n[![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_base/develop?logo=python)](\n https://gitlab.com/ae-group/ae_base)\n[![LatestPyPIrelease](\n https://img.shields.io/gitlab/pipeline/ae-group/ae_base/release0.3.56?logo=python)](\n https://gitlab.com/ae-group/ae_base/-/tree/release0.3.56)\n[![PyPIVersions](https://img.shields.io/pypi/v/ae_base)](\n https://pypi.org/project/ae-base/#history)\n\n>ae namespace module portion base: basic constants, helper functions and context manager.\n\n[![Coverage](https://ae-group.gitlab.io/ae_base/coverage.svg)](\n https://ae-group.gitlab.io/ae_base/coverage/index.html)\n[![MyPyPrecision](https://ae-group.gitlab.io/ae_base/mypy.svg)](\n https://ae-group.gitlab.io/ae_base/lineprecision.txt)\n[![PyLintScore](https://ae-group.gitlab.io/ae_base/pylint.svg)](\n https://ae-group.gitlab.io/ae_base/pylint.log)\n\n[![PyPIImplementation](https://img.shields.io/pypi/implementation/ae_base)](\n https://gitlab.com/ae-group/ae_base/)\n[![PyPIPyVersions](https://img.shields.io/pypi/pyversions/ae_base)](\n https://gitlab.com/ae-group/ae_base/)\n[![PyPIWheel](https://img.shields.io/pypi/wheel/ae_base)](\n https://gitlab.com/ae-group/ae_base/)\n[![PyPIFormat](https://img.shields.io/pypi/format/ae_base)](\n https://pypi.org/project/ae-base/)\n[![PyPILicense](https://img.shields.io/pypi/l/ae_base)](\n https://gitlab.com/ae-group/ae_base/-/blob/develop/LICENSE.md)\n[![PyPIStatus](https://img.shields.io/pypi/status/ae_base)](\n https://libraries.io/pypi/ae-base)\n[![PyPIDownloads](https://img.shields.io/pypi/dm/ae_base)](\n https://pypi.org/project/ae-base/#files)\n\n\n## installation\n\n\nexecute the following command to install the\nae.base module\nin the currently active virtual environment:\n \n```shell script\npip install ae-base\n```\n\nif you want to contribute to this portion then first fork\n[the ae_base repository at GitLab](\nhttps://gitlab.com/ae-group/ae_base "ae.base code repository").\nafter that pull it to your machine and finally execute the\nfollowing command in the root folder of this repository\n(ae_base):\n\n```shell script\npip install -e .[dev]\n```\n\nthe last command will install this module portion, along with the tools you need\nto develop and run tests or to extend the portion documentation. to contribute only to the unit tests or to the\ndocumentation of this portion, replace the setup extras key `dev` in the above command with `tests` or `docs`\nrespectively.\n\nmore detailed explanations on how to contribute to this project\n[are available here](\nhttps://gitlab.com/ae-group/ae_base/-/blob/develop/CONTRIBUTING.rst)\n\n\n## namespace portion documentation\n\ninformation on the features and usage of this portion are available at\n[ReadTheDocs](\nhttps://ae.readthedocs.io/en/latest/_autosummary/ae.base.html\n"ae_base documentation").\n',
19
+ 'long_description_content_type': 'text/markdown',
20
+ 'name': 'ae_base',
21
+ 'package_data': {'': []},
22
+ 'packages': ['ae'],
23
+ 'project_urls': {'Bug Tracker': 'https://gitlab.com/ae-group/ae_base/-/issues', 'Documentation': 'https://ae.readthedocs.io/en/latest/_autosummary/ae.base.html', 'Repository': 'https://gitlab.com/ae-group/ae_base', 'Source': 'https://ae.readthedocs.io/en/latest/_modules/ae/base.html'},
24
+ 'python_requires': '>=3.9',
25
+ 'setup_requires': ['aedev_setup_project'],
26
+ 'url': 'https://gitlab.com/ae-group/ae_base',
27
+ 'version': '0.3.57',
28
+ 'zip_safe': True,
29
+ }
30
+
31
+ if __name__ == "__main__":
32
+ setuptools.setup(**setup_kwargs)
33
+ pass
@@ -18,15 +18,15 @@ from typing import cast
18
18
  # noinspection PyProtectedMember
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
- UNSET,
22
- URI_SEP_CHAR, app_name_guess, ascii_str, build_config_variable_values, camel_to_snake,
21
+ UNSET, URI_SEP_CHAR,
22
+ app_name_guess, ascii_str, build_config_variable_values, camel_to_snake,
23
23
  dedefuse, deep_dict_update, defuse, dummy_function, duplicates, env_str,
24
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
- parse_dotenv, project_main_file, read_file, round_traditional, snake_to_camel, stack_frames, stack_var, stack_vars,
29
- str_ascii, sys_env_dict, sys_env_text, to_ascii, utc_datetime, write_file,
28
+ parse_dotenv, project_main_file, read_file, round_traditional, sign, snake_to_camel,
29
+ stack_frames, stack_var, stack_vars, str_ascii, sys_env_dict, sys_env_text, to_ascii, utc_datetime, write_file,
30
30
  ErrorMsgMixin)
31
31
 
32
32
 
@@ -40,6 +40,7 @@ env_var_val = 'value of env var'
40
40
  folder_name = 'fdr'
41
41
  full_folders = (0, 1, 3)
42
42
 
43
+
43
44
  @pytest.fixture
44
45
  def os_env_test_env():
45
46
  """ create .env files to test and backup os.environ. """
@@ -79,7 +80,7 @@ class TestErrorMsgMixin:
79
80
  assert ins.cae is None # in test env is no console/gui app available
80
81
  assert ins.po is ins.dpo is ins.vpo is print
81
82
 
82
- with patch('ae.core.main_app_instance', lambda : None):
83
+ with patch('ae.core.main_app_instance', lambda: None):
83
84
  ins = ErrorMsgMixin()
84
85
  assert ins
85
86
  assert ins.cae is None
@@ -105,7 +106,7 @@ class TestErrorMsgMixin:
105
106
 
106
107
  app_ins = _AppMock()
107
108
 
108
- with patch('ae.core.main_app_instance', lambda : app_ins):
109
+ with patch('ae.core.main_app_instance', lambda: app_ins):
109
110
  ins = ErrorMsgMixin()
110
111
  assert ins.cae is app_ins
111
112
  assert ins.po is not print
@@ -488,43 +489,64 @@ class TestBaseHelpers:
488
489
  load_dotenvs()
489
490
  assert env_var_name not in os.environ
490
491
 
491
- def test_load_env_var_defaults_not_loaded(self, os_env_test_env):
492
+ def test_load_env_var_defaults_errors(self):
493
+ with pytest.raises(TypeError):
494
+ # noinspection PyArgumentList
495
+ load_env_var_defaults()
496
+
497
+ with pytest.raises(TypeError):
498
+ # noinspection PyTypeChecker
499
+ load_env_var_defaults(None, None)
500
+
501
+ # noinspection PyTypeChecker
502
+ load_env_var_defaults("inv:_ file path", ()) # NO ERROR EXCEPTIONS on these invalid arg values!!!
503
+
504
+ def test_load_env_var_defaults_not_loaded(self):
505
+ env_vars = {}
506
+
507
+ load_env_var_defaults('/', env_vars)
508
+ assert env_var_name not in env_vars
509
+
510
+ load_env_var_defaults('.', env_vars)
511
+ assert env_var_name not in env_vars
512
+
513
+ def test_load_env_var_defaults_not_loaded_in_os_environ(self, os_env_test_env):
492
514
  assert env_var_name not in os.environ
493
515
 
494
- load_env_var_defaults('/')
516
+ load_env_var_defaults('/', os.environ)
495
517
  assert env_var_name not in os.environ
496
518
 
497
- load_env_var_defaults('.')
519
+ load_env_var_defaults('.', os.environ)
498
520
  assert env_var_name not in os.environ
499
521
 
500
- load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 5)))
522
+ load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 5)), os.environ)
501
523
  assert env_var_name not in os.environ
502
524
 
503
- load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 6))) # invalid/too-deep path
525
+ load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 6)), os.environ) # too-deep path
504
526
  assert env_var_name not in os.environ
505
527
 
506
528
  def test_load_env_var_defaults_load_start_parent_first_no_chain(self, os_env_test_env):
507
- load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 4)))
529
+ load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 4)), os.environ)
508
530
  assert env_var_name in os.environ
509
531
  assert os.environ[env_var_name] == env_var_val + '3'
510
532
 
511
533
  def test_load_env_var_defaults_load_start_first_no_chain(self, os_env_test_env):
512
- load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 3)))
534
+ load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 3)), os.environ)
513
535
  assert env_var_name in os.environ
514
536
  assert os.environ[env_var_name] == env_var_val + '3'
515
537
 
516
538
  def test_load_env_var_defaults_load_start_parent_first_in_chain(self, os_env_test_env):
517
- load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 2)))
539
+ load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 2)), os.environ)
518
540
  assert env_var_name in os.environ
519
541
  assert os.environ[env_var_name] == env_var_val + '1'
520
542
 
521
543
  def test_load_env_var_defaults_load_start_no_parent_first_in_chain(self, os_env_test_env):
522
- load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 1)))
544
+ load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 1)), os.environ)
523
545
  assert env_var_name in os.environ
524
546
  assert os.environ[env_var_name] == env_var_val + '1'
525
547
 
526
548
  def test_load_env_var_defaults_load_start_on_second_within_chain(self, os_env_test_env):
527
- load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 0)))
549
+ load_env_var_defaults(os.path.join(os_env_test_env, *((folder_name, ) * 0)), os.environ)
528
550
  assert env_var_name in os.environ
529
551
  assert os.environ[env_var_name] == env_var_val + '0'
530
552
 
@@ -559,17 +581,15 @@ class TestBaseHelpers:
559
581
  assert mask_secrets({'_token': "secret"}, fragments=('TOKEN', 'secret')) == {'_token': "secret"}
560
582
 
561
583
  untouched = 'untouched_Pw_d_p_a_s_s_word'
562
- dat = {'key1':
563
- {'subKey1':
564
- (
565
- {'host_Pwd': "secret"},
566
- untouched,
567
- ),
568
- 'passWord___': "secRet",
569
- },
584
+ dat = {'key1': {'subKey1': (
585
+ {'host_Pwd': "secret"},
586
+ untouched,
587
+ ),
588
+ 'passWord___': "secRet",
589
+ },
570
590
  'any_PASSWORD_to_hide': "Se",
571
591
  untouched: untouched,
572
- }
592
+ }
573
593
  assert mask_secrets(dat) is dat
574
594
  assert dat['key1']['subKey1'][0]['host_Pwd'] == "sec*********"
575
595
  assert dat['key1']['passWord___'] == "sec*********"
@@ -634,6 +654,7 @@ class TestBaseHelpers:
634
654
  finally:
635
655
  os.environ.pop('ANDROID_ARGUMENT', None)
636
656
 
657
+ # noinspection PyUnreachableCode
637
658
  try:
638
659
  os.environ['KIVY_BUILD'] = 'android'
639
660
  assert _os_platform() == 'android'
@@ -687,12 +708,20 @@ class TestBaseHelpers:
687
708
  with tempfile.NamedTemporaryFile(mode="w") as fp:
688
709
  fp.write('declaredVar = DeclaredValue\n')
689
710
  fp.write('replacedVar = beforeTheDollar$declaredVar\n')
690
- fp.write('uncutVar = beforeTheDollar$afterTheDollar\n')
711
+ fp.write('uncutVar=beforeTheDollar$afterTheDollar\n')
691
712
  fp.seek(0)
692
713
  loaded = parse_dotenv(fp.name)
693
714
  assert loaded['replacedVar'] == "beforeTheDollarDeclaredValue"
694
715
  assert loaded['uncutVar'] == "beforeTheDollar$afterTheDollar"
695
716
 
717
+ def test_parse_dotenv_double_in_single_value(self):
718
+ with tempfile.NamedTemporaryFile(mode="w") as fp:
719
+ fp.write("""var_nam='"var val"'""")
720
+ fp.seek(0)
721
+ loaded = parse_dotenv(fp.name)
722
+ assert 'var_nam' in loaded
723
+ assert loaded['var_nam'] == '"var val"'
724
+
696
725
  def test_parse_dotenv_double_quoted_value(self):
697
726
  with tempfile.NamedTemporaryFile(mode="w") as fp:
698
727
  fp.write('var_nam="var val"')
@@ -708,6 +737,14 @@ class TestBaseHelpers:
708
737
  loaded = parse_dotenv(fp.name)
709
738
  assert 'var_nam' not in loaded # added warning
710
739
 
740
+ def test_parse_dotenv_single_in_double_quoted_value(self):
741
+ with tempfile.NamedTemporaryFile(mode="w") as fp:
742
+ fp.write('''var_nam="'var val'"''')
743
+ fp.seek(0)
744
+ loaded = parse_dotenv(fp.name)
745
+ assert 'var_nam' in loaded
746
+ assert loaded['var_nam'] == "'var val'"
747
+
711
748
  def test_parse_dotenv_single_value(self):
712
749
  with tempfile.NamedTemporaryFile(mode="w") as fp:
713
750
  fp.write("var_nam='var val'")
@@ -716,6 +753,24 @@ class TestBaseHelpers:
716
753
  assert 'var_nam' in loaded
717
754
  assert loaded['var_nam'] == "var val"
718
755
 
756
+ def test_parse_dotenv_literal_dict_with_list(self):
757
+ with tempfile.NamedTemporaryFile(mode="w") as fp:
758
+ var_val = "{'key': {'sub-key': ['list-item', 'list-item with = char', ]}}"
759
+ fp.write("var_nam=" + var_val)
760
+ fp.seek(0)
761
+ loaded = parse_dotenv(fp.name)
762
+ assert 'var_nam' in loaded
763
+ assert loaded['var_nam'] == var_val
764
+
765
+ def test_parse_dotenv_literal_dict_with_list_quoted(self):
766
+ with tempfile.NamedTemporaryFile(mode="w") as fp:
767
+ var_val = "{'key': {'sub-key': ['list-item', 'list-item with = char']}}"
768
+ fp.write('var_nam="' + var_val + '"')
769
+ fp.seek(0)
770
+ loaded = parse_dotenv(fp.name)
771
+ assert 'var_nam' in loaded
772
+ assert loaded['var_nam'] == var_val
773
+
719
774
  def test_parse_dotenv_start_parent_first_in_chain(self, os_env_test_env):
720
775
  assert env_var_name not in os.environ
721
776
  file_path = os.path.join(os_env_test_env, folder_name, DOTENV_FILE_NAME)
@@ -802,7 +857,7 @@ class TestBaseHelpers:
802
857
 
803
858
  def test_parse_dotenv_var_not_expands_escaped_variables(self):
804
859
  with tempfile.NamedTemporaryFile(mode="w") as fp:
805
- fp.write("var_nam=var val \\$env_var \${env_var}")
860
+ fp.write("var_nam=var val \\$env_var \\${env_var}")
806
861
  fp.seek(0)
807
862
  loaded = parse_dotenv(fp.name)
808
863
  assert 'var_nam' in loaded
@@ -853,6 +908,31 @@ class TestBaseHelpers:
853
908
  assert round_traditional(0.075, 2) == 0.08
854
909
  assert round(0.075, 2) == 0.07
855
910
 
911
+ def test_sign_with_float_arg(self):
912
+ assert sign(1.11) == 1
913
+ assert sign(-0.000003) == -1
914
+ assert sign(0.0000000) == 0
915
+ assert sign(-0.0) == 0
916
+
917
+ def test_sign_with_int_arg(self):
918
+ assert sign(3) == 1
919
+ assert sign(-6) == -1
920
+ assert sign(0) == 0
921
+ assert sign(-0) == 0
922
+
923
+ def test_sign_with_invalid_arg(self):
924
+ with pytest.raises(TypeError):
925
+ # noinspection PyArgumentList
926
+ sign()
927
+
928
+ with pytest.raises(TypeError):
929
+ # noinspection PyArgumentList,PyTypeChecker
930
+ sign(None)
931
+
932
+ with pytest.raises(TypeError):
933
+ # noinspection PyArgumentList,PyTypeChecker
934
+ sign(UNSET)
935
+
856
936
  def test_snake_to_camel(self):
857
937
  assert snake_to_camel("_Any_Camel_Case_Name") == "AnyCamelCaseName"
858
938
  assert snake_to_camel("any_Camel_Case_Name") == "AnyCamelCaseName"
@@ -981,6 +1061,7 @@ class TestModuleHelpers:
981
1061
  os.remove(module_file)
982
1062
 
983
1063
  # test already imported module
1064
+ # noinspection PyUnreachableCode
984
1065
  callee = module_attr('textwrap', attr_name='indent')
985
1066
  assert callable(callee)
986
1067
  assert callee is textwrap.indent
@@ -1033,7 +1114,7 @@ class TestModuleHelpers:
1033
1114
  os.remove(module_file)
1034
1115
 
1035
1116
  def test_module_attr_not_exists_attr(self):
1036
- """ first test with non-existing module, second test with non-existing function. """
1117
+ """ first test with a non-existing module, second test with a non-existing function. """
1037
1118
  namespace = TESTS_FOLDER
1038
1119
  mod_name = 'test_module_name'
1039
1120
  att_name = 'test_module_func'
@@ -1060,7 +1141,7 @@ class TestModuleHelpers:
1060
1141
  os.remove(module_file)
1061
1142
 
1062
1143
  def test_module_attr_not_exists_module(self):
1063
- """ first test with non-existing module, second test with non-existing function. """
1144
+ """ first test with a non-existing module, second test with a non-existing function. """
1064
1145
  mod_name = 'non_existing_test_module_name'
1065
1146
  att_name = 'non_existing_test_module_func'
1066
1147
  assert module_attr(mod_name, attr_name=att_name) is None
@@ -1102,7 +1183,7 @@ class TestStackHelpers:
1102
1183
  for frame in stack_frames():
1103
1184
  assert frame
1104
1185
  assert getattr(frame, 'f_globals')
1105
- # if pytest runs from terminal then f_locals is missing in the highest frame:
1186
+ # if pytest runs from terminal, then f_locals is missing in the highest frame:
1106
1187
  # assert getattr(frame, 'f_locals')
1107
1188
 
1108
1189
  def test_stack_var_module(self):
ae_base-0.3.55/setup.py DELETED
@@ -1,18 +0,0 @@
1
- # THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.tpl_project V0.3.32
2
- """ setup this project with setuptools and aedev.setup_project. """
3
- import pprint
4
- import sys
5
-
6
- import setuptools
7
-
8
- from aedev.setup_project import project_env_vars # type: ignore
9
-
10
- pev = project_env_vars(from_setup=True)
11
-
12
- if __name__ == "__main__":
13
- print("# EXECUTING SETUPTOOLS SETUP: argv, kwargs ###################")
14
- print(pprint.pformat(sys.argv, indent=3, width=75, compact=True))
15
- setup_kwargs = pev['setup_kwargs']
16
- print(pprint.pformat(setup_kwargs, indent=3, width=75, compact=True))
17
- setuptools.setup(**setup_kwargs)
18
- print("# FINISHED SETUPTOOLS SETUP ##################################")
File without changes