dynaconf 3.3.2__tar.gz → 3.3.3__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.3.2 → dynaconf-3.3.3}/CHANGELOG.md +25 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/PKG-INFO +1 -1
- {dynaconf-3.3.2 → dynaconf-3.3.3}/RELEASING.md +1 -0
- dynaconf-3.3.3/dynaconf/VERSION +1 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/base.py +3 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/nodes.py +6 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/validator.py +35 -19
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf.egg-info/PKG-INFO +1 -1
- {dynaconf-3.3.2 → dynaconf-3.3.3}/pyproject.toml +1 -1
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_utils.py +81 -75
- dynaconf-3.3.2/dynaconf/VERSION +0 -1
- {dynaconf-3.3.2 → dynaconf-3.3.3}/CONTRIBUTING.md +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/CONTRIBUTORS.md +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/LICENSE +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/MANIFEST.in +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/README.md +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/SECURITY.md +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/__main__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/cli.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/constants.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/contrib/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/contrib/django_dynaconf_v2.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/contrib/flask_dynaconf.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/default_settings.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/hooking.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/base.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/env_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/ini_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/json_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/py_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/redis_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/toml_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/vault_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/loaders/yaml_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/strategies/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/strategies/filtering.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/test_settings.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/typed/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/typed/compat.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/typed/exceptions.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/typed/guards.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/typed/main.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/typed/types.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/typed/utils.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/typed/validators.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/utils/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/utils/boxing.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/utils/files.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/utils/functional.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/utils/inspect.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/utils/parse_conf.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/validator_conditions.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/box/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/box/box.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/box/box_list.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/box/config_box.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/box/converters.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/box/exceptions.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/box/from_file.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/box/shorthand_box.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/_bashcomplete.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/_compat.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/_termui_impl.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/_textwrap.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/_unicodefun.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/_winconsole.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/core.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/decorators.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/exceptions.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/formatting.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/globals.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/parser.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/termui.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/testing.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/types.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/click/utils.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/dotenv/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/dotenv/cli.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/dotenv/compat.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/dotenv/ipython.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/dotenv/main.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/dotenv/parser.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/dotenv/py.typed +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/dotenv/version.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/anchor.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/comments.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/compat.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/composer.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/configobjwalker.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/constructor.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/cyaml.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/dumper.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/emitter.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/error.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/events.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/main.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/nodes.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/parser.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/py.typed +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/reader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/representer.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/resolver.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/scalarbool.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/scalarfloat.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/scalarint.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/scalarstring.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/scanner.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/serializer.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/setup.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/timestamp.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/tokens.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/ruamel/yaml/util.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/toml/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/toml/decoder.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/toml/encoder.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/toml/ordered.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/toml/tz.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/tomllib/__init__.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/tomllib/_parser.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/tomllib/_re.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/tomllib/_types.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf/vendor/tomllib/_writer.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf.egg-info/SOURCES.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf.egg-info/dependency_links.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf.egg-info/entry_points.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf.egg-info/not-zip-safe +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf.egg-info/requires.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/dynaconf.egg-info/top_level.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/setup.cfg +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_base.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_basic.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_cli.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_compat.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_django.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_dynabox.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_endtoend.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_env_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_envvar_prefix.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_feature_flag.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_flask.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_hooking.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_ini_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_inspect.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_json_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_loaders.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_nested_loading.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_nodes.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_py_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_redis.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_release_utility.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_settings_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_toml_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_typed.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_validators.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_validators_conditions.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_vault.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/tests/test_yaml_loader.py +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/vendor_licenses/box-LICENSE.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/vendor_licenses/click-LICENSE.rst +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/vendor_licenses/licenses.sh +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/vendor_licenses/python-dotenv-LICENSE.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/vendor_licenses/ruamel.yaml-LICENSE.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/vendor_licenses/toml-LICENSE.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/vendor_licenses/tomli-LICENSE.txt +0 -0
- {dynaconf-3.3.2 → dynaconf-3.3.3}/vendor_licenses/vendor_versions.txt +0 -0
|
@@ -2,6 +2,31 @@ Changelog
|
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
4
|
<!-- insertion marker -->
|
|
5
|
+
## [3.3.3](https://github.com/dynaconf/dynaconf/releases/tag/3.3.3) - 2026-07-22
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
- Fixed regression on lazy evaluation when using dynaboxify=False (#1429). By @pedro-psb.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Docs
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
- Clarify the values of True, False and None for must_exist check (#1416). By @pedro-psb.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Chore
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
- Fix netlify deploy command on publish workflow (#1420). By @pedro-psb.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
- Consolidate docs-publishing workflow for rolling-release (#1417). By @pedro-psb.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
- Simplify docs-only skip and include backport branches on main CI (#1415). By @pedro-psb.
|
|
29
|
+
|
|
5
30
|
## [3.3.2](https://github.com/dynaconf/dynaconf/releases/tag/3.3.2) - 2026-06-29
|
|
6
31
|
|
|
7
32
|
### Bug Fixes
|
|
@@ -60,6 +60,7 @@ To do so, run `Actions → Publish → Run workflow` with the tag.
|
|
|
60
60
|
- The publication uses [Trusted Publishing](https://docs.pypi.org/trusted-publishers/), which must be configured in PyPI.
|
|
61
61
|
- The release requires content write permissions (push tags). A [Github App](https://docs.github.com/en/apps/overview)
|
|
62
62
|
(DynaconfBot) was created to enable emitting short-lived tokens with well-scoped permission.
|
|
63
|
+
- Docs publish can be triggered separately via `publish-docs.yml` workflow if required.
|
|
63
64
|
|
|
64
65
|
### Glossary
|
|
65
66
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.3.3
|
|
@@ -31,6 +31,7 @@ from dynaconf.loaders import yaml_loader
|
|
|
31
31
|
from dynaconf.loaders.base import SourceMetadata
|
|
32
32
|
from dynaconf.nodes import DataDict
|
|
33
33
|
from dynaconf.nodes import DataList
|
|
34
|
+
from dynaconf.nodes import recursively_evaluate_lazy_format
|
|
34
35
|
from dynaconf.strategies.filtering import PrefixFilter
|
|
35
36
|
from dynaconf.utils import BANNER
|
|
36
37
|
from dynaconf.utils import ensure_a_list
|
|
@@ -641,6 +642,8 @@ class Settings:
|
|
|
641
642
|
self.execute_loaders(key=key)
|
|
642
643
|
|
|
643
644
|
data = _get_with_default(parent or core.store, key, default)
|
|
645
|
+
if config.dynaboxify is False:
|
|
646
|
+
data = recursively_evaluate_lazy_format(data, self)
|
|
644
647
|
if cast:
|
|
645
648
|
data = apply_converter(cast, data, box_settings=self)
|
|
646
649
|
return data
|
|
@@ -89,9 +89,14 @@ class Validator:
|
|
|
89
89
|
# When the very first thing to be performed when passed.
|
|
90
90
|
# if no env is passed to `when` it is inherited
|
|
91
91
|
|
|
92
|
-
`must_exist`
|
|
92
|
+
`must_exist` controls existence checking (executed after when)::
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
must_exist=True — variable must be present; raises if absent
|
|
95
|
+
must_exist=False — variable must be absent; raises if present
|
|
96
|
+
must_exist=None — no existence rule (default); absent variables
|
|
97
|
+
skip all further checks on that name
|
|
98
|
+
|
|
99
|
+
`required` is an alias for `must_exist`.
|
|
95
100
|
|
|
96
101
|
condition is a callable to be executed and return boolean::
|
|
97
102
|
|
|
@@ -214,11 +219,11 @@ class Validator:
|
|
|
214
219
|
return _repr
|
|
215
220
|
|
|
216
221
|
@property
|
|
217
|
-
def required(self) -> bool:
|
|
218
|
-
return
|
|
222
|
+
def required(self) -> bool | None:
|
|
223
|
+
return self.must_exist
|
|
219
224
|
|
|
220
225
|
@required.setter
|
|
221
|
-
def required(self, value: bool):
|
|
226
|
+
def required(self, value: bool | None):
|
|
222
227
|
self.must_exist = value
|
|
223
228
|
|
|
224
229
|
@property
|
|
@@ -387,21 +392,32 @@ class Validator:
|
|
|
387
392
|
else:
|
|
388
393
|
value = settings.get(name, default_value)
|
|
389
394
|
|
|
390
|
-
#
|
|
391
|
-
if self.must_exist is
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
395
|
+
# Existence checks
|
|
396
|
+
if self.must_exist is None: # must_exist is unset
|
|
397
|
+
if value is empty:
|
|
398
|
+
continue # no further checks required, as there is nothing to check
|
|
399
|
+
else:
|
|
400
|
+
pass # proceed with further checks
|
|
401
|
+
elif self.must_exist is True:
|
|
402
|
+
if value is empty:
|
|
403
|
+
_message = self.messages["must_exist_true"].format(
|
|
404
|
+
name=name, env=env
|
|
405
|
+
)
|
|
406
|
+
raise ValidationError(_message, details=[(self, _message)])
|
|
407
|
+
else:
|
|
408
|
+
pass
|
|
409
|
+
elif self.must_exist is False:
|
|
410
|
+
if value is empty:
|
|
411
|
+
continue # value absent as required — nothing further to check
|
|
412
|
+
else:
|
|
413
|
+
_message = self.messages["must_exist_false"].format(
|
|
414
|
+
name=name, env=env
|
|
415
|
+
)
|
|
416
|
+
raise ValidationError(_message, details=[(self, _message)])
|
|
417
|
+
else:
|
|
418
|
+
raise ValueError(
|
|
419
|
+
f"must_exist must be True, False, or None, got {self.must_exist!r}"
|
|
400
420
|
)
|
|
401
|
-
raise ValidationError(_message, details=[(self, _message)])
|
|
402
|
-
|
|
403
|
-
if self.must_exist in (False, None) and value is empty:
|
|
404
|
-
continue
|
|
405
421
|
|
|
406
422
|
# value or default value already set
|
|
407
423
|
# by settings.setdefault above
|
|
@@ -455,85 +455,104 @@ def test_upperfy():
|
|
|
455
455
|
assert upperfy("foo_BAR") == "FOO_BAR"
|
|
456
456
|
|
|
457
457
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
def
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
def get(self, key, default=None):
|
|
473
|
-
if key.endswith("_FOR_DYNACONF"):
|
|
474
|
-
return getattr(self, key)
|
|
475
|
-
return parse_conf_data("@format {this.FOO}/bar", box_settings=self)
|
|
458
|
+
class TestLazyInternal:
|
|
459
|
+
def test_format_class(self):
|
|
460
|
+
value = Lazy("{this[FOO]}/bar")
|
|
461
|
+
settings = {"FOO": "foo"}
|
|
462
|
+
assert value(settings) == "foo/bar"
|
|
463
|
+
assert str(value) == value.value
|
|
464
|
+
assert repr(value) == f"'@{value.formatter} {value.value}'"
|
|
465
|
+
|
|
466
|
+
def test_format_class_jinja(self):
|
|
467
|
+
value = Lazy(
|
|
468
|
+
"{{this['FOO']}}/bar", formatter=Formatters.jinja_formatter
|
|
469
|
+
)
|
|
470
|
+
settings = {"FOO": "foo"}
|
|
471
|
+
assert value(settings) == "foo/bar"
|
|
476
472
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
return False
|
|
481
|
-
return True
|
|
473
|
+
def test_custom_function_formatter(self):
|
|
474
|
+
def custom_formatter(value, **context):
|
|
475
|
+
return f"custom:{value}"
|
|
482
476
|
|
|
483
|
-
|
|
484
|
-
|
|
477
|
+
lazy_val = Lazy("test", formatter=custom_formatter)
|
|
478
|
+
assert lazy_val({}) == "custom:test"
|
|
485
479
|
|
|
480
|
+
def test_json_serializable(self):
|
|
481
|
+
value = Lazy("{this[FOO]}/bar")
|
|
482
|
+
assert (
|
|
483
|
+
json.dumps({"val": value}, cls=DynaconfEncoder)
|
|
484
|
+
== '{"val": "@format {this[FOO]}/bar"}'
|
|
485
|
+
)
|
|
486
486
|
|
|
487
|
-
def test_lazy_format_on_settings(settings):
|
|
488
|
-
os.environ["ENV_THING"] = "LazyFormat"
|
|
489
|
-
settings.set("set_1", "really")
|
|
490
|
-
settings.set("lazy", "@format {env[ENV_THING]}/{this[set_1]}/{this.SET_2}")
|
|
491
|
-
settings.set("set_2", "works")
|
|
492
487
|
|
|
493
|
-
|
|
488
|
+
class TestLazyDecorator:
|
|
489
|
+
def _make_settings(self, template):
|
|
490
|
+
class Settings:
|
|
491
|
+
FOO = "foo"
|
|
492
|
+
AUTO_CAST_FOR_DYNACONF = True
|
|
494
493
|
|
|
494
|
+
@evaluate_lazy_format
|
|
495
|
+
def get(self, key, default=None):
|
|
496
|
+
if key.endswith("_FOR_DYNACONF"):
|
|
497
|
+
return getattr(self, key)
|
|
498
|
+
return parse_conf_data(template, box_settings=self)
|
|
495
499
|
|
|
496
|
-
def
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
+
def __contains__(self, key):
|
|
501
|
+
value = getattr(self, key, missing)
|
|
502
|
+
if value is missing:
|
|
503
|
+
return False
|
|
504
|
+
return True
|
|
500
505
|
|
|
506
|
+
return Settings()
|
|
501
507
|
|
|
502
|
-
def
|
|
503
|
-
|
|
504
|
-
|
|
508
|
+
def test_format(self):
|
|
509
|
+
settings = self._make_settings("@format {this.FOO}/bar")
|
|
510
|
+
assert settings.get("foo") == "foo/bar"
|
|
505
511
|
|
|
506
|
-
|
|
512
|
+
def test_jinja(self):
|
|
513
|
+
settings = self._make_settings("@jinja {{this.FOO}}/bar")
|
|
514
|
+
assert settings.get("foo") == "foo/bar"
|
|
507
515
|
|
|
508
|
-
@evaluate_lazy_format
|
|
509
|
-
def get(self, key, default=None):
|
|
510
|
-
if key.endswith("_FOR_DYNACONF"):
|
|
511
|
-
return getattr(self, key)
|
|
512
|
-
return parse_conf_data(
|
|
513
|
-
"@jinja {{this.FOO}}/bar", box_settings=settings
|
|
514
|
-
)
|
|
515
516
|
|
|
516
|
-
|
|
517
|
-
|
|
517
|
+
class TestLazyUsage:
|
|
518
|
+
@pytest.fixture(params=[True, False], ids=["dynaboxify", "no_dynaboxify"])
|
|
519
|
+
def settings(self, request):
|
|
520
|
+
return Dynaconf(dynaboxify=request.param)
|
|
518
521
|
|
|
522
|
+
def test_format(self, settings):
|
|
523
|
+
os.environ["ENV_THING"] = "LazyFormat"
|
|
524
|
+
settings.set("set_1", "really")
|
|
525
|
+
settings.set(
|
|
526
|
+
"lazy", "@format {env[ENV_THING]}/{this[set_1]}/{this.SET_2}"
|
|
527
|
+
)
|
|
528
|
+
settings.set("set_2", "works")
|
|
519
529
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
settings.set(
|
|
524
|
-
"lazy", "@jinja {{env.ENV_THING}}/{{this['set_1']}}/{{this.SET_2}}"
|
|
525
|
-
)
|
|
526
|
-
settings.set("set_2", "works")
|
|
530
|
+
assert (
|
|
531
|
+
settings.LAZY == settings.get("lazy") == "LazyFormat/really/works"
|
|
532
|
+
)
|
|
527
533
|
|
|
528
|
-
|
|
534
|
+
def test_format_nested_dict(self, settings):
|
|
535
|
+
settings.set("BASE_VALUE", "hello")
|
|
536
|
+
settings.set("NESTED", {"inner": "@format {this[BASE_VALUE]}/world"})
|
|
537
|
+
assert settings.get("NESTED")["inner"] == "hello/world"
|
|
538
|
+
|
|
539
|
+
def test_jinja(self, settings):
|
|
540
|
+
os.environ["ENV_THING"] = "LazyFormat"
|
|
541
|
+
settings.set("set_1", "really")
|
|
542
|
+
settings.set(
|
|
543
|
+
"lazy",
|
|
544
|
+
"@jinja {{env.ENV_THING}}/{{this['set_1']}}/{{this.SET_2}}",
|
|
545
|
+
)
|
|
546
|
+
settings.set("set_2", "works")
|
|
529
547
|
|
|
548
|
+
assert (
|
|
549
|
+
settings.LAZY == settings.get("lazy") == "LazyFormat/really/works"
|
|
550
|
+
)
|
|
530
551
|
|
|
531
|
-
def
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
== '{"val": "@format {this[FOO]}/bar"}'
|
|
536
|
-
)
|
|
552
|
+
def test_jinja_nested_dict(self, settings):
|
|
553
|
+
settings.set("BASE_VALUE", "hello")
|
|
554
|
+
settings.set("NESTED", {"inner": "@jinja {{this.BASE_VALUE}}/world"})
|
|
555
|
+
assert settings.get("NESTED")["inner"] == "hello/world"
|
|
537
556
|
|
|
538
557
|
|
|
539
558
|
def test_try_to_encode():
|
|
@@ -1365,19 +1384,6 @@ def test_read_file_os_error(tmp_path, monkeypatch):
|
|
|
1365
1384
|
settings.SECRET
|
|
1366
1385
|
|
|
1367
1386
|
|
|
1368
|
-
def test_lazy_with_custom_function_formatter():
|
|
1369
|
-
"""Test Lazy with custom function (not BaseFormatter)"""
|
|
1370
|
-
from dynaconf.utils.parse_conf import Lazy
|
|
1371
|
-
|
|
1372
|
-
def custom_formatter(value, **context):
|
|
1373
|
-
return f"custom:{value}"
|
|
1374
|
-
|
|
1375
|
-
lazy_val = Lazy("test", formatter=custom_formatter)
|
|
1376
|
-
settings = {}
|
|
1377
|
-
result = lazy_val(settings)
|
|
1378
|
-
assert result == "custom:test"
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
1387
|
def test_safe_json_parse_extract_objects(settings):
|
|
1382
1388
|
"""Test _safe_json_parse with extract_json_objects"""
|
|
1383
1389
|
# Test case where extract_json_objects finds valid JSON
|
dynaconf-3.3.2/dynaconf/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.3.2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|