ae-base 0.3.56__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.56
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.56
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.55?logo=python)](
78
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.55)
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.56.
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.56
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.55?logo=python)](
9
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.55)
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.56.
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)
@@ -168,10 +168,10 @@ from contextlib import contextmanager
168
168
  from importlib.machinery import ModuleSpec
169
169
  from inspect import getinnerframes, getouterframes, getsourcefile
170
170
  from types import ModuleType
171
- from typing import Any, Callable, Generator, Iterable, Optional, Union, cast
171
+ from typing import Any, Callable, Generator, Iterable, MutableMapping, Optional, Union, cast
172
172
 
173
173
 
174
- __version__ = '0.3.56'
174
+ __version__ = '0.3.57'
175
175
 
176
176
 
177
177
  os_path_abspath = os.path.abspath
@@ -633,24 +633,24 @@ def load_dotenvs():
633
633
 
634
634
  .. hint:: call from the main module of project/app in order to also load ``.env`` files in/above the project folder.
635
635
  """
636
- load_env_var_defaults(os.getcwd())
636
+ env_vars = os.environ
637
+ load_env_var_defaults(os.getcwd(), env_vars)
637
638
  if file_name := stack_var('__file__'):
638
- 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)
639
640
 
640
641
 
641
- def load_env_var_defaults(start_dir: str):
642
- """ 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.
643
644
 
644
- :param start_dir: folder to start search of an ``.env`` file, if not found, then checks the parent folder.
645
- if the first ``.env `` file got found, then load their shell environment variables
646
- 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
647
649
  further ``.env`` files in the parent folder to load them too, until either detecting
648
650
  a folder without an ``.env`` file or until an ``.env`` got loaded from the root folder.
649
-
650
- .. note::
651
- only variables that are not declared in :data:`os.environ` will be added (with the
652
- value specified in the ``.env`` file to be loaded). the variable values declared in the subfolders
653
- 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.
654
654
  """
655
655
  file_path = os_path_abspath(os_path_join(start_dir, DOTENV_FILE_NAME))
656
656
  if not os_path_isfile(file_path):
@@ -658,8 +658,8 @@ def load_env_var_defaults(start_dir: str):
658
658
 
659
659
  while os_path_isfile(file_path):
660
660
  for var_nam, var_val in parse_dotenv(file_path).items():
661
- if var_nam not in os.environ:
662
- os.environ[var_nam] = var_val
661
+ if var_nam not in env_vars:
662
+ env_vars[var_nam] = var_val
663
663
 
664
664
  if os.sep not in file_path:
665
665
  break # pragma: no cover # prevent endless-loop for ``.env`` file in root dir (os.sep == '/')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ae_base
3
- Version: 0.3.56
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.56
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.55?logo=python)](
78
- https://gitlab.com/ae-group/ae_base/-/tree/release0.3.55)
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.56.
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
@@ -489,43 +489,64 @@ class TestBaseHelpers:
489
489
  load_dotenvs()
490
490
  assert env_var_name not in os.environ
491
491
 
492
- 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):
493
514
  assert env_var_name not in os.environ
494
515
 
495
- load_env_var_defaults('/')
516
+ load_env_var_defaults('/', os.environ)
496
517
  assert env_var_name not in os.environ
497
518
 
498
- load_env_var_defaults('.')
519
+ load_env_var_defaults('.', os.environ)
499
520
  assert env_var_name not in os.environ
500
521
 
501
- 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)
502
523
  assert env_var_name not in os.environ
503
524
 
504
- 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
505
526
  assert env_var_name not in os.environ
506
527
 
507
528
  def test_load_env_var_defaults_load_start_parent_first_no_chain(self, os_env_test_env):
508
- 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)
509
530
  assert env_var_name in os.environ
510
531
  assert os.environ[env_var_name] == env_var_val + '3'
511
532
 
512
533
  def test_load_env_var_defaults_load_start_first_no_chain(self, os_env_test_env):
513
- 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)
514
535
  assert env_var_name in os.environ
515
536
  assert os.environ[env_var_name] == env_var_val + '3'
516
537
 
517
538
  def test_load_env_var_defaults_load_start_parent_first_in_chain(self, os_env_test_env):
518
- 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)
519
540
  assert env_var_name in os.environ
520
541
  assert os.environ[env_var_name] == env_var_val + '1'
521
542
 
522
543
  def test_load_env_var_defaults_load_start_no_parent_first_in_chain(self, os_env_test_env):
523
- 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)
524
545
  assert env_var_name in os.environ
525
546
  assert os.environ[env_var_name] == env_var_val + '1'
526
547
 
527
548
  def test_load_env_var_defaults_load_start_on_second_within_chain(self, os_env_test_env):
528
- 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)
529
550
  assert env_var_name in os.environ
530
551
  assert os.environ[env_var_name] == env_var_val + '0'
531
552
 
@@ -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)
ae_base-0.3.56/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