dynaconf 3.2.5__tar.gz → 3.2.7__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.
- {dynaconf-3.2.5 → dynaconf-3.2.7}/CHANGELOG.md +23 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/PKG-INFO +9 -31
- dynaconf-3.2.7/dynaconf/VERSION +1 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/base.py +34 -3
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/cli.py +79 -35
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/hooking.py +48 -11
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/__init__.py +73 -36
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/env_loader.py +29 -13
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/ini_loader.py +17 -2
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/json_loader.py +17 -2
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/py_loader.py +10 -2
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/redis_loader.py +9 -2
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/toml_loader.py +17 -3
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/yaml_loader.py +17 -2
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/utils/__init__.py +50 -7
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/utils/boxing.py +7 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/utils/inspect.py +9 -2
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/utils/parse_conf.py +60 -7
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/validator.py +25 -7
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/_termui_impl.py +3 -3
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/core.py +1 -1
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/types.py +1 -1
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/compat.py +1 -1
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/error.py +6 -7
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/events.py +6 -11
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/resolver.py +3 -3
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/scalarstring.py +2 -3
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/tokens.py +18 -19
- dynaconf-3.2.7/dynaconf/vendor/tomllib/_types.py +4 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/tomllib/_writer.py +1 -1
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf.egg-info/PKG-INFO +9 -31
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf.egg-info/SOURCES.txt +0 -24
- dynaconf-3.2.5/dynaconf/VERSION +0 -1
- dynaconf-3.2.5/dynaconf/vendor/tomllib/_types.py +0 -4
- dynaconf-3.2.5/tests/test_base.py +0 -1510
- dynaconf-3.2.5/tests/test_basic.py +0 -7
- dynaconf-3.2.5/tests/test_cli.py +0 -881
- dynaconf-3.2.5/tests/test_compat.py +0 -56
- dynaconf-3.2.5/tests/test_django.py +0 -44
- dynaconf-3.2.5/tests/test_dynabox.py +0 -103
- dynaconf-3.2.5/tests/test_endtoend.py +0 -67
- dynaconf-3.2.5/tests/test_env_loader.py +0 -523
- dynaconf-3.2.5/tests/test_envvar_prefix.py +0 -46
- dynaconf-3.2.5/tests/test_feature_flag.py +0 -34
- dynaconf-3.2.5/tests/test_flask.py +0 -165
- dynaconf-3.2.5/tests/test_hooking.py +0 -268
- dynaconf-3.2.5/tests/test_ini_loader.py +0 -208
- dynaconf-3.2.5/tests/test_inspect.py +0 -823
- dynaconf-3.2.5/tests/test_json_loader.py +0 -230
- dynaconf-3.2.5/tests/test_nested_loading.py +0 -385
- dynaconf-3.2.5/tests/test_py_loader.py +0 -186
- dynaconf-3.2.5/tests/test_redis.py +0 -124
- dynaconf-3.2.5/tests/test_toml_loader.py +0 -256
- dynaconf-3.2.5/tests/test_utils.py +0 -538
- dynaconf-3.2.5/tests/test_validators.py +0 -887
- dynaconf-3.2.5/tests/test_validators_conditions.py +0 -64
- dynaconf-3.2.5/tests/test_vault.py +0 -131
- dynaconf-3.2.5/tests/test_yaml_loader.py +0 -580
- {dynaconf-3.2.5 → dynaconf-3.2.7}/3.x-release-notes.md +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/CONTRIBUTING.md +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/CONTRIBUTORS.md +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/LICENSE +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/MANIFEST.in +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/README.md +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/constants.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/contrib/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/contrib/django_dynaconf_v2.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/contrib/flask_dynaconf.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/default_settings.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/base.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/loaders/vault_loader.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/strategies/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/strategies/filtering.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/test_settings.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/utils/files.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/utils/functional.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/validator_conditions.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/box/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/box/box.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/box/box_list.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/box/config_box.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/box/converters.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/box/exceptions.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/box/from_file.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/box/shorthand_box.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/_bashcomplete.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/_compat.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/_textwrap.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/_unicodefun.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/_winconsole.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/decorators.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/exceptions.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/formatting.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/globals.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/parser.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/termui.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/testing.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/click/utils.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/dotenv/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/dotenv/cli.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/dotenv/compat.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/dotenv/ipython.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/dotenv/main.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/dotenv/parser.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/dotenv/version.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/anchor.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/comments.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/composer.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/configobjwalker.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/constructor.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/cyaml.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/dumper.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/emitter.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/loader.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/main.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/nodes.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/parser.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/reader.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/representer.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/scalarbool.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/scalarfloat.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/scalarint.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/scanner.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/serializer.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/setup.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/timestamp.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/ruamel/yaml/util.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/toml/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/toml/decoder.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/toml/encoder.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/toml/ordered.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/toml/tz.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/tomllib/__init__.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/tomllib/_parser.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf/vendor/tomllib/_re.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf.egg-info/dependency_links.txt +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf.egg-info/entry_points.txt +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf.egg-info/not-zip-safe +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf.egg-info/requires.txt +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/dynaconf.egg-info/top_level.txt +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/setup.cfg +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/setup.py +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/vendor_licenses/box-LICENSE.txt +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/vendor_licenses/click-LICENSE.rst +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/vendor_licenses/licenses.sh +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/vendor_licenses/python-dotenv-LICENSE.txt +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/vendor_licenses/ruamel.yaml-LICENSE.txt +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/vendor_licenses/toml-LICENSE.txt +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/vendor_licenses/tomli-LICENSE.txt +0 -0
- {dynaconf-3.2.5 → dynaconf-3.2.7}/vendor_licenses/vendor_versions.txt +0 -0
|
@@ -2,6 +2,29 @@ Changelog
|
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
4
|
<!-- insertion marker -->
|
|
5
|
+
## [3.2.7](https://github.com/dynaconf/dynaconf/releases/tag/3.2.7) - 2025-01-21
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- lazy validator's default value would evaluate early (#1198). *By Pedro Brochado*.
|
|
10
|
+
- Fixed an error that would raise when using get_history() with lazy values (#1184) (#1185). *By Pedro Brochado*.
|
|
11
|
+
- Fixed Redis loader when ENV prefix is `None`.
|
|
12
|
+
- Populate object method now takes `internal` attribute to filter out internal variables.
|
|
13
|
+
- On CLI `json.dumps` defaults to `repr` for types that cannot be serialized.
|
|
14
|
+
- Added an identifier to validator calls of `set` method
|
|
15
|
+
- Fix django app discovery using DJANGO_SETTINGS_MODULE variable
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
- Added `@insert` token to call `list.insert`
|
|
20
|
+
- Allow env loader to load from multiple prefixes
|
|
21
|
+
- Allow multiple composable current environments
|
|
22
|
+
- Track more data on `load_file` method
|
|
23
|
+
- Added `--json` to dynaconf list CLI
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## [3.2.6](https://github.com/dynaconf/dynaconf/releases/tag/3.2.6) - 2024-07-19
|
|
27
|
+
|
|
5
28
|
## [3.2.5](https://github.com/pedro-psb/dynaconf/releases/tag/3.2.5) - 2024-03-18
|
|
6
29
|
|
|
7
30
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dynaconf
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.7
|
|
4
4
|
Summary: The dynamic configurator for your Python Project
|
|
5
5
|
Home-page: https://github.com/dynaconf/dynaconf
|
|
6
6
|
Author: Bruno Rocha
|
|
@@ -26,6 +26,14 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
26
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
27
|
Requires-Python: >=3.8
|
|
28
28
|
Description-Content-Type: text/markdown
|
|
29
|
+
Provides-Extra: redis
|
|
30
|
+
Provides-Extra: vault
|
|
31
|
+
Provides-Extra: yaml
|
|
32
|
+
Provides-Extra: toml
|
|
33
|
+
Provides-Extra: ini
|
|
34
|
+
Provides-Extra: configobj
|
|
35
|
+
Provides-Extra: all
|
|
36
|
+
Provides-Extra: test
|
|
29
37
|
License-File: LICENSE
|
|
30
38
|
License-File: vendor_licenses/box-LICENSE.txt
|
|
31
39
|
License-File: vendor_licenses/click-LICENSE.rst
|
|
@@ -35,36 +43,6 @@ License-File: vendor_licenses/ruamel.yaml-LICENSE.txt
|
|
|
35
43
|
License-File: vendor_licenses/toml-LICENSE.txt
|
|
36
44
|
License-File: vendor_licenses/tomli-LICENSE.txt
|
|
37
45
|
License-File: vendor_licenses/vendor_versions.txt
|
|
38
|
-
Provides-Extra: redis
|
|
39
|
-
Requires-Dist: redis; extra == "redis"
|
|
40
|
-
Provides-Extra: vault
|
|
41
|
-
Requires-Dist: hvac; extra == "vault"
|
|
42
|
-
Provides-Extra: yaml
|
|
43
|
-
Requires-Dist: ruamel.yaml; extra == "yaml"
|
|
44
|
-
Provides-Extra: toml
|
|
45
|
-
Requires-Dist: toml; extra == "toml"
|
|
46
|
-
Provides-Extra: ini
|
|
47
|
-
Requires-Dist: configobj; extra == "ini"
|
|
48
|
-
Provides-Extra: configobj
|
|
49
|
-
Requires-Dist: configobj; extra == "configobj"
|
|
50
|
-
Provides-Extra: all
|
|
51
|
-
Requires-Dist: redis; extra == "all"
|
|
52
|
-
Requires-Dist: ruamel.yaml; extra == "all"
|
|
53
|
-
Requires-Dist: configobj; extra == "all"
|
|
54
|
-
Requires-Dist: hvac; extra == "all"
|
|
55
|
-
Provides-Extra: test
|
|
56
|
-
Requires-Dist: pytest; extra == "test"
|
|
57
|
-
Requires-Dist: pytest-cov; extra == "test"
|
|
58
|
-
Requires-Dist: pytest-xdist; extra == "test"
|
|
59
|
-
Requires-Dist: pytest-mock; extra == "test"
|
|
60
|
-
Requires-Dist: radon; extra == "test"
|
|
61
|
-
Requires-Dist: flask>=0.12; extra == "test"
|
|
62
|
-
Requires-Dist: django; extra == "test"
|
|
63
|
-
Requires-Dist: python-dotenv; extra == "test"
|
|
64
|
-
Requires-Dist: toml; extra == "test"
|
|
65
|
-
Requires-Dist: redis; extra == "test"
|
|
66
|
-
Requires-Dist: hvac>=1.1.0; extra == "test"
|
|
67
|
-
Requires-Dist: configobj; extra == "test"
|
|
68
46
|
|
|
69
47
|
<!-- [](http://dynaconf.com) -->
|
|
70
48
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.2.7
|
|
@@ -229,7 +229,7 @@ class Settings:
|
|
|
229
229
|
self._loaded_py_modules = []
|
|
230
230
|
self._loaded_files = []
|
|
231
231
|
self._deleted = set()
|
|
232
|
-
self._store = DynaBox(box_settings=self)
|
|
232
|
+
self._store = kwargs.pop("_store", DynaBox(box_settings=self))
|
|
233
233
|
self._env_cache = {}
|
|
234
234
|
self._loaded_by_loaders: dict[SourceMetadata | str, Any] = {}
|
|
235
235
|
self._loaders = []
|
|
@@ -968,6 +968,15 @@ class Settings:
|
|
|
968
968
|
self.store.get(key, None) if not isinstance(parsed, Lazy) else None
|
|
969
969
|
)
|
|
970
970
|
|
|
971
|
+
if getattr(parsed, "_dynaconf_insert", False):
|
|
972
|
+
# `@insert` calls insert in a list by index
|
|
973
|
+
if existing and isinstance(existing, list):
|
|
974
|
+
source_metadata = source_metadata._replace(merged=True)
|
|
975
|
+
existing.insert(parsed.index, parsed.unwrap())
|
|
976
|
+
parsed = existing
|
|
977
|
+
else:
|
|
978
|
+
parsed = [parsed.unwrap()]
|
|
979
|
+
|
|
971
980
|
if getattr(parsed, "_dynaconf_del", None):
|
|
972
981
|
self.unset(key, force=True) # `@del` in a first level var.
|
|
973
982
|
return
|
|
@@ -1227,14 +1236,27 @@ class Settings:
|
|
|
1227
1236
|
validate = self.get("VALIDATE_ON_UPDATE_FOR_DYNACONF")
|
|
1228
1237
|
|
|
1229
1238
|
env = (env or self.current_env).upper()
|
|
1239
|
+
|
|
1230
1240
|
files = ensure_a_list(path)
|
|
1231
1241
|
if files:
|
|
1242
|
+
# Using inspect take the filename and line number of the caller
|
|
1243
|
+
# to be used in the source_metadata
|
|
1244
|
+
frame = inspect.currentframe()
|
|
1245
|
+
caller = inspect.getouterframes(frame)[1]
|
|
1232
1246
|
already_loaded = set()
|
|
1233
1247
|
for _filename in files:
|
|
1234
1248
|
# load_file() will handle validation later
|
|
1235
1249
|
with suppress(ValidationError):
|
|
1250
|
+
source_metadata = SourceMetadata(
|
|
1251
|
+
loader=f"load_file@{caller.filename}:{caller.lineno}",
|
|
1252
|
+
identifier=_filename,
|
|
1253
|
+
env=env,
|
|
1254
|
+
)
|
|
1236
1255
|
if py_loader.try_to_load_from_py_module_name(
|
|
1237
|
-
obj=self,
|
|
1256
|
+
obj=self,
|
|
1257
|
+
name=_filename,
|
|
1258
|
+
silent=True,
|
|
1259
|
+
identifier=source_metadata,
|
|
1238
1260
|
):
|
|
1239
1261
|
# if it was possible to load from module name
|
|
1240
1262
|
# continue the loop.
|
|
@@ -1265,6 +1287,11 @@ class Settings:
|
|
|
1265
1287
|
|
|
1266
1288
|
# load_file() will handle validation later
|
|
1267
1289
|
with suppress(ValidationError):
|
|
1290
|
+
source_metadata = SourceMetadata(
|
|
1291
|
+
loader=f"load_file@{caller.filename}:{caller.lineno}",
|
|
1292
|
+
identifier=path,
|
|
1293
|
+
env=env,
|
|
1294
|
+
)
|
|
1268
1295
|
settings_loader(
|
|
1269
1296
|
obj=self,
|
|
1270
1297
|
env=env,
|
|
@@ -1272,6 +1299,7 @@ class Settings:
|
|
|
1272
1299
|
key=key,
|
|
1273
1300
|
filename=path,
|
|
1274
1301
|
validate=validate,
|
|
1302
|
+
identifier=source_metadata,
|
|
1275
1303
|
)
|
|
1276
1304
|
already_loaded.add(path)
|
|
1277
1305
|
|
|
@@ -1357,7 +1385,7 @@ class Settings:
|
|
|
1357
1385
|
value = self.get_fresh(key)
|
|
1358
1386
|
return value is True or value in true_values
|
|
1359
1387
|
|
|
1360
|
-
def populate_obj(self, obj, keys=None, ignore=None):
|
|
1388
|
+
def populate_obj(self, obj, keys=None, ignore=None, internal=False):
|
|
1361
1389
|
"""Given the `obj` populate it using self.store items.
|
|
1362
1390
|
|
|
1363
1391
|
:param obj: An object to be populated, a class instance.
|
|
@@ -1366,6 +1394,9 @@ class Settings:
|
|
|
1366
1394
|
"""
|
|
1367
1395
|
keys = keys or self.keys()
|
|
1368
1396
|
for key in keys:
|
|
1397
|
+
if not internal:
|
|
1398
|
+
if key in UPPER_DEFAULT_SETTINGS:
|
|
1399
|
+
continue
|
|
1369
1400
|
key = upperfy(key)
|
|
1370
1401
|
if ignore and key in ignore:
|
|
1371
1402
|
continue
|
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import importlib
|
|
4
|
+
import inspect as python_inspect
|
|
4
5
|
import json
|
|
5
6
|
import os
|
|
6
7
|
import pprint
|
|
7
8
|
import sys
|
|
8
9
|
import warnings
|
|
9
10
|
import webbrowser
|
|
11
|
+
from contextlib import redirect_stdout
|
|
10
12
|
from contextlib import suppress
|
|
11
13
|
from pathlib import Path
|
|
12
|
-
from typing import TYPE_CHECKING
|
|
13
14
|
|
|
14
15
|
from dynaconf import constants
|
|
15
16
|
from dynaconf import default_settings
|
|
16
17
|
from dynaconf import LazySettings
|
|
17
18
|
from dynaconf import loaders
|
|
18
19
|
from dynaconf import settings as legacy_settings
|
|
20
|
+
from dynaconf.base import Settings
|
|
19
21
|
from dynaconf.loaders.py_loader import get_module
|
|
22
|
+
from dynaconf.utils import prepare_json
|
|
20
23
|
from dynaconf.utils import upperfy
|
|
21
24
|
from dynaconf.utils.files import read_file
|
|
22
25
|
from dynaconf.utils.functional import empty
|
|
@@ -33,9 +36,6 @@ from dynaconf.vendor import click
|
|
|
33
36
|
from dynaconf.vendor import toml
|
|
34
37
|
from dynaconf.vendor import tomllib
|
|
35
38
|
|
|
36
|
-
if TYPE_CHECKING: # pragma: no cover
|
|
37
|
-
from dynaconf.base import Settings # noqa: F401
|
|
38
|
-
|
|
39
39
|
os.environ["PYTHONIOENCODING"] = "utf-8"
|
|
40
40
|
|
|
41
41
|
CWD = None
|
|
@@ -55,6 +55,8 @@ def set_settings(ctx, instance=None):
|
|
|
55
55
|
settings = None
|
|
56
56
|
|
|
57
57
|
_echo_enabled = ctx.invoked_subcommand not in ["get", "inspect", None]
|
|
58
|
+
if "--json" in click.get_os_args():
|
|
59
|
+
_echo_enabled = False
|
|
58
60
|
|
|
59
61
|
if instance is not None:
|
|
60
62
|
if ctx.invoked_subcommand in ["init"]:
|
|
@@ -79,19 +81,16 @@ def set_settings(ctx, instance=None):
|
|
|
79
81
|
)
|
|
80
82
|
elif "DJANGO_SETTINGS_MODULE" in os.environ: # pragma: no cover
|
|
81
83
|
sys.path.insert(0, os.path.abspath(os.getcwd()))
|
|
82
|
-
|
|
83
|
-
# Django extension v2
|
|
84
|
-
from django.conf import settings # noqa
|
|
85
|
-
import dynaconf # noqa: F401
|
|
86
|
-
import django
|
|
84
|
+
import django # noqa
|
|
87
85
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
86
|
+
django.setup() # ensure django is setup to avoid AppRegistryNotReady
|
|
87
|
+
settings_module = import__django_settings(
|
|
88
|
+
os.environ["DJANGO_SETTINGS_MODULE"]
|
|
89
|
+
)
|
|
90
|
+
for member in python_inspect.getmembers(settings_module):
|
|
91
|
+
if isinstance(member[1], (LazySettings, Settings)):
|
|
92
|
+
settings = member[1]
|
|
93
|
+
break
|
|
95
94
|
|
|
96
95
|
if settings is not None and _echo_enabled:
|
|
97
96
|
click.echo(
|
|
@@ -117,6 +116,18 @@ def set_settings(ctx, instance=None):
|
|
|
117
116
|
settings = LazySettings()
|
|
118
117
|
|
|
119
118
|
|
|
119
|
+
def import__django_settings(django_settings_module):
|
|
120
|
+
"""Import the Django settings module from the string importable path."""
|
|
121
|
+
try:
|
|
122
|
+
with redirect_stdout(None):
|
|
123
|
+
module = importlib.import_module(django_settings_module)
|
|
124
|
+
except ImportError as e:
|
|
125
|
+
raise click.UsageError(e)
|
|
126
|
+
except FileNotFoundError:
|
|
127
|
+
return
|
|
128
|
+
return module
|
|
129
|
+
|
|
130
|
+
|
|
120
131
|
def import_settings(dotted_path):
|
|
121
132
|
"""Import settings instance from python dotted path.
|
|
122
133
|
|
|
@@ -130,8 +141,10 @@ def import_settings(dotted_path):
|
|
|
130
141
|
raise click.UsageError(
|
|
131
142
|
f"invalid path to settings instance: {dotted_path}"
|
|
132
143
|
)
|
|
144
|
+
|
|
133
145
|
try:
|
|
134
|
-
|
|
146
|
+
with redirect_stdout(None):
|
|
147
|
+
module = importlib.import_module(module)
|
|
135
148
|
except ImportError as e:
|
|
136
149
|
raise click.UsageError(e)
|
|
137
150
|
except FileNotFoundError:
|
|
@@ -485,7 +498,7 @@ def get(key, default, env, unparse):
|
|
|
485
498
|
result = unparse_conf_data(result)
|
|
486
499
|
|
|
487
500
|
if isinstance(result, (dict, list, tuple)):
|
|
488
|
-
result = json.dumps(result, sort_keys=True)
|
|
501
|
+
result = json.dumps(prepare_json(result), sort_keys=True, default=repr)
|
|
489
502
|
|
|
490
503
|
click.echo(result, nl=False)
|
|
491
504
|
|
|
@@ -530,7 +543,24 @@ def get(key, default, env, unparse):
|
|
|
530
543
|
default=False,
|
|
531
544
|
help="Output file is flat (do not include [env] name)",
|
|
532
545
|
)
|
|
533
|
-
|
|
546
|
+
@click.option(
|
|
547
|
+
"--json",
|
|
548
|
+
"_json",
|
|
549
|
+
"-j",
|
|
550
|
+
is_flag=True,
|
|
551
|
+
default=False,
|
|
552
|
+
help="Prints out data serialized as JSON",
|
|
553
|
+
)
|
|
554
|
+
def _list(
|
|
555
|
+
env,
|
|
556
|
+
key,
|
|
557
|
+
more,
|
|
558
|
+
loader,
|
|
559
|
+
_all=False,
|
|
560
|
+
output=None,
|
|
561
|
+
flat=False,
|
|
562
|
+
_json=False,
|
|
563
|
+
):
|
|
534
564
|
"""
|
|
535
565
|
Lists user defined settings or all (including internal configs).
|
|
536
566
|
|
|
@@ -552,14 +582,15 @@ def _list(env, key, more, loader, _all=False, output=None, flat=False):
|
|
|
552
582
|
if cur_env == "main":
|
|
553
583
|
flat = True
|
|
554
584
|
|
|
555
|
-
|
|
556
|
-
click.
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
585
|
+
if not _json:
|
|
586
|
+
click.echo(
|
|
587
|
+
click.style(
|
|
588
|
+
f"Working in {cur_env} environment ",
|
|
589
|
+
bold=True,
|
|
590
|
+
bg="bright_blue",
|
|
591
|
+
fg="bright_white",
|
|
592
|
+
)
|
|
561
593
|
)
|
|
562
|
-
)
|
|
563
594
|
|
|
564
595
|
if not loader:
|
|
565
596
|
data = settings.as_dict(env=env, internal=_all)
|
|
@@ -585,14 +616,20 @@ def _list(env, key, more, loader, _all=False, output=None, flat=False):
|
|
|
585
616
|
return f"{key}{data_type} {value}"
|
|
586
617
|
|
|
587
618
|
if not key:
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
619
|
+
if not _json:
|
|
620
|
+
datalines = "\n".join(
|
|
621
|
+
format_setting(k, v)
|
|
622
|
+
for k, v in data.items()
|
|
623
|
+
if k not in data.get("RENAMED_VARS", [])
|
|
624
|
+
)
|
|
625
|
+
(click.echo_via_pager if more else click.echo)(datalines)
|
|
594
626
|
if output:
|
|
595
|
-
loaders.write(output, data, env=not flat and cur_env)
|
|
627
|
+
loaders.write(output, prepare_json(data), env=not flat and cur_env)
|
|
628
|
+
if _json:
|
|
629
|
+
json_data = json.dumps(
|
|
630
|
+
prepare_json(data), sort_keys=True, default=repr
|
|
631
|
+
)
|
|
632
|
+
click.echo(json_data, nl=False)
|
|
596
633
|
else:
|
|
597
634
|
key = upperfy(key)
|
|
598
635
|
|
|
@@ -605,9 +642,16 @@ def _list(env, key, more, loader, _all=False, output=None, flat=False):
|
|
|
605
642
|
click.secho("Key not found", bg="red", fg="white", err=True)
|
|
606
643
|
return
|
|
607
644
|
|
|
608
|
-
|
|
645
|
+
if not _json:
|
|
646
|
+
click.echo(format_setting(key, value))
|
|
609
647
|
if output:
|
|
610
|
-
loaders.write(
|
|
648
|
+
loaders.write(
|
|
649
|
+
output, prepare_json({key: value}), env=not flat and cur_env
|
|
650
|
+
)
|
|
651
|
+
if _json:
|
|
652
|
+
click.echo(
|
|
653
|
+
json.dumps(prepare_json({key: value}), default=repr), nl=True
|
|
654
|
+
)
|
|
611
655
|
|
|
612
656
|
if env:
|
|
613
657
|
settings.setenv()
|
|
@@ -6,7 +6,6 @@ from functools import wraps
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
from typing import Callable
|
|
8
8
|
|
|
9
|
-
from dynaconf.base import RESERVED_ATTRS
|
|
10
9
|
from dynaconf.base import Settings
|
|
11
10
|
from dynaconf.loaders.base import SourceMetadata
|
|
12
11
|
|
|
@@ -77,17 +76,9 @@ def hookable(function=None, name=None):
|
|
|
77
76
|
):
|
|
78
77
|
return fun(self, *args, **kwargs)
|
|
79
78
|
|
|
80
|
-
# Create an
|
|
79
|
+
# Create an unhook-able (to avoid recursion)
|
|
81
80
|
# temporary settings to pass to the hooked function
|
|
82
|
-
temp_settings =
|
|
83
|
-
dynaconf_skip_loaders=True,
|
|
84
|
-
dynaconf_skip_validators=True,
|
|
85
|
-
)
|
|
86
|
-
allowed_keys = self.__dict__.keys() - set(RESERVED_ATTRS)
|
|
87
|
-
temp_data = {
|
|
88
|
-
k: v for k, v in self.__dict__.items() if k in allowed_keys
|
|
89
|
-
}
|
|
90
|
-
temp_settings._store.update(temp_data)
|
|
81
|
+
temp_settings = TempSettingsHolder(self)
|
|
91
82
|
|
|
92
83
|
def _hook(action: str, value: HookValue) -> HookValue:
|
|
93
84
|
"""executes the hooks for the given action"""
|
|
@@ -304,3 +295,49 @@ class HookableSettings(Settings):
|
|
|
304
295
|
@hookable
|
|
305
296
|
def get(self, *args, **kwargs):
|
|
306
297
|
return Settings.get(self, *args, **kwargs)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class TempSettingsHolder:
|
|
301
|
+
"""Holds settings to be passed down to hooks.
|
|
302
|
+
To save runtime resources initialize a copy of it only if accessed.
|
|
303
|
+
"""
|
|
304
|
+
|
|
305
|
+
_settings = None
|
|
306
|
+
|
|
307
|
+
def __init__(self, settings):
|
|
308
|
+
self._original_settings = settings
|
|
309
|
+
|
|
310
|
+
def _initialize(self):
|
|
311
|
+
if self._settings is None:
|
|
312
|
+
self._settings = Settings(
|
|
313
|
+
dynaconf_skip_loaders=True,
|
|
314
|
+
dynaconf_skip_validators=True,
|
|
315
|
+
_store=self._original_settings._store._safe_copy(),
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
def __getattr__(self, attr):
|
|
319
|
+
self._initialize()
|
|
320
|
+
return getattr(self._settings, attr)
|
|
321
|
+
|
|
322
|
+
def __getitem__(self, item):
|
|
323
|
+
self._initialize()
|
|
324
|
+
return self._settings[item]
|
|
325
|
+
|
|
326
|
+
def __setitem__(self, item, value):
|
|
327
|
+
self._initialize()
|
|
328
|
+
self._settings[item] = value
|
|
329
|
+
|
|
330
|
+
def __iter__(self):
|
|
331
|
+
self._initialize()
|
|
332
|
+
return iter(self._settings)
|
|
333
|
+
|
|
334
|
+
def __contains__(self, item):
|
|
335
|
+
self._initialize()
|
|
336
|
+
return item in self._settings
|
|
337
|
+
|
|
338
|
+
def __setattr__(self, attr, value):
|
|
339
|
+
if attr in ["_original_settings", "_settings"]:
|
|
340
|
+
super().__setattr__(attr, value)
|
|
341
|
+
else:
|
|
342
|
+
self._initialize()
|
|
343
|
+
setattr(self._settings, attr, value)
|
|
@@ -12,6 +12,7 @@ from dynaconf.loaders import json_loader
|
|
|
12
12
|
from dynaconf.loaders import py_loader
|
|
13
13
|
from dynaconf.loaders import toml_loader
|
|
14
14
|
from dynaconf.loaders import yaml_loader
|
|
15
|
+
from dynaconf.loaders.base import SourceMetadata
|
|
15
16
|
from dynaconf.utils import deduplicate
|
|
16
17
|
from dynaconf.utils import ensure_a_list
|
|
17
18
|
from dynaconf.utils.boxing import DynaBox
|
|
@@ -126,12 +127,13 @@ def execute_module_hooks(
|
|
|
126
127
|
hook_file = os.path.join(
|
|
127
128
|
os.path.dirname(loaded_file), "dynaconf_hooks.py"
|
|
128
129
|
)
|
|
130
|
+
if not os.path.exists(hook_file):
|
|
131
|
+
# Return early if file doesn't exist.
|
|
132
|
+
# Faster than attempting to import.
|
|
133
|
+
continue
|
|
129
134
|
hook_module = py_loader.import_from_filename(
|
|
130
135
|
obj, hook_file, silent=silent
|
|
131
136
|
)
|
|
132
|
-
if not hook_module:
|
|
133
|
-
# There was no hook on the same path as a python file
|
|
134
|
-
continue
|
|
135
137
|
_run_hook_module(
|
|
136
138
|
hook_type=hook,
|
|
137
139
|
hook_module=hook_module,
|
|
@@ -221,6 +223,7 @@ def settings_loader(
|
|
|
221
223
|
key=None,
|
|
222
224
|
filename=None,
|
|
223
225
|
validate=False,
|
|
226
|
+
identifier="settings_loader",
|
|
224
227
|
):
|
|
225
228
|
"""Loads from defined settings module
|
|
226
229
|
|
|
@@ -230,6 +233,8 @@ def settings_loader(
|
|
|
230
233
|
:param silent: Boolean to raise loading errors
|
|
231
234
|
:param key: Load a single key if provided
|
|
232
235
|
:param filename: optional filename to override the settings_module
|
|
236
|
+
:param validate: If True validate the loaded data
|
|
237
|
+
:param identifier: A string or SourceMetadata to identify the loader
|
|
233
238
|
"""
|
|
234
239
|
if filename is None:
|
|
235
240
|
settings_module = settings_module or obj.settings_module
|
|
@@ -294,6 +299,9 @@ def settings_loader(
|
|
|
294
299
|
continue
|
|
295
300
|
|
|
296
301
|
if mod_file.endswith(loader["ext"]):
|
|
302
|
+
if isinstance(identifier, str):
|
|
303
|
+
# ensure it is always loader name
|
|
304
|
+
identifier = loader["name"].lower()
|
|
297
305
|
loader["loader"].load(
|
|
298
306
|
obj,
|
|
299
307
|
filename=mod_file,
|
|
@@ -301,6 +309,7 @@ def settings_loader(
|
|
|
301
309
|
silent=silent,
|
|
302
310
|
key=key,
|
|
303
311
|
validate=validate,
|
|
312
|
+
identifier=identifier,
|
|
304
313
|
)
|
|
305
314
|
continue
|
|
306
315
|
|
|
@@ -313,45 +322,73 @@ def settings_loader(
|
|
|
313
322
|
|
|
314
323
|
# must be Python file or module
|
|
315
324
|
# load from default defined module settings.py or .secrets.py if exists
|
|
316
|
-
py_loader.load(
|
|
325
|
+
py_loader.load(
|
|
326
|
+
obj, mod_file, key=key, validate=validate, identifier=identifier
|
|
327
|
+
)
|
|
317
328
|
|
|
318
329
|
# load from the current env e.g: development_settings.py
|
|
330
|
+
# counting on the case where env is a comma separated string
|
|
319
331
|
env = env or obj.current_env
|
|
320
|
-
if
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
332
|
+
if env and isinstance(env, str):
|
|
333
|
+
for env_name in env.split(","):
|
|
334
|
+
load_from_env_named_file(
|
|
335
|
+
obj, env_name, key, validate, identifier, mod_file
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def load_from_env_named_file(obj, env, key, validate, identifier, mod_file):
|
|
340
|
+
"""Load from env named file e.g: development_settings.py"""
|
|
341
|
+
if mod_file.endswith(".py"):
|
|
342
|
+
if ".secrets.py" == mod_file:
|
|
343
|
+
tmpl = ".{0}_{1}{2}"
|
|
344
|
+
mod_file = "secrets.py"
|
|
333
345
|
else:
|
|
334
|
-
|
|
335
|
-
|
|
346
|
+
tmpl = "{0}_{1}{2}"
|
|
347
|
+
|
|
348
|
+
dirname = os.path.dirname(mod_file)
|
|
349
|
+
filename, extension = os.path.splitext(os.path.basename(mod_file))
|
|
350
|
+
new_filename = tmpl.format(env.lower(), filename, extension)
|
|
351
|
+
env_mod_file = os.path.join(dirname, new_filename)
|
|
352
|
+
global_filename = tmpl.format("global", filename, extension)
|
|
353
|
+
global_mod_file = os.path.join(dirname, global_filename)
|
|
354
|
+
else:
|
|
355
|
+
parts = mod_file.rsplit(".", 1)
|
|
356
|
+
if len(parts) > 1:
|
|
357
|
+
head, tail = parts
|
|
358
|
+
else:
|
|
359
|
+
head, tail = None, parts[0]
|
|
360
|
+
tail = env_mod_file = f"{env.lower()}_{tail}"
|
|
336
361
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
validate=validate,
|
|
344
|
-
)
|
|
362
|
+
if head:
|
|
363
|
+
env_mod_file = f"{head}.{tail}"
|
|
364
|
+
global_mod_file = f"{head}.global_{tail}"
|
|
365
|
+
else:
|
|
366
|
+
env_mod_file = tail
|
|
367
|
+
global_mod_file = f"global_{tail}"
|
|
345
368
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
369
|
+
source_metadata = SourceMetadata(
|
|
370
|
+
loader="py",
|
|
371
|
+
identifier=identifier,
|
|
372
|
+
env=env,
|
|
373
|
+
)
|
|
374
|
+
py_loader.load(
|
|
375
|
+
obj,
|
|
376
|
+
env_mod_file,
|
|
377
|
+
identifier=source_metadata,
|
|
378
|
+
silent=True,
|
|
379
|
+
key=key,
|
|
380
|
+
validate=validate,
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
# load from global_settings.py
|
|
384
|
+
py_loader.load(
|
|
385
|
+
obj,
|
|
386
|
+
global_mod_file,
|
|
387
|
+
identifier="py_global",
|
|
388
|
+
silent=True,
|
|
389
|
+
key=key,
|
|
390
|
+
validate=validate,
|
|
391
|
+
)
|
|
355
392
|
|
|
356
393
|
|
|
357
394
|
def enable_external_loaders(obj):
|