dynaconf 3.3.1__tar.gz → 3.3.2__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.1 → dynaconf-3.3.2}/CHANGELOG.md +25 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/PKG-INFO +1 -1
- dynaconf-3.3.2/dynaconf/VERSION +1 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/base.py +3 -2
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/cli.py +2 -2
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/utils/__init__.py +1 -1
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/utils/parse_conf.py +1 -1
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf.egg-info/PKG-INFO +1 -1
- {dynaconf-3.3.1 → dynaconf-3.3.2}/pyproject.toml +5 -2
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_cli.py +73 -35
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_utils.py +49 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_validators.py +16 -0
- dynaconf-3.3.1/dynaconf/VERSION +0 -1
- {dynaconf-3.3.1 → dynaconf-3.3.2}/CONTRIBUTING.md +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/CONTRIBUTORS.md +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/LICENSE +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/MANIFEST.in +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/README.md +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/RELEASING.md +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/SECURITY.md +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/__main__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/constants.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/contrib/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/contrib/django_dynaconf_v2.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/contrib/flask_dynaconf.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/default_settings.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/hooking.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/base.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/env_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/ini_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/json_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/py_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/redis_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/toml_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/vault_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/loaders/yaml_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/nodes.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/strategies/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/strategies/filtering.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/test_settings.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/typed/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/typed/compat.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/typed/exceptions.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/typed/guards.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/typed/main.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/typed/types.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/typed/utils.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/typed/validators.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/utils/boxing.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/utils/files.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/utils/functional.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/utils/inspect.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/validator.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/validator_conditions.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/box/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/box/box.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/box/box_list.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/box/config_box.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/box/converters.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/box/exceptions.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/box/from_file.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/box/shorthand_box.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/_bashcomplete.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/_compat.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/_termui_impl.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/_textwrap.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/_unicodefun.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/_winconsole.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/core.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/decorators.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/exceptions.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/formatting.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/globals.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/parser.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/termui.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/testing.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/types.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/click/utils.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/dotenv/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/dotenv/cli.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/dotenv/compat.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/dotenv/ipython.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/dotenv/main.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/dotenv/parser.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/dotenv/py.typed +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/dotenv/version.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/anchor.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/comments.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/compat.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/composer.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/configobjwalker.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/constructor.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/cyaml.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/dumper.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/emitter.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/error.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/events.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/main.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/nodes.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/parser.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/py.typed +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/reader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/representer.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/resolver.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/scalarbool.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/scalarfloat.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/scalarint.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/scalarstring.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/scanner.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/serializer.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/setup.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/timestamp.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/tokens.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/ruamel/yaml/util.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/toml/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/toml/decoder.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/toml/encoder.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/toml/ordered.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/toml/tz.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/tomllib/__init__.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/tomllib/_parser.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/tomllib/_re.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/tomllib/_types.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf/vendor/tomllib/_writer.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf.egg-info/SOURCES.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf.egg-info/dependency_links.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf.egg-info/entry_points.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf.egg-info/not-zip-safe +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf.egg-info/requires.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/dynaconf.egg-info/top_level.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/setup.cfg +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_base.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_basic.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_compat.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_django.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_dynabox.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_endtoend.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_env_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_envvar_prefix.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_feature_flag.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_flask.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_hooking.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_ini_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_inspect.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_json_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_loaders.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_nested_loading.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_nodes.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_py_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_redis.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_release_utility.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_settings_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_toml_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_typed.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_validators_conditions.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_vault.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/tests/test_yaml_loader.py +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/vendor_licenses/box-LICENSE.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/vendor_licenses/click-LICENSE.rst +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/vendor_licenses/licenses.sh +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/vendor_licenses/python-dotenv-LICENSE.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/vendor_licenses/ruamel.yaml-LICENSE.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/vendor_licenses/toml-LICENSE.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/vendor_licenses/tomli-LICENSE.txt +0 -0
- {dynaconf-3.3.1 → dynaconf-3.3.2}/vendor_licenses/vendor_versions.txt +0 -0
|
@@ -2,6 +2,31 @@ Changelog
|
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
4
|
<!-- insertion marker -->
|
|
5
|
+
## [3.3.2](https://github.com/dynaconf/dynaconf/releases/tag/3.3.2) - 2026-06-29
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
- Don't treat a string sharing a converter prefix as a cast (#1412). By @sarathfrancis90.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
- Fixed 'dynaconf validate' edge cases with validation_file.toml (#1411). By @pedro-psb.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
- Avoid RecursionError in from_env with validate_on_update (#1409). By @Redbot.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
- Avoid crash merging a dynaconf_merge list into a missing key (#1410). By @sarathfrancis90.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Chore
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
- Fix check-release command from release utility. By @pedro-psb.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
- Improve changelog generation output. By @pedro-psb.
|
|
29
|
+
|
|
5
30
|
## [3.3.1](https://github.com/dynaconf/dynaconf/releases/tag/3.3.1) - 2026-06-26
|
|
6
31
|
|
|
7
32
|
### Bug Fixes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.3.2
|
|
@@ -880,8 +880,9 @@ class Settings:
|
|
|
880
880
|
return self.MAIN_ENV_FOR_DYNACONF.lower()
|
|
881
881
|
|
|
882
882
|
if self.FORCE_ENV_FOR_DYNACONF is not None:
|
|
883
|
-
|
|
884
|
-
|
|
883
|
+
forced = self.FORCE_ENV_FOR_DYNACONF
|
|
884
|
+
self.set("ENV_FOR_DYNACONF", forced, validate=False)
|
|
885
|
+
return forced
|
|
885
886
|
|
|
886
887
|
try:
|
|
887
888
|
return self.loaded_envs[-1]
|
|
@@ -820,9 +820,9 @@ def validate(path): # pragma: no cover
|
|
|
820
820
|
)
|
|
821
821
|
sys.exit(1)
|
|
822
822
|
|
|
823
|
-
# guarantee there is an environment
|
|
824
823
|
validation_data = {k.lower(): v for k, v in validation_data.items()}
|
|
825
|
-
if not
|
|
824
|
+
if not settings.ENVIRONMENTS_FOR_DYNACONF:
|
|
825
|
+
# flat file: top-level keys are field names, not environments
|
|
826
826
|
validation_data = {"default": validation_data}
|
|
827
827
|
|
|
828
828
|
success = True
|
|
@@ -761,7 +761,7 @@ def _parse_conf_data(data, tomlfy=False, box_settings=None):
|
|
|
761
761
|
castenabled
|
|
762
762
|
and data
|
|
763
763
|
and isinstance(data, str)
|
|
764
|
-
and data.
|
|
764
|
+
and data.partition(" ")[0] in converters
|
|
765
765
|
):
|
|
766
766
|
# Check combination token is used
|
|
767
767
|
comb_token = re.match(
|
|
@@ -170,7 +170,6 @@ omit = [
|
|
|
170
170
|
# ======
|
|
171
171
|
|
|
172
172
|
[tool.pytest.ini_options]
|
|
173
|
-
pythonpath = [".github/scripts"]
|
|
174
173
|
markers = [
|
|
175
174
|
"integration: marks tests as integration (deselect with '-m \"not integration\"')",
|
|
176
175
|
]
|
|
@@ -209,7 +208,7 @@ ignore_missing_imports = true
|
|
|
209
208
|
# ===========
|
|
210
209
|
|
|
211
210
|
[tool.bumpversion]
|
|
212
|
-
current_version = "3.3.
|
|
211
|
+
current_version = "3.3.2"
|
|
213
212
|
parse = """(?x)
|
|
214
213
|
(?P<major>0|[1-9]\\d*)\\.
|
|
215
214
|
(?P<minor>0|[1-9]\\d*)\\.
|
|
@@ -311,6 +310,7 @@ lint = [
|
|
|
311
310
|
"typos>=1.42.3",
|
|
312
311
|
]
|
|
313
312
|
test = [
|
|
313
|
+
"dynaconf-release-utility",
|
|
314
314
|
"boto3>=1.40.67",
|
|
315
315
|
"commentjson>=0.9.0",
|
|
316
316
|
"configobj>=5.0.9",
|
|
@@ -342,3 +342,6 @@ release = [
|
|
|
342
342
|
"toml>=0.10.2",
|
|
343
343
|
"twine>=6.2.0",
|
|
344
344
|
]
|
|
345
|
+
|
|
346
|
+
[tool.uv.sources]
|
|
347
|
+
dynaconf-release-utility = { path = ".github/scripts/", editable = true }
|
|
@@ -465,48 +465,86 @@ host = "test.com"
|
|
|
465
465
|
"""
|
|
466
466
|
|
|
467
467
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
468
|
+
class TestValidate:
|
|
469
|
+
def _run_validate(
|
|
470
|
+
self,
|
|
471
|
+
*,
|
|
472
|
+
settings_mod: str,
|
|
473
|
+
validation_file: str,
|
|
474
|
+
env: dict | None = None,
|
|
475
|
+
) -> str:
|
|
476
|
+
return run(
|
|
477
|
+
["-i", settings_mod, "validate", "-p", validation_file], env
|
|
478
|
+
)
|
|
471
479
|
|
|
472
|
-
|
|
473
|
-
|
|
480
|
+
def test_basic(self, create_file):
|
|
481
|
+
validators_toml = create_file("dynaconf_validators.toml", VALIDATION)
|
|
482
|
+
toml_valid = create_file("settings_valid.toml", TOML_VALID)
|
|
483
|
+
toml_invalid = create_file("settings_invalid.toml", TOML_INVALID)
|
|
474
484
|
|
|
475
|
-
|
|
476
|
-
|
|
485
|
+
result = self._run_validate(
|
|
486
|
+
settings_mod="tests.config.settingsenv",
|
|
487
|
+
validation_file=str(validators_toml),
|
|
488
|
+
env={"SETTINGS_FILE_FOR_DYNACONF": str(toml_valid)},
|
|
489
|
+
)
|
|
490
|
+
assert "Validation success!" in result
|
|
477
491
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
"
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
492
|
+
result = self._run_validate(
|
|
493
|
+
settings_mod="tests.test_cli.settings",
|
|
494
|
+
validation_file=str(validators_toml.parent),
|
|
495
|
+
env={"SETTINGS_FILE_FOR_DYNACONF": str(toml_invalid)},
|
|
496
|
+
)
|
|
497
|
+
assert "age must lte 30 but it is 35 in env default" in result
|
|
498
|
+
assert (
|
|
499
|
+
"project must eq hello_world but it is This is not hello_world "
|
|
500
|
+
"in env production" in result
|
|
501
|
+
)
|
|
502
|
+
assert (
|
|
503
|
+
"host must is_not_in ['test.com'] but it is test.com in env "
|
|
504
|
+
"production" in result
|
|
505
|
+
)
|
|
506
|
+
assert "Validation success!" not in result
|
|
489
507
|
|
|
490
|
-
|
|
508
|
+
@pytest.mark.parametrize(
|
|
509
|
+
"environments, expected",
|
|
491
510
|
[
|
|
492
|
-
"-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
511
|
+
pytest.param(True, "Validation error!", id="environments-enabled"),
|
|
512
|
+
pytest.param(
|
|
513
|
+
False, "Validation success!", id="environments-disabled"
|
|
514
|
+
),
|
|
515
|
+
# In this last case, 'main' is considered a regular field, and it doesn't have
|
|
516
|
+
# a validator a must_exist rule. 'staryear' must exist, but if it's
|
|
517
|
+
# parent "main" (not an env here!) doesnt exist, which is fine, the
|
|
518
|
+
# validator doesn't apply. This is the most strict interpretation, and
|
|
519
|
+
# having the 'must_exist' rule propagate, that's it, require 'main' to exist,
|
|
520
|
+
# can be considered a new feature
|
|
497
521
|
],
|
|
498
|
-
{"SETTINGS_FILE_FOR_DYNACONF": str(toml_invalid)},
|
|
499
522
|
)
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
523
|
+
def test_issue_1368(self, create_file, environments: bool, expected: str):
|
|
524
|
+
"""Section-based validators in dynaconf_validators.toml with a non-default section name.
|
|
525
|
+
|
|
526
|
+
https://github.com/dynaconf/dynaconf/issues/1368
|
|
527
|
+
"""
|
|
528
|
+
module = f"config_{environments}"
|
|
529
|
+
create_file(
|
|
530
|
+
f"{module}.py",
|
|
531
|
+
f"""
|
|
532
|
+
from dynaconf import Dynaconf
|
|
533
|
+
settings = Dynaconf(environments={environments})
|
|
534
|
+
""",
|
|
535
|
+
)
|
|
536
|
+
validators_toml = create_file(
|
|
537
|
+
"dynaconf_validators.toml",
|
|
538
|
+
"""
|
|
539
|
+
[main]
|
|
540
|
+
startyear = {must_exist=true}
|
|
541
|
+
""",
|
|
542
|
+
)
|
|
543
|
+
result = self._run_validate(
|
|
544
|
+
settings_mod=f"{module}.settings",
|
|
545
|
+
validation_file=str(validators_toml),
|
|
546
|
+
)
|
|
547
|
+
assert expected in result
|
|
510
548
|
|
|
511
549
|
|
|
512
550
|
def create_file(filename: str | Path, data: str):
|
|
@@ -128,6 +128,39 @@ def test_casting_str(settings):
|
|
|
128
128
|
assert isinstance(res, str) and res == "7"
|
|
129
129
|
|
|
130
130
|
|
|
131
|
+
def test_string_starting_with_converter_prefix_is_not_cast(settings):
|
|
132
|
+
"""A plain string that merely shares a prefix with a converter token
|
|
133
|
+
(e.g. ``@interface`` starts with ``@int``) must be kept verbatim, not
|
|
134
|
+
treated as a cast. Previously this raised ``KeyError``.
|
|
135
|
+
"""
|
|
136
|
+
# these all start with a real converter token as a *prefix* only
|
|
137
|
+
for value in (
|
|
138
|
+
"@interface", # @int
|
|
139
|
+
"@integer", # @int
|
|
140
|
+
"@formatter", # @format
|
|
141
|
+
"@gettext", # @get
|
|
142
|
+
"@uppercase", # @upper
|
|
143
|
+
"@stringify", # @str
|
|
144
|
+
"@noneofthat", # @none
|
|
145
|
+
):
|
|
146
|
+
assert parse_conf_data(value, box_settings=settings) == value
|
|
147
|
+
assert (
|
|
148
|
+
parse_conf_data(value, tomlfy=True, box_settings=settings) == value
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# a prefix collision followed by more words must also pass through
|
|
152
|
+
assert (
|
|
153
|
+
parse_conf_data("@formatter blah", tomlfy=True, box_settings=settings)
|
|
154
|
+
== "@formatter blah"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# real converter tokens must still cast (regression guard)
|
|
158
|
+
assert parse_conf_data("@int 5", box_settings=settings) == 5
|
|
159
|
+
assert parse_conf_data("@none", box_settings=settings) is None
|
|
160
|
+
settings.set("value", 5)
|
|
161
|
+
assert parse_conf_data("@int @format {this.value}")(settings) == 5
|
|
162
|
+
|
|
163
|
+
|
|
131
164
|
def test_casting_int(settings):
|
|
132
165
|
res = parse_conf_data("@int 2")
|
|
133
166
|
assert isinstance(res, int) and res == 2
|
|
@@ -334,6 +367,22 @@ def test_merge_dict_with_meta_values(settings):
|
|
|
334
367
|
assert new == {"A": 1, "C": 4}
|
|
335
368
|
|
|
336
369
|
|
|
370
|
+
def test_merge_list_token_when_key_absent_in_old():
|
|
371
|
+
# A list carrying the `dynaconf_merge` marker must not crash when the key
|
|
372
|
+
# holding it is absent from the existing data (there is nothing to merge
|
|
373
|
+
# into). The marker is consumed and the provided list is kept as-is.
|
|
374
|
+
old = {"existing": 1}
|
|
375
|
+
new = {"ports": [8080, "dynaconf_merge"]}
|
|
376
|
+
object_merge(old, new)
|
|
377
|
+
assert new == {"existing": 1, "ports": [8080]}
|
|
378
|
+
|
|
379
|
+
# Same for the `dynaconf_merge_unique` marker.
|
|
380
|
+
old = {"existing": 1}
|
|
381
|
+
new = {"ports": [8080, "dynaconf_merge_unique"]}
|
|
382
|
+
object_merge(old, new)
|
|
383
|
+
assert new == {"existing": 1, "ports": [8080]}
|
|
384
|
+
|
|
385
|
+
|
|
337
386
|
def test_trimmed_split():
|
|
338
387
|
# No sep
|
|
339
388
|
assert trimmed_split("hello") == ["hello"]
|
|
@@ -921,3 +921,19 @@ def test_validation_after_setenv_or_from_env(tmp_path):
|
|
|
921
921
|
with pytest.raises(ValidationError):
|
|
922
922
|
other_settings = settings.from_env("production")
|
|
923
923
|
other_settings.validators.validate_all()
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
def test_from_env_with_validate_on_update_does_not_recurse():
|
|
927
|
+
"""from_env must not infinitely recurse via current_env -> validation."""
|
|
928
|
+
from dynaconf import Dynaconf
|
|
929
|
+
from dynaconf import Validator
|
|
930
|
+
|
|
931
|
+
settings = Dynaconf(
|
|
932
|
+
environments=True,
|
|
933
|
+
validate_on_update=True,
|
|
934
|
+
validators=[Validator("FOO", default="bar")],
|
|
935
|
+
)
|
|
936
|
+
|
|
937
|
+
# Before the fix this raised RecursionError.
|
|
938
|
+
other_settings = settings.from_env("development")
|
|
939
|
+
assert other_settings.current_env.lower() == "development"
|
dynaconf-3.3.1/dynaconf/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.3.1
|
|
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
|