New Upstream Release - python-dynaconf

Ready changes

Summary

Merged new upstream version: 3.1.12 (was: 3.1.11).

Resulting package

Built on 2023-05-19T06:48 (took 8m31s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases python3-dynaconf

Lintian Result

Diff

diff --git a/3.x-release-notes.md b/3.x-release-notes.md
index a19d9e5..0753c63 100644
--- a/3.x-release-notes.md
+++ b/3.x-release-notes.md
@@ -3,13 +3,13 @@
 In Dynaconf 3.0.0 we introduced some improvements and with
 those improvements it comes some **breaking changes.**
 
-Some of the changes were discussed on the **1st Dynaconf community meeting** [video is available](https://www.twitch.tv/videos/657033043) and [meeting notes #354](https://github.com/rochacbruno/dynaconf/issues/354).
+Some of the changes were discussed on the **1st Dynaconf community meeting** [video is available](https://www.twitch.tv/videos/657033043) and [meeting notes #354](https://github.com/dynaconf/dynaconf/issues/354).
 
 
 ## Improvements
 
-- Validators now implements `|` and `&` operators to allow `Validator() &| Validator()` and has more `operations` available such as `len_eq, len_min, len_max, startswith` [#353](https://github.com/rochacbruno/dynaconf/pull/353).
-- First level variables are now allowed to be `lowercase` it is now possible to access `settings.foo` or `settings.FOO` [#357](https://github.com/rochacbruno/dynaconf/pull/357).
+- Validators now implements `|` and `&` operators to allow `Validator() &| Validator()` and has more `operations` available such as `len_eq, len_min, len_max, startswith` [#353](https://github.com/dynaconf/dynaconf/pull/353).
+- First level variables are now allowed to be `lowercase` it is now possible to access `settings.foo` or `settings.FOO` [#357](https://github.com/dynaconf/dynaconf/pull/357).
 - All Dependencies are now vendored, so when installing Dynaconf is not needed to install any dependency.
 - Dynaconf configuration options are now aliased so when creating an instance of `LazySettings|FlaskDynaconf|DjangoDynaconf` it is now possible to pass instead of `ENVVAR_PREFIX_FOR_DYNACONF` just `envvar_prefix` and this lowercase alias is now accepted.
 - Fixed bugs in `merge` and deprecated the `@reset` token.
@@ -39,7 +39,7 @@ settings = Dynaconf(**options)
 
 and then in your program you do `from project.config import settings` instead of `from dynaconf import settings`.
 
-The `**options` are any of the [dynaconf config options](https://dynaconf.readthedocs.io/en/latest/guides/configuration.html)
+The `**options` are any of the [dynaconf config options](https://www.dynaconf.com/configuration/)
 
 ex:
 
@@ -66,7 +66,7 @@ key = 'value'
 key = 'value'
 ```
 
-**Now starting on 3.0.0** the environments are disabled by default, so the same file can be crated as.
+**Now starting on 3.0.0** the environments are disabled by default, so the same file can be created as.
 
 ```toml
 key = 'value'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e686c8e..7594689 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,576 @@ Changelog
 =========
 
 
+3.1.11 (2022-09-22)
+-------------------
+- Release version 3.1.11. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Bruno Rocha (2):
+            Release version 3.1.10
+            Release hotfix (no need to run coverage or include tests_functional)
+- Release hotfix (no need to run coverage or include tests_functional)
+  [Bruno Rocha]
+- Release version 3.1.10. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Amadou Crookes (1):
+            envars.md typo fix (#786)
+
+      Bruno Rocha (19):
+            Release version 3.1.9
+            Bump dev version to 3.1.10
+            Update badges
+            demo repo will be replaced by a video tutorial soon
+            Fix CI
+            New data key casing must adapt to existing key casing (#795)
+            Add test and docs about includes (#796)
+            Removed vendor_src folder (#798)
+            Replacing rochacbruno/ with dynaconf/ (#800)
+            Fix codecov (#801)
+            Parse negative numbers from envvar Fix #799 and Fix #585 (#802)
+            Fix get command with Django (#804)
+            Add a functional test runner (#805)
+            Test runner docs and styling (#806)
+            Allow merge_unique on lists when merge_enabled=True (#810)
+            Rebind current env when forced for Pytest Fix #728 (#809)
+            AUTO_CAST can be enabled on instance (#811)
+            Ensure pyminify is on release script
+            Add missing tomllib to monify script
+
+      Gaurav Talreja (1):
+            Fix #807 Use client.auth.approle.login instead of client.auth_approle (#808)
+
+      Jitendra Yejare (1):
+            Fix #768 of kv property depreciation from client object (#769)
+
+      Joren Retel (2):
+            Feature/detect casting comb token from converters (#784)
+            Adding documentation and example to makefile. (#791)
+
+      João Gustavo A. Amorim (1):
+            Add pyupgrade hook (#759)
+
+      Kian-Meng Ang (1):
+            Fix typos (#788)
+
+      Lucas Limeira (1):
+            Using filter_strategy in env_loader to fix #760 (#767)
+
+      Nicholas Nadeau, Ph.D., P.Eng (1):
+            fix: typo (#766)
+
+      Oleksii Baranov (2):
+            Bump codecov action version (#775)
+            Fix cli init command for flask (#705) (#774)
+
+      Pedro de Medeiros (1):
+            documentation fixes (#771)
+
+      The Gitter Badger (1):
+            Add a Gitter chat badge to README.md (#776)
+
+      Théo Melo (1):
+            Fixing a typo on the readme file (#763)
+
+      Vicente Marçal (1):
+            docs(pt-br): Docs Translation to brazilian portugues. (#787)
+
+
+3.1.10 (2022-09-22)
+-------------------
+
+Fix
+~~~
+- Typo (#766) [Bruno Rocha, Nicholas Nadeau, Ph.D., P.Eng]
+
+Other
+~~~~~
+- Release version 3.1.10. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Amadou Crookes (1):
+            envars.md typo fix (#786)
+
+      Bruno Rocha (19):
+            Release version 3.1.9
+            Bump dev version to 3.1.10
+            Update badges
+            demo repo will be replaced by a video tutorial soon
+            Fix CI
+            New data key casing must adapt to existing key casing (#795)
+            Add test and docs about includes (#796)
+            Removed vendor_src folder (#798)
+            Replacing rochacbruno/ with dynaconf/ (#800)
+            Fix codecov (#801)
+            Parse negative numbers from envvar Fix #799 and Fix #585 (#802)
+            Fix get command with Django (#804)
+            Add a functional test runner (#805)
+            Test runner docs and styling (#806)
+            Allow merge_unique on lists when merge_enabled=True (#810)
+            Rebind current env when forced for Pytest Fix #728 (#809)
+            AUTO_CAST can be enabled on instance (#811)
+            Ensure pyminify is on release script
+            Add missing tomllib to monify script
+
+      Gaurav Talreja (1):
+            Fix #807 Use client.auth.approle.login instead of client.auth_approle (#808)
+
+      Jitendra Yejare (1):
+            Fix #768 of kv property depreciation from client object (#769)
+
+      Joren Retel (2):
+            Feature/detect casting comb token from converters (#784)
+            Adding documentation and example to makefile. (#791)
+
+      João Gustavo A. Amorim (1):
+            Add pyupgrade hook (#759)
+
+      Kian-Meng Ang (1):
+            Fix typos (#788)
+
+      Lucas Limeira (1):
+            Using filter_strategy in env_loader to fix #760 (#767)
+
+      Nicholas Nadeau, Ph.D., P.Eng (1):
+            fix: typo (#766)
+
+      Oleksii Baranov (2):
+            Bump codecov action version (#775)
+            Fix cli init command for flask (#705) (#774)
+
+      Pedro de Medeiros (1):
+            documentation fixes (#771)
+
+      The Gitter Badger (1):
+            Add a Gitter chat badge to README.md (#776)
+
+      Théo Melo (1):
+            Fixing a typo on the readme file (#763)
+
+      Vicente Marçal (1):
+            docs(pt-br): Docs Translation to brazilian portugues. (#787)
+- Add missing tomllib to monify script. [Bruno Rocha]
+- Ensure pyminify is on release script. [Bruno Rocha]
+- AUTO_CAST can be enabled on instance (#811) [Bruno Rocha]
+
+  Fix #772
+- Rebind current env when forced for Pytest Fix #728 (#809) [Bruno
+  Rocha]
+- Allow merge_unique on lists when merge_enabled=True (#810) [Bruno
+  Rocha]
+
+  Fix #726
+- Fix #807 Use client.auth.approle.login instead of client.auth_approle
+  (#808) [Gaurav Talreja]
+- Fix typos (#788) [Kian-Meng Ang]
+
+  Found via this command:
+
+      codespell -S "./dynaconf/vendor/*,./docs/pt-br/*,./.mypy_cache/*,*.svg" -L hashi
+- Test runner docs and styling (#806) [Bruno Rocha]
+
+  * Test runner docs and styling
+
+  * No emojis on windows
+- Add a functional test runner (#805) [Bruno Rocha]
+
+  * Add a functional test runner
+
+  * Renamed example/ to tests_functional/
+- Fix get command with Django (#804) [Bruno Rocha]
+
+  Fix #789
+- Parse negative numbers from envvar Fix #799 and Fix #585 (#802) [Bruno
+  Rocha]
+- Fix codecov (#801) [Bruno Rocha]
+
+  * Fix codecov
+
+  * call coverage xml
+- Replacing rochacbruno/ with dynaconf/ (#800) [Bruno Rocha]
+
+  * Replacing rochacbruno/ with dynaconf/
+
+  * xscode doesn't exist anymore
+- Removed vendor_src folder (#798) [Bruno Rocha]
+
+  * Removed vendor_src folder
+
+  Now `vendor` is the source
+  and minification happens during release process.
+
+  * Added tomllib (vendored) as a replacement for toml fix #708
+
+  toml kept as a fallback until 4.0.0 to nor break compatibility
+
+  - toml follows 0.5.0 spec
+  - tomlib follows 1.0.0 spec
+  - toml allows emojis and unicode chars unencoded
+  - tomllib foolows the spec where only encoded chars are allowed
+- Add test and docs about includes (#796) [Bruno Rocha]
+
+  closes #794
+- New data key casing must adapt to existing key casing (#795) [Bruno
+  Rocha]
+
+  Fix #737
+- Docs(pt-br): Docs Translation to brazilian portugues. (#787) [Vicente
+  Marçal]
+- Adding documentation and example to makefile. (#791) [Joren Retel]
+
+  * Adding documentation and example to makefile.
+
+  * Put header one level down in  docs.
+- Feature/detect casting comb token from converters (#784) [Joren Retel]
+- Envars.md typo fix (#786) [Amadou Crookes]
+- Fix CI. [Bruno Rocha]
+- Demo repo will be replaced by a video tutorial soon. [Bruno Rocha]
+- Update badges. [Bruno Rocha]
+- Documentation fixes (#771) [Bruno Rocha, Pedro de Medeiros]
+- Add a Gitter chat badge to README.md (#776) [Bruno Rocha, The Gitter
+  Badger]
+- Fix cli init command for flask (#705) (#774) [Bruno Rocha, Oleksii
+  Baranov]
+- Bump codecov action version (#775) [Oleksii Baranov]
+- Fix #768 of kv property depreciation from client object (#769)
+  [Jitendra Yejare]
+- Using filter_strategy in env_loader to fix #760 (#767) [Lucas Limeira]
+- Fixing a typo on the readme file (#763) [Théo Melo]
+- Add pyupgrade hook (#759) [João Gustavo A. Amorim]
+
+  * update hooks and add pyupgrade
+
+  * updates by pyupgrade
+
+  * remove unused typing imports
+
+  * add `from __future__ import annotations` across the codebase
+
+  * add `from __future__ import annotations` in examples
+- Bump dev version to 3.1.10. [Bruno Rocha]
+- Release version 3.1.9. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Bruno Rocha (4):
+            Release version 3.1.8
+            Bye py 3.7
+            Multiple fixes for 3.19 (#756)
+            update docs site (#758)
+
+      João Gustavo A. Amorim (1):
+            Organize pre-commit setup (#757)
+
+      dependabot[bot] (1):
+            Bump django from 2.2.27 to 2.2.28 in /example/django_pytest_pure (#743)
+
+
+3.1.9 (2022-06-06)
+------------------
+- Release version 3.1.9. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Bruno Rocha (4):
+            Release version 3.1.8
+            Bye py 3.7
+            Multiple fixes for 3.19 (#756)
+            update docs site (#758)
+
+      João Gustavo A. Amorim (1):
+            Organize pre-commit setup (#757)
+
+      dependabot[bot] (1):
+            Bump django from 2.2.27 to 2.2.28 in /example/django_pytest_pure (#743)
+- Update docs site (#758) [Bruno Rocha]
+- Organize pre-commit setup (#757) [João Gustavo A. Amorim]
+- Multiple fixes for 3.19 (#756) [Bruno Rocha]
+- Bump django from 2.2.27 to 2.2.28 in /example/django_pytest_pure
+  (#743) [dependabot[bot], dependabot[bot]]
+- Bye py 3.7. [Bruno Rocha]
+- Release version 3.1.8. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Anderson Sousa (1):
+            Document the usage with python -m (#710)
+
+      Andressa Cabistani (2):
+            Add unique label when merging lists to fix issue #653 (#661)
+            Add new validation to fix issue #585 (#667)
+
+      Armin Berres (1):
+            Fix typo in error message
+
+      Bruno Rocha (7):
+            Release version 3.1.7
+            Found this bug that was duplicating the generated envlist (#663)
+            Add support for Python 3.10 (#665)
+            Attempt to fix #555 (#669)
+            Create update_contributors.yml
+            Fixing pre-coomit and docs CI
+            Added `dynaconf get` command to cli (#730)
+
+      Caneco (2):
+            improvement: add brand new logo to the project (#686)
+            improvement: update socialcard to match the python way (#687)
+
+      EdwardCuiPeacock (2):
+            Feature: add @jinja and @format casting (#704)
+            Combo converter doc (#735)
+
+      Eitan Mosenkis (1):
+            Fix FlaskConfig.setdefault (#706)
+
+      Enderson Menezes (Mr. Enderson) (2):
+            Force PYTHONIOENCODING to utf-8 to fix #664 (#672)
+            edit: move discussions to github tab (#682)
+
+      Eugene Triguba (1):
+            Fix custom prefix link in envvar documentation (#680)
+
+      Gibran Herrera (1):
+            Fix Issue 662 Lazy validation (#675)
+
+      Jitendra Yejare (2):
+            Load vault secrets from environment less stores or which are not written by dynaconf (#725)
+            Use default value when settings is blank (#729)
+
+      Pavel Alimpiev (1):
+            Update docs link (#678)
+
+      Ugo Benassayag (1):
+            Added validate_only_current_env to validator (issue #734) (#736)
+
+      Waylon Walker (1):
+            Docs Fix Spelling (#696)
+
+      dependabot[bot] (3):
+            Bump django from 2.1.5 to 2.2.26 in /example/django_pytest_pure (#711)
+            Bump mkdocs from 1.1.2 to 1.2.3 (#715)
+            Bump django from 2.2.26 to 2.2.27 in /example/django_pytest_pure (#717)
+
+      github-actions[bot] (2):
+            [automated] Update Contributors File (#691)
+            [automated] Update Contributors File (#732)
+
+      lowercase00 (1):
+            Makes Django/Flask kwargs case insensitive (#721)
+
+
+3.1.8 (2022-04-15)
+------------------
+- Release version 3.1.8. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Anderson Sousa (1):
+            Document the usage with python -m (#710)
+
+      Andressa Cabistani (2):
+            Add unique label when merging lists to fix issue #653 (#661)
+            Add new validation to fix issue #585 (#667)
+
+      Armin Berres (1):
+            Fix typo in error message
+
+      Bruno Rocha (7):
+            Release version 3.1.7
+            Found this bug that was duplicating the generated envlist (#663)
+            Add support for Python 3.10 (#665)
+            Attempt to fix #555 (#669)
+            Create update_contributors.yml
+            Fixing pre-coomit and docs CI
+            Added `dynaconf get` command to cli (#730)
+
+      Caneco (2):
+            improvement: add brand new logo to the project (#686)
+            improvement: update socialcard to match the python way (#687)
+
+      EdwardCuiPeacock (2):
+            Feature: add @jinja and @format casting (#704)
+            Combo converter doc (#735)
+
+      Eitan Mosenkis (1):
+            Fix FlaskConfig.setdefault (#706)
+
+      Enderson Menezes (Mr. Enderson) (2):
+            Force PYTHONIOENCODING to utf-8 to fix #664 (#672)
+            edit: move discussions to github tab (#682)
+
+      Eugene Triguba (1):
+            Fix custom prefix link in envvar documentation (#680)
+
+      Gibran Herrera (1):
+            Fix Issue 662 Lazy validation (#675)
+
+      Jitendra Yejare (2):
+            Load vault secrets from environment less stores or which are not written by dynaconf (#725)
+            Use default value when settings is blank (#729)
+
+      Pavel Alimpiev (1):
+            Update docs link (#678)
+
+      Ugo Benassayag (1):
+            Added validate_only_current_env to validator (issue #734) (#736)
+
+      Waylon Walker (1):
+            Docs Fix Spelling (#696)
+
+      dependabot[bot] (3):
+            Bump django from 2.1.5 to 2.2.26 in /example/django_pytest_pure (#711)
+            Bump mkdocs from 1.1.2 to 1.2.3 (#715)
+            Bump django from 2.2.26 to 2.2.27 in /example/django_pytest_pure (#717)
+
+      github-actions[bot] (2):
+            [automated] Update Contributors File (#691)
+            [automated] Update Contributors File (#732)
+
+      lowercase00 (1):
+            Makes Django/Flask kwargs case insensitive (#721)
+- Combo converter doc (#735) [EdwardCuiPeacock]
+- Added validate_only_current_env to validator (issue #734) (#736) [Ugo
+  Benassayag, Ugo Benassayag]
+- [automated] Update Contributors File (#732) [github-actions[bot],
+  rochacbruno]
+- Added `dynaconf get` command to cli (#730) [Bruno Rocha]
+- Fixing pre-coomit and docs CI. [Bruno Rocha]
+- Fix typo in error message. [Armin Berres]
+
+  It is, e.g., REDIS_HOST_FOR_DYNACONF - not REDIS_FOR_DYNACONF_HOST.
+- Bump django from 2.2.26 to 2.2.27 in /example/django_pytest_pure
+  (#717) [Bruno Rocha, dependabot[bot], dependabot[bot]]
+- Bump mkdocs from 1.1.2 to 1.2.3 (#715) [Bruno Rocha, dependabot[bot],
+  dependabot[bot]]
+- Fix custom prefix link in envvar documentation (#680) [Andressa
+  Cabistani, Bruno Rocha, Eugene Triguba]
+- Use default value when settings is blank (#729) [Bruno Rocha, Jitendra
+  Yejare]
+- Load vault secrets from environment less stores or which are not
+  written by dynaconf (#725) [Jitendra Yejare]
+- Makes Django/Flask kwargs case insensitive (#721) [lowercase00]
+- Docs Fix Spelling (#696) [Bruno Rocha, Waylon Walker]
+- Bump django from 2.1.5 to 2.2.26 in /example/django_pytest_pure (#711)
+  [Bruno Rocha, dependabot[bot], dependabot[bot]]
+- [automated] Update Contributors File (#691) [github-actions[bot],
+  rochacbruno]
+- Feature: add @jinja and @format casting (#704) [Bruno Rocha,
+  EdwardCuiPeacock]
+- Document the usage with python -m (#710) [Anderson Sousa, Bruno Rocha]
+- Fix FlaskConfig.setdefault (#706) [Eitan Mosenkis]
+- Create update_contributors.yml. [Bruno Rocha]
+- Improvement: update socialcard to match the python way (#687) [Caneco]
+- Improvement: add brand new logo to the project (#686) [Caneco]
+- Edit: move discussions to github tab (#682) [Enderson Menezes (Mr.
+  Enderson)]
+- Update docs link (#678) [Pavel Alimpiev]
+
+  * Replace an old Django-related link with a new one
+
+  * Update docs link
+- Fix Issue 662 Lazy validation (#675) [Gibran Herrera]
+- Force PYTHONIOENCODING to utf-8 to fix #664 (#672) [Enderson Menezes
+  (Mr. Enderson)]
+- Attempt to fix #555 (#669) [Bruno Rocha]
+- Add new validation to fix issue #585 (#667) [Andressa Cabistani,
+  andressa.cabistani]
+- Add support for Python 3.10 (#665) [Bruno Rocha]
+
+  Python 3.10 supported and tested
+- Found this bug that was duplicating the generated envlist (#663)
+  [Bruno Rocha]
+- Add unique label when merging lists to fix issue #653 (#661) [Andressa
+  Cabistani, andressa.cabistani]
+- Release version 3.1.7. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Bruno Rocha (2):
+            Release version 3.1.6
+            Add missing docs and missing python_requires (#659)
+
+
+3.1.7 (2021-09-09)
+------------------
+- Release version 3.1.7. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Bruno Rocha (2):
+            Release version 3.1.6
+            Add missing docs and missing python_requires (#659)
+- Add missing docs and missing python_requires (#659) [Bruno Rocha]
+- Release version 3.1.6. [Bruno Rocha]
+
+  Shortlog of commits since last release:
+
+      Ambient Lighter (1):
+            Fix typo (#647)
+
+      Bruno Rocha (19):
+            Release version 3.1.4
+            demo link (#546)
+            removed release_notes from the docs. (#550)
+            HOTFIX: Add coverage for 2 lines on validators.
+            Fix #595 namedtuples are no more converted to BoxList (#623)
+            Fix black issues (#631)
+            Update FUNDING.yml
+            description and type annotation for validator (#634)
+            Add myoy and pre-commit to CI (#635)
+            Update codaci badge (#636)
+            Remove dependabot (this project has no dependencies)
+            fix #596 django override (#645)
+            fix #491 pytest django Fix #491 pytest and django (#646)
+            Delete requirements.txt
+            Update FUNDING.yml
+            Add support for dynaconf_hooks(post) issue #654 (#655)
+            Move to Github Actions (#656)
+            Bye Azure (#657)
+            Bump dev version
+
+      FrankBattaglia (1):
+            fix dict iterator methods for flask DynaconfConfig (#581)
+
+      Jacob Callahan (1):
+            Add the ability for selective validation (#549)
+
+      Kamil Gałuszka (1):
+            Add support for Python 3.9 and remove Ubuntu 16.04 that is deprecated in Azure Pipelines (#618)
+
+      Konstantin (2):
+            Update configuration.md (#553)
+            Update configuration.md (#554)
+
+      Linus Torvalds (1):
+            Fix a typo in the docs
+
+      Martin Thoma (1):
+            Add type annotations for dynaconf.utils (#450)
+
+      Nicholas Dentandt (1):
+            feat: add filter strategy with PrefixFilter (#625)
+
+      Robert Rosca (1):
+            Add a warning if `--env` is passed to `init` (#629)
+
+      Tanya Tereshchenko (1):
+            Do not search anywhere if the absolute path to a file provided (#570)
+
+      Yusuf Kaka (1):
+            Added an example using FastAPI (#571)
+
+      dependabot-preview[bot] (2):
+            Bump mkdocs-material from 7.0.5 to 7.0.6 (#552)
+            Upgrade to GitHub-native Dependabot (#574)
+
+      puntonim (1):
+            Fix typo (#588)
+
+
 3.1.6 (2021-09-09)
 ------------------
 - Release version 3.1.6. [Bruno Rocha]
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e009cca..7cde113 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -14,7 +14,7 @@ This Diagram can help you understand visually what happens on Dynaconf: https://
    2. Activate a python3.6+ virtualenv
    3. Code
 2. Update the `docs/guides/` related to your changes.
-3. Update `example/` (editing or adding a new one related to your changes)
+3. Update `tests_functional/` (editing or adding a new one related to your changes)
 4. Ensure tests are passing (see below `make all`)
    1. This project uses `pre-commit` and `Black` for code styling and adequacy tests.
 5. Commit, Push and make a Pull Request!
@@ -27,7 +27,7 @@ This Diagram can help you understand visually what happens on Dynaconf: https://
 git clone git@github.com:{$USER}/dynaconf.git
 
 # Add the upstream remote
-git remote add upstream https://github.com/rochacbruno/dynaconf.git
+git remote add upstream https://github.com/dynaconf/dynaconf.git
 
 # Activate your Python Environment
 python3.7 -m venv venv
@@ -47,8 +47,8 @@ git fetch upstream; git rebase upstream/master
 # Fix any conflicts if any.
 
 # Update docs/guides/ if needed
-# Edit example/ if needed
-# Create a new app in example/{your_example} and add it to Makefile.
+# Edit tests_functional/ if needed
+# Create a new app in tests_functional/{your_example} and add it to Makefile.
 
 # Then ensure everything is ok
 make all
@@ -59,7 +59,7 @@ git commit -am "Changed XPTO to fix #issue_number"
 # Push to your own fork
 git push -u origin HEAD
 
-# Open github.com/rochacbruno/dynaconf and send a Pull Request.
+# Open github.com/dynaconf/dynaconf and send a Pull Request.
 ```
 
 ### Run integration tests
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
new file mode 100644
index 0000000..a6de01e
--- /dev/null
+++ b/CONTRIBUTORS.md
@@ -0,0 +1,34 @@
+# Contributors
+
+Shout out to our top contributors!
+
+- [rochacbruno](https://api.github.com/users/rochacbruno)
+- [douglas](https://api.github.com/users/douglas)
+- [dependabot-preview[bot]](https://api.github.com/users/dependabot-preview%5Bbot%5D)
+- [jperras](https://api.github.com/users/jperras)
+- [janw](https://api.github.com/users/janw)
+- [hilam](https://api.github.com/users/hilam)
+- [VaultVulp](https://api.github.com/users/VaultVulp)
+- [gpkc](https://api.github.com/users/gpkc)
+- [ilitotor](https://api.github.com/users/ilitotor)
+- [kedark3](https://api.github.com/users/kedark3)
+- [sirex](https://api.github.com/users/sirex)
+- [dependabot[bot]](https://api.github.com/users/dependabot%5Bbot%5D)
+- [dgarcia360](https://api.github.com/users/dgarcia360)
+- [rsnyman](https://api.github.com/users/rsnyman)
+- [andressadotpy](https://api.github.com/users/andressadotpy)
+- [Bernardoow](https://api.github.com/users/Bernardoow)
+- [caneco](https://api.github.com/users/caneco)
+- [dmsimard](https://api.github.com/users/dmsimard)
+- [Sytten](https://api.github.com/users/Sytten)
+- [endersonmenezes](https://api.github.com/users/endersonmenezes)
+- [FrankBattaglia](https://api.github.com/users/FrankBattaglia)
+- [jyejare](https://api.github.com/users/jyejare)
+- [pheanex](https://api.github.com/users/pheanex)
+- [chobeat](https://api.github.com/users/chobeat)
+- [tanalam2411](https://api.github.com/users/tanalam2411)
+- [mspinelli](https://api.github.com/users/mspinelli)
+- [cassiobotaro](https://api.github.com/users/cassiobotaro)
+- [mirekdlugosz](https://api.github.com/users/mirekdlugosz)
+- [adevore](https://api.github.com/users/adevore)
+- [AmbientLighter](https://api.github.com/users/AmbientLighter)
diff --git a/MANIFEST.in b/MANIFEST.in
index 448ac1e..b1638fa 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,4 +3,5 @@ include *.png
 include LICENSE
 include VERSION
 include dynaconf/VERSION
+recursive-include vendor_licenses **
 prune dynaconf/vendor_src
diff --git a/PKG-INFO b/PKG-INFO
index 22dcf73..1629de8 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,8 +1,8 @@
 Metadata-Version: 2.1
 Name: dynaconf
-Version: 3.1.7
+Version: 3.1.12
 Summary: The dynamic configurator for your Python Project
-Home-page: https://github.com/rochacbruno/dynaconf
+Home-page: https://github.com/dynaconf/dynaconf
 Author: Bruno Rocha
 Author-email: rochacbruno@gmail.com
 License: MIT
@@ -17,13 +17,14 @@ Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
 Classifier: Topic :: Utilities
 Classifier: Topic :: Software Development :: Libraries
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Requires-Python: >=3.7
+Requires-Python: >=3.8
 Description-Content-Type: text/markdown
 Provides-Extra: redis
 Provides-Extra: vault
@@ -32,17 +33,26 @@ Provides-Extra: toml
 Provides-Extra: ini
 Provides-Extra: configobj
 Provides-Extra: all
+Provides-Extra: test
 License-File: LICENSE
+License-File: vendor_licenses/box-LICENSE.txt
+License-File: vendor_licenses/click-LICENSE.rst
+License-File: vendor_licenses/licenses.sh
+License-File: vendor_licenses/python-dotenv-LICENSE.txt
+License-File: vendor_licenses/ruamel.yaml-LICENSE.txt
+License-File: vendor_licenses/toml-LICENSE.txt
+License-File: vendor_licenses/tomli-LICENSE.txt
+License-File: vendor_licenses/vendor_versions.txt
 
-[![Dynaconf](docs/img/logo_400.svg?sanitize=true)](http://dynaconf.com)
+<!-- [![Dynaconf](docs/img/logo_400.svg?sanitize=true)](http://dynaconf.com) -->
 
-> **dynaconf** - Configuration Management for Python.
-
-[![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) [![PyPI](https://img.shields.io/pypi/v/dynaconf.svg)](https://pypi.python.org/pypi/dynaconf) [![PyPI](https://img.shields.io/pypi/pyversions/dynaconf.svg)]() ![PyPI - Downloads](https://img.shields.io/pypi/dm/dynaconf.svg?label=pip%20installs&logo=python) [![CI](https://github.com/rochacbruno/dynaconf/actions/workflows/main.yml/badge.svg)](https://github.com/rochacbruno/dynaconf/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/rochacbruno/dynaconf/branch/master/graph/badge.svg)](https://codecov.io/gh/rochacbruno/dynaconf) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/42d2f11ef0a446808b246c8c69603f6e)](https://www.codacy.com/gh/rochacbruno/dynaconf/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=rochacbruno/dynaconf&amp;utm_campaign=Badge_Grade) ![GitHub issues](https://img.shields.io/github/issues/rochacbruno/dynaconf.svg) ![GitHub stars](https://img.shields.io/github/stars/rochacbruno/dynaconf.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/rochacbruno/dynaconf.svg) ![GitHub commits since latest release](https://img.shields.io/github/commits-since/rochacbruno/dynaconf/latest.svg) ![GitHub last commit](https://img.shields.io/github/last-commit/rochacbruno/dynaconf.svg) [![Code Style Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black/) [![Discussion](https://img.shields.io/badge/chat-discussions-blue.svg?logo=googlechat)](https://github.com/rochacbruno/dynaconf/discussions) [![Discussion](https://img.shields.io/badge/demo-learn-yellow.svg?logo=gnubash)](https://github.com/rochacbruno/learndynaconf)
+<p align="center"><img src="/art/header.png?v2" alt="dynaconf. new logo"></p>
 
+> **dynaconf** - Configuration Management for Python.
 
+[![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) [![PyPI](https://img.shields.io/pypi/v/dynaconf.svg)](https://pypi.python.org/pypi/dynaconf) [![PyPI](https://img.shields.io/pypi/pyversions/dynaconf.svg)]() ![PyPI - Downloads](https://img.shields.io/pypi/dm/dynaconf.svg?label=pip%20installs&logo=python) [![CI](https://github.com/dynaconf/dynaconf/actions/workflows/main.yml/badge.svg)](https://github.com/dynaconf/dynaconf/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/dynaconf/dynaconf/branch/master/graph/badge.svg)](https://codecov.io/gh/dynaconf/dynaconf) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/3fb2de98464442f99a7663181803b400)](https://www.codacy.com/gh/dynaconf/dynaconf/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=dynaconf/dynaconf&amp;utm_campaign=Badge_Grade)  ![GitHub stars](https://img.shields.io/github/stars/dynaconf/dynaconf.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/dynaconf/dynaconf.svg) ![GitHub commits since latest release](https://img.shields.io/github/commits-since/dynaconf/dynaconf/latest.svg) ![GitHub last commit](https://img.shields.io/github/last-commit/dynaconf/dynaconf.svg) [![Code Style Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black/)
 
-[![Foo](https://xscode.com/assets/promo-banner.svg)](https://xscode.com/rochacbruno/dynaconf)
+![GitHub issues](https://img.shields.io/github/issues/dynaconf/dynaconf.svg) [![User Forum](https://img.shields.io/badge/users-forum-blue.svg?logo=googlechat)](https://github.com/dynaconf/dynaconf/discussions) [![Join the chat at https://gitter.im/dynaconf/dev](https://badges.gitter.im/dynaconf/dev.svg)](https://gitter.im/dynaconf/dev?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![ Matrix](https://img.shields.io/badge/dev-room-blue.svg?logo=matrix)](https://matrix.to/#/#dynaconf:matrix.org)
 
 ## Features
 
@@ -57,11 +67,6 @@ License-File: LICENSE
 - CLI for common operations such as `init, list, write, validate, export`.
 - full docs on https://dynaconf.com
 
-## Quick start
-
-> **DEMO:** You can see a working demo here: https://github.com/rochacbruno/learndynaconf
-
-
 ### Install
 
 ```bash
@@ -97,7 +102,7 @@ $ dynaconf init -f toml
 .
 ├── config.py       # This is from where you import your settings object (required)
 ├── .secrets.toml   # This is to hold sensitive data like passwords and tokens (optional)
-└── settings.toml   # This is to hold your application setttings (optional)
+└── settings.toml   # This is to hold your application settings (optional)
 ```
 
 On the file `config.py` Dynaconf init generates the following boilerpate
@@ -168,10 +173,10 @@ There is a lot more you can do, **read the docs:** http://dynaconf.com
 
 ## Contribute
 
-Main discussions happens on [t.me/dynaconf](https://t.me/dynaconf) learn more about how to get involved on [CONTRIBUTING.md guide](CONTRIBUTING.md)
+Main discussions happens on [Discussions Tab](https://github.com/dynaconf/dynaconf/discussions) learn more about how to get involved on [CONTRIBUTING.md guide](CONTRIBUTING.md)
 
-
-## more
+## More
 
 If you are looking for something similar to Dynaconf to use in your Rust projects: https://github.com/rubik/hydroconf
 
+And a special thanks to [Caneco](https://twitter.com/caneco) for the logo.
diff --git a/README.md b/README.md
index 6a71d06..24cacd9 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,12 @@
-[![Dynaconf](docs/img/logo_400.svg?sanitize=true)](http://dynaconf.com)
+<!-- [![Dynaconf](docs/img/logo_400.svg?sanitize=true)](http://dynaconf.com) -->
 
-> **dynaconf** - Configuration Management for Python.
-
-[![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) [![PyPI](https://img.shields.io/pypi/v/dynaconf.svg)](https://pypi.python.org/pypi/dynaconf) [![PyPI](https://img.shields.io/pypi/pyversions/dynaconf.svg)]() ![PyPI - Downloads](https://img.shields.io/pypi/dm/dynaconf.svg?label=pip%20installs&logo=python) [![CI](https://github.com/rochacbruno/dynaconf/actions/workflows/main.yml/badge.svg)](https://github.com/rochacbruno/dynaconf/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/rochacbruno/dynaconf/branch/master/graph/badge.svg)](https://codecov.io/gh/rochacbruno/dynaconf) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/42d2f11ef0a446808b246c8c69603f6e)](https://www.codacy.com/gh/rochacbruno/dynaconf/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=rochacbruno/dynaconf&amp;utm_campaign=Badge_Grade) ![GitHub issues](https://img.shields.io/github/issues/rochacbruno/dynaconf.svg) ![GitHub stars](https://img.shields.io/github/stars/rochacbruno/dynaconf.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/rochacbruno/dynaconf.svg) ![GitHub commits since latest release](https://img.shields.io/github/commits-since/rochacbruno/dynaconf/latest.svg) ![GitHub last commit](https://img.shields.io/github/last-commit/rochacbruno/dynaconf.svg) [![Code Style Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black/) [![Discussion](https://img.shields.io/badge/chat-discussions-blue.svg?logo=googlechat)](https://github.com/rochacbruno/dynaconf/discussions) [![Discussion](https://img.shields.io/badge/demo-learn-yellow.svg?logo=gnubash)](https://github.com/rochacbruno/learndynaconf)
+<p align="center"><img src="/art/header.png?v2" alt="dynaconf. new logo"></p>
 
+> **dynaconf** - Configuration Management for Python.
 
+[![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) [![PyPI](https://img.shields.io/pypi/v/dynaconf.svg)](https://pypi.python.org/pypi/dynaconf) [![PyPI](https://img.shields.io/pypi/pyversions/dynaconf.svg)]() ![PyPI - Downloads](https://img.shields.io/pypi/dm/dynaconf.svg?label=pip%20installs&logo=python) [![CI](https://github.com/dynaconf/dynaconf/actions/workflows/main.yml/badge.svg)](https://github.com/dynaconf/dynaconf/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/dynaconf/dynaconf/branch/master/graph/badge.svg)](https://codecov.io/gh/dynaconf/dynaconf) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/3fb2de98464442f99a7663181803b400)](https://www.codacy.com/gh/dynaconf/dynaconf/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=dynaconf/dynaconf&amp;utm_campaign=Badge_Grade)  ![GitHub stars](https://img.shields.io/github/stars/dynaconf/dynaconf.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/dynaconf/dynaconf.svg) ![GitHub commits since latest release](https://img.shields.io/github/commits-since/dynaconf/dynaconf/latest.svg) ![GitHub last commit](https://img.shields.io/github/last-commit/dynaconf/dynaconf.svg) [![Code Style Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black/)
 
-[![Foo](https://xscode.com/assets/promo-banner.svg)](https://xscode.com/rochacbruno/dynaconf)
+![GitHub issues](https://img.shields.io/github/issues/dynaconf/dynaconf.svg) [![User Forum](https://img.shields.io/badge/users-forum-blue.svg?logo=googlechat)](https://github.com/dynaconf/dynaconf/discussions) [![Join the chat at https://gitter.im/dynaconf/dev](https://badges.gitter.im/dynaconf/dev.svg)](https://gitter.im/dynaconf/dev?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![ Matrix](https://img.shields.io/badge/dev-room-blue.svg?logo=matrix)](https://matrix.to/#/#dynaconf:matrix.org)
 
 ## Features
 
@@ -21,11 +21,6 @@
 - CLI for common operations such as `init, list, write, validate, export`.
 - full docs on https://dynaconf.com
 
-## Quick start
-
-> **DEMO:** You can see a working demo here: https://github.com/rochacbruno/learndynaconf
-
-
 ### Install
 
 ```bash
@@ -61,7 +56,7 @@ $ dynaconf init -f toml
 .
 ├── config.py       # This is from where you import your settings object (required)
 ├── .secrets.toml   # This is to hold sensitive data like passwords and tokens (optional)
-└── settings.toml   # This is to hold your application setttings (optional)
+└── settings.toml   # This is to hold your application settings (optional)
 ```
 
 On the file `config.py` Dynaconf init generates the following boilerpate
@@ -132,9 +127,10 @@ There is a lot more you can do, **read the docs:** http://dynaconf.com
 
 ## Contribute
 
-Main discussions happens on [t.me/dynaconf](https://t.me/dynaconf) learn more about how to get involved on [CONTRIBUTING.md guide](CONTRIBUTING.md)
-
+Main discussions happens on [Discussions Tab](https://github.com/dynaconf/dynaconf/discussions) learn more about how to get involved on [CONTRIBUTING.md guide](CONTRIBUTING.md)
 
-## more
+## More
 
 If you are looking for something similar to Dynaconf to use in your Rust projects: https://github.com/rubik/hydroconf
+
+And a special thanks to [Caneco](https://twitter.com/caneco) for the logo.
diff --git a/debian/changelog b/debian/changelog
index 88b6c60..18034db 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+python-dynaconf (3.1.12-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Fri, 19 May 2023 06:41:15 -0000
+
 python-dynaconf (3.1.7-2) unstable; urgency=medium
 
   [ Debian Janitor ]
diff --git a/dynaconf.egg-info/PKG-INFO b/dynaconf.egg-info/PKG-INFO
index 22dcf73..1629de8 100644
--- a/dynaconf.egg-info/PKG-INFO
+++ b/dynaconf.egg-info/PKG-INFO
@@ -1,8 +1,8 @@
 Metadata-Version: 2.1
 Name: dynaconf
-Version: 3.1.7
+Version: 3.1.12
 Summary: The dynamic configurator for your Python Project
-Home-page: https://github.com/rochacbruno/dynaconf
+Home-page: https://github.com/dynaconf/dynaconf
 Author: Bruno Rocha
 Author-email: rochacbruno@gmail.com
 License: MIT
@@ -17,13 +17,14 @@ Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
 Classifier: Topic :: Utilities
 Classifier: Topic :: Software Development :: Libraries
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Requires-Python: >=3.7
+Requires-Python: >=3.8
 Description-Content-Type: text/markdown
 Provides-Extra: redis
 Provides-Extra: vault
@@ -32,17 +33,26 @@ Provides-Extra: toml
 Provides-Extra: ini
 Provides-Extra: configobj
 Provides-Extra: all
+Provides-Extra: test
 License-File: LICENSE
+License-File: vendor_licenses/box-LICENSE.txt
+License-File: vendor_licenses/click-LICENSE.rst
+License-File: vendor_licenses/licenses.sh
+License-File: vendor_licenses/python-dotenv-LICENSE.txt
+License-File: vendor_licenses/ruamel.yaml-LICENSE.txt
+License-File: vendor_licenses/toml-LICENSE.txt
+License-File: vendor_licenses/tomli-LICENSE.txt
+License-File: vendor_licenses/vendor_versions.txt
 
-[![Dynaconf](docs/img/logo_400.svg?sanitize=true)](http://dynaconf.com)
+<!-- [![Dynaconf](docs/img/logo_400.svg?sanitize=true)](http://dynaconf.com) -->
 
-> **dynaconf** - Configuration Management for Python.
-
-[![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) [![PyPI](https://img.shields.io/pypi/v/dynaconf.svg)](https://pypi.python.org/pypi/dynaconf) [![PyPI](https://img.shields.io/pypi/pyversions/dynaconf.svg)]() ![PyPI - Downloads](https://img.shields.io/pypi/dm/dynaconf.svg?label=pip%20installs&logo=python) [![CI](https://github.com/rochacbruno/dynaconf/actions/workflows/main.yml/badge.svg)](https://github.com/rochacbruno/dynaconf/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/rochacbruno/dynaconf/branch/master/graph/badge.svg)](https://codecov.io/gh/rochacbruno/dynaconf) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/42d2f11ef0a446808b246c8c69603f6e)](https://www.codacy.com/gh/rochacbruno/dynaconf/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=rochacbruno/dynaconf&amp;utm_campaign=Badge_Grade) ![GitHub issues](https://img.shields.io/github/issues/rochacbruno/dynaconf.svg) ![GitHub stars](https://img.shields.io/github/stars/rochacbruno/dynaconf.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/rochacbruno/dynaconf.svg) ![GitHub commits since latest release](https://img.shields.io/github/commits-since/rochacbruno/dynaconf/latest.svg) ![GitHub last commit](https://img.shields.io/github/last-commit/rochacbruno/dynaconf.svg) [![Code Style Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black/) [![Discussion](https://img.shields.io/badge/chat-discussions-blue.svg?logo=googlechat)](https://github.com/rochacbruno/dynaconf/discussions) [![Discussion](https://img.shields.io/badge/demo-learn-yellow.svg?logo=gnubash)](https://github.com/rochacbruno/learndynaconf)
+<p align="center"><img src="/art/header.png?v2" alt="dynaconf. new logo"></p>
 
+> **dynaconf** - Configuration Management for Python.
 
+[![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) [![PyPI](https://img.shields.io/pypi/v/dynaconf.svg)](https://pypi.python.org/pypi/dynaconf) [![PyPI](https://img.shields.io/pypi/pyversions/dynaconf.svg)]() ![PyPI - Downloads](https://img.shields.io/pypi/dm/dynaconf.svg?label=pip%20installs&logo=python) [![CI](https://github.com/dynaconf/dynaconf/actions/workflows/main.yml/badge.svg)](https://github.com/dynaconf/dynaconf/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/dynaconf/dynaconf/branch/master/graph/badge.svg)](https://codecov.io/gh/dynaconf/dynaconf) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/3fb2de98464442f99a7663181803b400)](https://www.codacy.com/gh/dynaconf/dynaconf/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=dynaconf/dynaconf&amp;utm_campaign=Badge_Grade)  ![GitHub stars](https://img.shields.io/github/stars/dynaconf/dynaconf.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/dynaconf/dynaconf.svg) ![GitHub commits since latest release](https://img.shields.io/github/commits-since/dynaconf/dynaconf/latest.svg) ![GitHub last commit](https://img.shields.io/github/last-commit/dynaconf/dynaconf.svg) [![Code Style Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black/)
 
-[![Foo](https://xscode.com/assets/promo-banner.svg)](https://xscode.com/rochacbruno/dynaconf)
+![GitHub issues](https://img.shields.io/github/issues/dynaconf/dynaconf.svg) [![User Forum](https://img.shields.io/badge/users-forum-blue.svg?logo=googlechat)](https://github.com/dynaconf/dynaconf/discussions) [![Join the chat at https://gitter.im/dynaconf/dev](https://badges.gitter.im/dynaconf/dev.svg)](https://gitter.im/dynaconf/dev?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![ Matrix](https://img.shields.io/badge/dev-room-blue.svg?logo=matrix)](https://matrix.to/#/#dynaconf:matrix.org)
 
 ## Features
 
@@ -57,11 +67,6 @@ License-File: LICENSE
 - CLI for common operations such as `init, list, write, validate, export`.
 - full docs on https://dynaconf.com
 
-## Quick start
-
-> **DEMO:** You can see a working demo here: https://github.com/rochacbruno/learndynaconf
-
-
 ### Install
 
 ```bash
@@ -97,7 +102,7 @@ $ dynaconf init -f toml
 .
 ├── config.py       # This is from where you import your settings object (required)
 ├── .secrets.toml   # This is to hold sensitive data like passwords and tokens (optional)
-└── settings.toml   # This is to hold your application setttings (optional)
+└── settings.toml   # This is to hold your application settings (optional)
 ```
 
 On the file `config.py` Dynaconf init generates the following boilerpate
@@ -168,10 +173,10 @@ There is a lot more you can do, **read the docs:** http://dynaconf.com
 
 ## Contribute
 
-Main discussions happens on [t.me/dynaconf](https://t.me/dynaconf) learn more about how to get involved on [CONTRIBUTING.md guide](CONTRIBUTING.md)
+Main discussions happens on [Discussions Tab](https://github.com/dynaconf/dynaconf/discussions) learn more about how to get involved on [CONTRIBUTING.md guide](CONTRIBUTING.md)
 
-
-## more
+## More
 
 If you are looking for something similar to Dynaconf to use in your Rust projects: https://github.com/rubik/hydroconf
 
+And a special thanks to [Caneco](https://twitter.com/caneco) for the logo.
diff --git a/dynaconf.egg-info/SOURCES.txt b/dynaconf.egg-info/SOURCES.txt
index f400eff..f63aa28 100644
--- a/dynaconf.egg-info/SOURCES.txt
+++ b/dynaconf.egg-info/SOURCES.txt
@@ -1,6 +1,7 @@
 3.x-release-notes.md
 CHANGELOG.md
 CONTRIBUTING.md
+CONTRIBUTORS.md
 LICENSE
 MANIFEST.in
 README.md
@@ -109,4 +110,39 @@ dynaconf/vendor/toml/__init__.py
 dynaconf/vendor/toml/decoder.py
 dynaconf/vendor/toml/encoder.py
 dynaconf/vendor/toml/ordered.py
-dynaconf/vendor/toml/tz.py
\ No newline at end of file
+dynaconf/vendor/toml/tz.py
+dynaconf/vendor/tomllib/__init__.py
+dynaconf/vendor/tomllib/_parser.py
+dynaconf/vendor/tomllib/_re.py
+dynaconf/vendor/tomllib/_types.py
+dynaconf/vendor/tomllib/_writer.py
+tests/test_base.py
+tests/test_basic.py
+tests/test_cli.py
+tests/test_compat.py
+tests/test_django.py
+tests/test_dynabox.py
+tests/test_endtoend.py
+tests/test_env_loader.py
+tests/test_envvar_prefix.py
+tests/test_feature_flag.py
+tests/test_flask.py
+tests/test_ini_loader.py
+tests/test_json_loader.py
+tests/test_nested_loading.py
+tests/test_py_loader.py
+tests/test_redis.py
+tests/test_toml_loader.py
+tests/test_utils.py
+tests/test_validators.py
+tests/test_validators_conditions.py
+tests/test_vault.py
+tests/test_yaml_loader.py
+vendor_licenses/box-LICENSE.txt
+vendor_licenses/click-LICENSE.rst
+vendor_licenses/licenses.sh
+vendor_licenses/python-dotenv-LICENSE.txt
+vendor_licenses/ruamel.yaml-LICENSE.txt
+vendor_licenses/toml-LICENSE.txt
+vendor_licenses/tomli-LICENSE.txt
+vendor_licenses/vendor_versions.txt
\ No newline at end of file
diff --git a/dynaconf.egg-info/entry_points.txt b/dynaconf.egg-info/entry_points.txt
index 2f21b24..44e2a17 100644
--- a/dynaconf.egg-info/entry_points.txt
+++ b/dynaconf.egg-info/entry_points.txt
@@ -1,3 +1,2 @@
 [console_scripts]
 dynaconf = dynaconf.cli:main
-
diff --git a/dynaconf.egg-info/requires.txt b/dynaconf.egg-info/requires.txt
index d5175cb..f4dfab6 100644
--- a/dynaconf.egg-info/requires.txt
+++ b/dynaconf.egg-info/requires.txt
@@ -1,7 +1,4 @@
 
-[:python_version < "3.5"]
-typing
-
 [all]
 redis
 ruamel.yaml
@@ -17,6 +14,26 @@ configobj
 [redis]
 redis
 
+[test]
+pytest
+pytest-cov
+pytest-xdist
+pytest-mock
+flake8
+pep8-naming
+flake8-debugger
+flake8-print
+flake8-todo
+radon
+flask>=0.12
+django
+python-dotenv
+toml
+codecov
+redis
+hvac
+configobj
+
 [toml]
 toml
 
diff --git a/dynaconf/VERSION b/dynaconf/VERSION
index 23887f6..b48ce58 100644
--- a/dynaconf/VERSION
+++ b/dynaconf/VERSION
@@ -1 +1 @@
-3.1.7
+3.1.12
diff --git a/dynaconf/__init__.py b/dynaconf/__init__.py
index a8cd25b..a99ce5f 100644
--- a/dynaconf/__init__.py
+++ b/dynaconf/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from dynaconf.base import LazySettings  # noqa
 from dynaconf.constants import DEFAULT_SETTINGS_FILES
 from dynaconf.contrib import DjangoDynaconf  # noqa
diff --git a/dynaconf/base.py b/dynaconf/base.py
index 631f1b2..15f3df4 100644
--- a/dynaconf/base.py
+++ b/dynaconf/base.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import copy
 import glob
 import importlib
@@ -66,7 +68,7 @@ class LazySettings(LazyObject):
         self.__resolve_config_aliases(kwargs)
         compat_kwargs(kwargs)
         self._kwargs = kwargs
-        super(LazySettings, self).__init__()
+        super().__init__()
 
         if wrapped:
             if self._django_override:
@@ -87,9 +89,9 @@ class LazySettings(LazyObject):
             "environment": "environments",
             "ENVIRONMENT": "ENVIRONMENTS",
         }
-        for mispell, correct in mispells.items():
-            if mispell in kwargs:
-                kwargs[correct] = kwargs.pop(mispell)
+        for misspell, correct in mispells.items():
+            if misspell in kwargs:
+                kwargs[correct] = kwargs.pop(misspell)
 
         for_dynaconf_keys = {
             key
@@ -144,6 +146,15 @@ class LazySettings(LazyObject):
         """
         return self.get(*args, **kwargs)
 
+    @property
+    def _should_load_dotenv(self):
+        """Chicken and egg problem, we must manually check envvar
+        before deciding if we are loading envvars :)"""
+        _environ_load_dotenv = parse_conf_data(
+            os.environ.get("LOAD_DOTENV_FOR_DYNACONF"), tomlfy=True
+        )
+        return self._kwargs.get("load_dotenv", _environ_load_dotenv)
+
     def _setup(self):
         """Initial setup, run once."""
 
@@ -155,7 +166,7 @@ class LazySettings(LazyObject):
                 DeprecationWarning,
             )
 
-        default_settings.reload(self._kwargs.get("load_dotenv"))
+        default_settings.reload(self._should_load_dotenv)
         environment_variable = self._kwargs.get(
             "ENVVAR_FOR_DYNACONF", default_settings.ENVVAR_FOR_DYNACONF
         )
@@ -169,10 +180,10 @@ class LazySettings(LazyObject):
         Allows user to reconfigure settings object passing a new settings
         module or separated kwargs
 
-        :param settings_module: defines the setttings file
+        :param settings_module: defines the settings file
         :param kwargs:  override default settings
         """
-        default_settings.reload(self._kwargs.get("load_dotenv"))
+        default_settings.reload(self._should_load_dotenv)
         environment_var = self._kwargs.get(
             "ENVVAR_FOR_DYNACONF", default_settings.ENVVAR_FOR_DYNACONF
         )
@@ -198,7 +209,7 @@ class Settings:
     def __init__(self, settings_module=None, **kwargs):  # pragma: no cover
         """Execute loaders and custom initialization
 
-        :param settings_module: defines the setttings file
+        :param settings_module: defines the settings file
         :param kwargs:  override default settings
         """
         self._fresh = False
@@ -218,6 +229,9 @@ class Settings:
         self._not_installed_warnings = []
         self._validate_only = kwargs.pop("validate_only", None)
         self._validate_exclude = kwargs.pop("validate_exclude", None)
+        self._validate_only_current_env = kwargs.pop(
+            "validate_only_current_env", False
+        )
 
         self.validators = ValidatorList(
             self, validators=kwargs.pop("validators", None)
@@ -230,11 +244,20 @@ class Settings:
             self.set(key, value)
         # execute loaders only after setting defaults got from kwargs
         self._defaults = kwargs
-        self.execute_loaders()
 
-        self.validators.validate(
-            only=self._validate_only, exclude=self._validate_exclude
-        )
+        # The following flags are used for when copying of settings is done
+        skip_loaders = kwargs.get("dynaconf_skip_loaders", False)
+        skip_validators = kwargs.get("dynaconf_skip_validators", False)
+
+        if not skip_loaders:
+            self.execute_loaders()
+
+        if not skip_validators:
+            self.validators.validate(
+                only=self._validate_only,
+                exclude=self._validate_exclude,
+                only_current_env=self._validate_only_current_env,
+            )
 
     def __call__(self, *args, **kwargs):
         """Allow direct call of `settings('val')`
@@ -246,7 +269,7 @@ class Settings:
         """Allow `settings.FOO = 'value'` while keeping internal attrs."""
 
         if name in RESERVED_ATTRS:
-            super(Settings, self).__setattr__(name, value)
+            super().__setattr__(name, value)
         else:
             self.set(name, value)
 
@@ -254,7 +277,7 @@ class Settings:
         """stores reference in `_deleted` for proper error management"""
         self._deleted.add(name)
         if hasattr(self, name):
-            super(Settings, self).__delattr__(name)
+            super().__delattr__(name)
 
     def __contains__(self, item):
         """Respond to `item in settings`"""
@@ -316,18 +339,37 @@ class Settings:
         """Redirects to store object"""
         return self.store.values()
 
-    def setdefault(self, item, default):
-        """Returns value if exists or set it as the given default"""
+    def setdefault(self, item, default, apply_default_on_none=False):
+        """Returns value if exists or set it as the given default
+
+        apply_default_on_none: if True, default is set when value is None
+        """
         value = self.get(item, empty)
-        if value is empty and default is not empty:
+
+        # Yaml loader reads empty values as None, would we apply defaults?
+        global_apply_default = (
+            self.get("APPLY_DEFAULT_ON_NONE_FOR_DYNACONF") is not None
+        )
+        apply_default = default is not empty and (
+            value is empty
+            or (
+                value is None
+                and (
+                    apply_default_on_none is True
+                    or global_apply_default is True
+                )
+            )
+        )
+
+        if apply_default:
             self.set(
                 item,
                 default,
                 loader_identifier="setdefault",
                 tomlfy=True,
-                dotted_lookup=True,
             )
             return default
+
         return value
 
     def as_dict(self, env=None, internal=False):
@@ -379,11 +421,11 @@ class Settings:
         default=None,
         cast=None,
         fresh=False,
-        dotted_lookup=True,
+        dotted_lookup=empty,
         parent=None,
     ):
         """
-        Get a value from settings store, this is the prefered way to access::
+        Get a value from settings store, this is the preferred way to access::
 
             >>> from dynaconf import settings
             >>> settings.get('KEY')
@@ -401,6 +443,9 @@ class Settings:
             # turn FOO__bar__ZAZ in `FOO.bar.ZAZ`
             key = key.replace(nested_sep, ".")
 
+        if dotted_lookup is empty:
+            dotted_lookup = self._store.get("DOTTED_LOOKUP_FOR_DYNACONF")
+
         if "." in key and dotted_lookup:
             return self._dotted_get(
                 dotted_key=key,
@@ -438,7 +483,7 @@ class Settings:
         """Check if key exists
 
         :param key: the name of setting variable
-        :param fresh: if key should be taken from source direclty
+        :param fresh: if key should be taken from source directly
         :return: Boolean
         """
         key = upperfy(key)
@@ -646,9 +691,10 @@ class Settings:
         """Return the current active env"""
 
         if self.ENVIRONMENTS_FOR_DYNACONF is False:
-            return "main"
+            return self.MAIN_ENV_FOR_DYNACONF.lower()
 
         if self.FORCE_ENV_FOR_DYNACONF is not None:
+            self.ENV_FOR_DYNACONF = self.FORCE_ENV_FOR_DYNACONF
             return self.FORCE_ENV_FOR_DYNACONF
 
         try:
@@ -707,8 +753,8 @@ class Settings:
         """
         env = env or self.ENV_FOR_DYNACONF
 
-        if not isinstance(env, str):
-            raise AttributeError("env should be a string")
+        if not isinstance(env, str) or "_" in env or " " in env:
+            raise ValueError("env should be a string without _ or spaces")
 
         env = env.upper()
 
@@ -793,7 +839,7 @@ class Settings:
         value,
         loader_identifier=None,
         tomlfy=False,
-        dotted_lookup=True,
+        dotted_lookup=empty,
         is_secret="DeprecatedArgument",  # noqa
         merge=False,
     ):
@@ -805,6 +851,9 @@ class Settings:
         :param tomlfy: Bool define if value is parsed by toml (defaults False)
         :param merge: Bool define if existing nested data will be merged.
         """
+        if dotted_lookup is empty:
+            dotted_lookup = self.get("DOTTED_LOOKUP_FOR_DYNACONF")
+
         nested_sep = self.get("NESTED_SEPARATOR_FOR_DYNACONF")
         if nested_sep and nested_sep in key:
             # turn FOO__bar__ZAZ in `FOO.bar.ZAZ`
@@ -826,9 +875,15 @@ class Settings:
 
         if getattr(value, "_dynaconf_reset", False):  # pragma: no cover
             # just in case someone use a `@reset` in a first level var.
-            # NOTE: @reset/Reset is deprecated in v3.0.0
             value = value.unwrap()
 
+        if getattr(value, "_dynaconf_merge_unique", False):
+            # just in case someone use a `@merge_unique` in a first level var
+            if existing:
+                value = object_merge(existing, value.unwrap(), unique=True)
+            else:
+                value = value.unwrap()
+
         if getattr(value, "_dynaconf_merge", False):
             # just in case someone use a `@merge` in a first level var
             if existing:
@@ -842,6 +897,7 @@ class Settings:
                 value = object_merge(existing, value)
             else:
                 # `dynaconf_merge` may be used within the key structure
+                # Or merge_enabled is set to True
                 value = self._merge_before_set(existing, value)
 
         if isinstance(value, dict):
@@ -849,7 +905,7 @@ class Settings:
 
         self.store[key] = value
         self._deleted.discard(key)
-        super(Settings, self).__setattr__(key, value)
+        super().__setattr__(key, value)
 
         # set loader identifiers so cleaners know which keys to clean
         if loader_identifier and loader_identifier in self.loaded_by_loaders:
@@ -868,6 +924,7 @@ class Settings:
         tomlfy=False,
         merge=False,
         is_secret="DeprecatedArgument",  # noqa
+        dotted_lookup=empty,
         **kwargs,
     ):
         """
@@ -898,6 +955,7 @@ class Settings:
                 loader_identifier=loader_identifier,
                 tomlfy=tomlfy,
                 merge=merge,
+                dotted_lookup=dotted_lookup,
             )
 
     def _merge_before_set(self, existing, value):
@@ -952,7 +1010,7 @@ class Settings:
         """Execute all internal and registered loaders
 
         :param env: The environment to load
-        :param silent: If loading erros is silenced
+        :param silent: If loading errors is silenced
         :param key: if provided load a single key
         :param filename: optional custom filename to load
         :param loaders: optional list of loader modules
@@ -973,8 +1031,8 @@ class Settings:
 
             loaders = self.loaders
 
-        for loader in loaders:
-            loader.load(self, env, silent=silent, key=key)
+        for core_loader in loaders:
+            core_loader.load(self, env, silent=silent, key=key)
 
         self.load_includes(env, silent=silent, key=key)
         execute_hooks("post", self, env, silent=silent, key=key)
@@ -1017,18 +1075,16 @@ class Settings:
                     # continue the loop.
                     continue
 
-                # python 3.6 does not resolve Pathlib basedirs
-                # issue #494
                 root_dir = str(self._root_path or os.getcwd())
+
+                # Issue #494
                 if (
                     isinstance(_filename, Path)
                     and str(_filename.parent) in root_dir
                 ):  # pragma: no cover
                     filepath = str(_filename)
                 else:
-                    filepath = os.path.join(
-                        self._root_path or os.getcwd(), str(_filename)
-                    )
+                    filepath = os.path.join(root_dir, str(_filename))
 
                 paths = [
                     p
@@ -1038,6 +1094,7 @@ class Settings:
                 local_paths = [
                     p for p in sorted(glob.glob(filepath)) if ".local." in p
                 ]
+
                 # Handle possible *.globs sorted alphanumeric
                 for path in paths + local_paths:
                     if path in already_loaded:  # pragma: no cover
@@ -1141,7 +1198,15 @@ class Settings:
 
     def dynaconf_clone(self):
         """Clone the current settings object."""
-        return copy.deepcopy(self)
+        try:
+            return copy.deepcopy(self)
+        except TypeError:
+            # can't deepcopy settings object because of module object
+            # being set as value in the settings dict
+            new_data = self.to_dict(internal=True)
+            new_data["dynaconf_skip_loaders"] = True
+            new_data["dynaconf_skip_validators"] = True
+            return Settings(**new_data)
 
     @property
     def dynaconf(self):
@@ -1152,7 +1217,7 @@ class Settings:
         internal methods and attrs.
         """
 
-        class AttrProxy(object):
+        class AttrProxy:
             def __init__(self, obj):
                 self.obj = obj
 
@@ -1208,11 +1273,13 @@ RESERVED_ATTRS = (
         "_not_installed_warnings",
         "_store",
         "_warn_dynaconf_global_settings",
+        "_should_load_dotenv",
         "environ",
         "SETTINGS_MODULE",
         "filter_strategy",
         "validators",
         "_validate_only",
         "_validate_exclude",
+        "_validate_only_current_env",
     ]
 )
diff --git a/dynaconf/cli.py b/dynaconf/cli.py
index 5bb8316..8b8ab5d 100644
--- a/dynaconf/cli.py
+++ b/dynaconf/cli.py
@@ -1,5 +1,7 @@
+from __future__ import annotations
+
 import importlib
-import io
+import json
 import os
 import pprint
 import sys
@@ -18,13 +20,20 @@ from dynaconf.utils import upperfy
 from dynaconf.utils.files import read_file
 from dynaconf.utils.functional import empty
 from dynaconf.utils.parse_conf import parse_conf_data
+from dynaconf.utils.parse_conf import unparse_conf_data
 from dynaconf.validator import ValidationError
 from dynaconf.validator import Validator
 from dynaconf.vendor import click
 from dynaconf.vendor import toml
+from dynaconf.vendor import tomllib
 
+os.environ["PYTHONIOENCODING"] = "utf-8"
 
-CWD = Path.cwd()
+CWD = None
+try:
+    CWD = Path.cwd()
+except FileNotFoundError:
+    pass
 EXTS = ["ini", "toml", "yaml", "json", "py", "env"]
 WRITERS = ["ini", "toml", "yaml", "json", "py", "redis", "vault", "env"]
 
@@ -38,6 +47,8 @@ def set_settings(ctx, instance=None):
 
     settings = None
 
+    _echo_enabled = ctx.invoked_subcommand not in ["get", None]
+
     if instance is not None:
         if ctx.invoked_subcommand in ["init"]:
             raise click.UsageError(
@@ -48,10 +59,11 @@ def set_settings(ctx, instance=None):
     elif "FLASK_APP" in os.environ:  # pragma: no cover
         with suppress(ImportError, click.UsageError):
             from flask.cli import ScriptInfo  # noqa
+            from dynaconf import FlaskDynaconf
 
             flask_app = ScriptInfo().load_app()
-            settings = flask_app.config
-            click.echo(
+            settings = FlaskDynaconf(flask_app, **flask_app.config).settings
+            _echo_enabled and click.echo(
                 click.style(
                     "Flask app detected", fg="white", bg="bright_black"
                 )
@@ -67,7 +79,7 @@ def set_settings(ctx, instance=None):
             settings = LazySettings()
 
         if settings is not None:
-            click.echo(
+            _echo_enabled and click.echo(
                 click.style(
                     "Django app detected", fg="white", bg="bright_black"
                 )
@@ -94,7 +106,7 @@ def set_settings(ctx, instance=None):
 def import_settings(dotted_path):
     """Import settings instance from python dotted path.
 
-    Last item in dotted path must be settings instace.
+    Last item in dotted path must be settings instance.
 
     Example: import_settings('path.to.settings')
     """
@@ -108,6 +120,8 @@ def import_settings(dotted_path):
         module = importlib.import_module(module)
     except ImportError as e:
         raise click.UsageError(e)
+    except FileNotFoundError:
+        return
     try:
         return getattr(module, name)
     except AttributeError as e:
@@ -158,7 +172,7 @@ def show_banner(ctx, param, value):
         return
     set_settings(ctx)
     click.echo(settings.dynaconf_banner)
-    click.echo("Learn more at: http://github.com/rochacbruno/dynaconf")
+    click.echo("Learn more at: http://github.com/dynaconf/dynaconf")
     ctx.exit()
 
 
@@ -256,6 +270,19 @@ def init(ctx, fileformat, path, env, _vars, _secrets, wg, y, django):
     """
     click.echo("⚙️  Configuring your Dynaconf environment")
     click.echo("-" * 42)
+    if "FLASK_APP" in os.environ:  # pragma: no cover
+        click.echo(
+            "⚠️  Flask detected, you can't use `dynaconf init` "
+            "on a flask project, instead go to dynaconf.com/flask/ "
+            "for more information.\n"
+            "Or add the following to your app.py\n"
+            "\n"
+            "from dynaconf import FlaskDynaconf\n"
+            "app = Flask(__name__)\n"
+            "FlaskDynaconf(app)\n"
+        )
+        exit(1)
+
     path = Path(path)
 
     if env is not None:
@@ -364,15 +391,14 @@ def init(ctx, fileformat, path, env, _vars, _secrets, wg, y, django):
         ignore_line = ".secrets.*"
         comment = "\n# Ignore dynaconf secret files\n"
         if not gitignore_path.exists():
-            with io.open(str(gitignore_path), "w", encoding=ENC) as f:
+            with open(str(gitignore_path), "w", encoding=ENC) as f:
                 f.writelines([comment, ignore_line, "\n"])
         else:
             existing = (
-                ignore_line
-                in io.open(str(gitignore_path), encoding=ENC).read()
+                ignore_line in open(str(gitignore_path), encoding=ENC).read()
             )
             if not existing:  # pragma: no cover
-                with io.open(str(gitignore_path), "a+", encoding=ENC) as f:
+                with open(str(gitignore_path), "a+", encoding=ENC) as f:
                     f.writelines([comment, ignore_line, "\n"])
 
         click.echo(
@@ -401,6 +427,51 @@ def init(ctx, fileformat, path, env, _vars, _secrets, wg, y, django):
         )
 
 
+@main.command(name="get")
+@click.argument("key", required=True)
+@click.option(
+    "--default",
+    "-d",
+    default=empty,
+    help="Default value if settings doesn't exist",
+)
+@click.option(
+    "--env", "-e", default=None, help="Filters the env to get the values"
+)
+@click.option(
+    "--unparse",
+    "-u",
+    default=False,
+    help="Unparse data by adding markers such as @none, @int etc..",
+    is_flag=True,
+)
+def get(key, default, env, unparse):
+    """Returns the raw value for a settings key.
+
+    If result is a dict, list or tuple it is printes as a valid json string.
+    """
+    if env:
+        env = env.strip()
+    if key:
+        key = key.strip()
+
+    if env:
+        settings.setenv(env)
+
+    if default is not empty:
+        result = settings.get(key, default)
+    else:
+        result = settings[key]  # let the keyerror raises
+
+    if unparse:
+        result = unparse_conf_data(result)
+
+    if isinstance(result, (dict, list, tuple)):
+        result = json.dumps(result, sort_keys=True)
+
+    click.echo(result, nl=False)
+
+
 @main.command(name="list")
 @click.option(
     "--env", "-e", default=None, help="Filters the env to get the values"
@@ -652,7 +723,16 @@ def validate(path):  # pragma: no cover
         click.echo(click.style(f"{path} not found", fg="white", bg="red"))
         sys.exit(1)
 
-    validation_data = toml.load(open(str(path)))
+    try:  # try tomlib first
+        validation_data = tomllib.load(open(str(path), "rb"))
+    except UnicodeDecodeError:  # fallback to legacy toml (TBR in 4.0.0)
+        warnings.warn(
+            "TOML files should have only UTF-8 encoded characters. "
+            "starting on 4.0.0 dynaconf will stop allowing invalid chars.",
+        )
+        validation_data = toml.load(
+            open(str(path), encoding=default_settings.ENCODING_FOR_DYNACONF),
+        )
 
     success = True
     for env, name_data in validation_data.items():
diff --git a/dynaconf/constants.py b/dynaconf/constants.py
index 1b9e7d3..6256273 100644
--- a/dynaconf/constants.py
+++ b/dynaconf/constants.py
@@ -1,4 +1,6 @@
 # pragma: no cover
+from __future__ import annotations
+
 INI_EXTENSIONS = (".ini", ".conf", ".properties")
 TOML_EXTENSIONS = (".toml", ".tml")
 YAML_EXTENSIONS = (".yaml", ".yml")
@@ -16,7 +18,7 @@ EXTERNAL_LOADERS = {
 
 DJANGO_PATCH = """
 # HERE STARTS DYNACONF EXTENSION LOAD (Keep at the very bottom of settings.py)
-# Read more at https://dynaconf.readthedocs.io/en/latest/guides/django.html
+# Read more at https://www.dynaconf.com/django/
 import dynaconf  # noqa
 settings = dynaconf.DjangoDynaconf(__name__)  # noqa
 # HERE ENDS DYNACONF EXTENSION LOAD (No more code below this line)
diff --git a/dynaconf/contrib/__init__.py b/dynaconf/contrib/__init__.py
index 565ae21..2c0279a 100644
--- a/dynaconf/contrib/__init__.py
+++ b/dynaconf/contrib/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from dynaconf.contrib.django_dynaconf_v2 import DjangoDynaconf  # noqa
 from dynaconf.contrib.flask_dynaconf import DynaconfConfig  # noqa
 from dynaconf.contrib.flask_dynaconf import FlaskDynaconf  # noqa
diff --git a/dynaconf/contrib/django_dynaconf_v2.py b/dynaconf/contrib/django_dynaconf_v2.py
index bb86454..aac4aab 100644
--- a/dynaconf/contrib/django_dynaconf_v2.py
+++ b/dynaconf/contrib/django_dynaconf_v2.py
@@ -1,9 +1,9 @@
 """Dynaconf django extension
 
-In the `django_project/settings.py` put at the very botton of the file:
+In the `django_project/settings.py` put at the very bottom of the file:
 
 # HERE STARTS DYNACONF EXTENSION LOAD (Keep at the very bottom of settings.py)
-# Read more at https://dynaconf.readthedocs.io/en/latest/guides/django.html
+# Read more at https://www.dynaconf.com/django/
 import dynaconf  # noqa
 settings = dynaconf.DjangoDynaconf(__name__)  # noqa
 # HERE ENDS DYNACONF EXTENSION LOAD (No more code below this line)
@@ -20,6 +20,8 @@ On your projects root folder now you can start as::
     DJANGO_ALLOWED_HOSTS='["localhost"]' \
     python manage.py runserver
 """
+from __future__ import annotations
+
 import inspect
 import os
 import sys
@@ -49,12 +51,15 @@ def load(django_settings_module_name=None, **kwargs):  # pragma: no cover
             os.environ["DJANGO_SETTINGS_MODULE"]
         ]
 
+    settings_module_name = django_settings_module.__name__
     settings_file = os.path.abspath(django_settings_module.__file__)
     _root_path = os.path.dirname(settings_file)
 
     # 1) Create the lazy settings object reusing settings_module consts
     options = {
-        k: v for k, v in django_settings_module.__dict__.items() if k.isupper()
+        k.upper(): v
+        for k, v in django_settings_module.__dict__.items()
+        if k.isupper()
     }
     options.update(kwargs)
     options.setdefault(
@@ -95,6 +100,16 @@ def load(django_settings_module_name=None, **kwargs):  # pragma: no cover
 
     lazy_settings.update(dj)
 
+    # Allow dynaconf_hooks to be in the same folder as the django.settings
+    dynaconf.loaders.execute_hooks(
+        "post",
+        lazy_settings,
+        lazy_settings.current_env,
+        modules=[settings_module_name],
+        files=[settings_file],
+    )
+    lazy_settings._loaded_py_modules.insert(0, settings_module_name)
+
     # 5) Patch django.conf.settings
     class Wrapper:
 
diff --git a/dynaconf/contrib/flask_dynaconf.py b/dynaconf/contrib/flask_dynaconf.py
index c4e1b77..a305194 100644
--- a/dynaconf/contrib/flask_dynaconf.py
+++ b/dynaconf/contrib/flask_dynaconf.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import warnings
 from collections import ChainMap
 from contextlib import suppress
@@ -69,7 +71,7 @@ class FlaskDynaconf:
             app,
             ENV='MYSITE',
             SETTINGS_FILE='settings.yml',
-            EXTRA_VALUE='You can add aditional config vars here'
+            EXTRA_VALUE='You can add additional config vars here'
         )
 
     Take a look at examples/flask in Dynaconf repository
@@ -90,8 +92,7 @@ class FlaskDynaconf:
                 "To use this extension Flask must be installed "
                 "install it with: pip install flask"
             )
-        self.kwargs = kwargs
-
+        self.kwargs = {k.upper(): v for k, v in kwargs.items()}
         kwargs.setdefault("ENVVAR_PREFIX", "FLASK")
         env_prefix = f"{kwargs['ENVVAR_PREFIX']}_ENV"  # FLASK_ENV
         kwargs.setdefault("ENV_SWITCHER", env_prefix)
@@ -143,7 +144,7 @@ class DynaconfConfig(Config):
 
     def __init__(self, _settings, _app, *args, **kwargs):
         """perform the initial load"""
-        super(DynaconfConfig, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
 
         # Bring Dynaconf instance value to Flask Config
         Config.update(self, _settings.store)
@@ -178,6 +179,9 @@ class DynaconfConfig(Config):
     def items(self):
         return self._chain_map().items()
 
+    def setdefault(self, key, value=None):
+        return self._chain_map().setdefault(key, value)
+
     def __iter__(self):
         return self._chain_map().__iter__()
 
diff --git a/dynaconf/default_settings.py b/dynaconf/default_settings.py
index 66601b0..40c627b 100644
--- a/dynaconf/default_settings.py
+++ b/dynaconf/default_settings.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import importlib
 import os
 import sys
@@ -84,8 +86,9 @@ if not SETTINGS_FILE_FOR_DYNACONF and mispelled_files is not None:
 # # In dynaconf 1.0.0 `NAMESPACE` got renamed to `ENV`
 
 
-# If provided environments will be loaded separatelly
+# If provided environments will be loaded separately
 ENVIRONMENTS_FOR_DYNACONF = get("ENVIRONMENTS_FOR_DYNACONF", False)
+MAIN_ENV_FOR_DYNACONF = get("MAIN_ENV_FOR_DYNACONF", "MAIN")
 
 # If False dynaconf will allow access to first level settings only in upper
 LOWERCASE_READ_FOR_DYNACONF = get("LOWERCASE_READ_FOR_DYNACONF", True)
@@ -122,12 +125,17 @@ IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF = get(
     "IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF", False
 )
 
+AUTO_CAST_FOR_DYNACONF = get("AUTO_CAST_FOR_DYNACONF", True)
+
 # The default encoding to open settings files
 ENCODING_FOR_DYNACONF = get("ENCODING_FOR_DYNACONF", "utf-8")
 
 # Merge objects on load
 MERGE_ENABLED_FOR_DYNACONF = get("MERGE_ENABLED_FOR_DYNACONF", False)
 
+# Lookup keys considering dots as separators
+DOTTED_LOOKUP_FOR_DYNACONF = get("DOTTED_LOOKUP_FOR_DYNACONF", True)
+
 # BY default `__` is the separator for nested env vars
 # export `DYNACONF__DATABASE__server=server.com`
 # export `DYNACONF__DATABASE__PORT=6666`
@@ -164,6 +172,7 @@ default_vault = {
     "timeout": get("VAULT_TIMEOUT_FOR_DYNACONF", None),
     "proxies": get("VAULT_PROXIES_FOR_DYNACONF", None),
     "allow_redirects": get("VAULT_ALLOW_REDIRECTS_FOR_DYNACONF", None),
+    "namespace": get("VAULT_NAMESPACE_FOR_DYNACONF", None),
 }
 VAULT_FOR_DYNACONF = get("VAULT_FOR_DYNACONF", default_vault)
 VAULT_ENABLED_FOR_DYNACONF = get("VAULT_ENABLED_FOR_DYNACONF", False)
@@ -230,6 +239,13 @@ PRELOAD_FOR_DYNACONF = get("PRELOAD_FOR_DYNACONF", [])
 # Files to skip if found on search tree
 SKIP_FILES_FOR_DYNACONF = get("SKIP_FILES_FOR_DYNACONF", [])
 
+# YAML reads empty vars as None, should dynaconf apply validator defaults?
+# this is set to None, then evaluated on base.Settings.setdefault
+# possible values are True/False
+APPLY_DEFAULT_ON_NONE_FOR_DYNACONF = get(
+    "APPLY_DEFAULT_ON_NONE_FOR_DYNACONF", None
+)
+
 
 # Backwards compatibility with renamed variables
 for old, new in RENAMED_VARS.items():
diff --git a/dynaconf/loaders/__init__.py b/dynaconf/loaders/__init__.py
index d4f50cf..e18cb84 100644
--- a/dynaconf/loaders/__init__.py
+++ b/dynaconf/loaders/__init__.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import importlib
 import os
 
@@ -69,7 +71,8 @@ def _run_hook_module(hook, hook_module, obj, key=None):
         return
 
     if hook_module and getattr(hook_module, "_error", False):
-        raise hook_module._error
+        if not isinstance(hook_module._error, FileNotFoundError):
+            raise hook_module._error
 
     hook_func = getattr(hook_module, hook, None)
     if hook_func:
@@ -85,13 +88,16 @@ def _run_hook_module(hook, hook_module, obj, key=None):
         obj._loaded_hooks[hook_module.__file__][hook] = hook_dict
 
 
-def execute_hooks(hook, obj, env=None, silent=True, key=None):
+def execute_hooks(
+    hook, obj, env=None, silent=True, key=None, modules=None, files=None
+):
     """Execute dynaconf_hooks from module or filepath."""
     if hook not in ["post"]:
         raise ValueError(f"hook {hook} not supported yet.")
 
     # try to load hooks using python module __name__
-    for loaded_module in obj._loaded_py_modules:
+    modules = modules or obj._loaded_py_modules
+    for loaded_module in modules:
         hook_module_name = ".".join(
             loaded_module.split(".")[:-1] + ["dynaconf_hooks"]
         )
@@ -109,7 +115,8 @@ def execute_hooks(hook, obj, env=None, silent=True, key=None):
             )
 
     # Try to load from python filename path
-    for loaded_file in obj._loaded_files:
+    files = files or obj._loaded_files
+    for loaded_file in files:
         hook_file = os.path.join(
             os.path.dirname(loaded_file), "dynaconf_hooks.py"
         )
@@ -261,7 +268,7 @@ def write(filename, data, env=None):
     loader_name = f"{filename.rpartition('.')[-1]}_loader"
     loader = globals().get(loader_name)
     if not loader:
-        raise IOError(f"{loader_name} cannot be found.")
+        raise OSError(f"{loader_name} cannot be found.")
 
     data = DynaBox(data, box_settings={}).to_dict()
     if loader is not py_loader and env and env not in data:
diff --git a/dynaconf/loaders/base.py b/dynaconf/loaders/base.py
index 9239920..dec5cb0 100644
--- a/dynaconf/loaders/base.py
+++ b/dynaconf/loaders/base.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import io
 import warnings
 
@@ -19,7 +21,14 @@ class BaseLoader:
     """
 
     def __init__(
-        self, obj, env, identifier, extensions, file_reader, string_reader
+        self,
+        obj,
+        env,
+        identifier,
+        extensions,
+        file_reader,
+        string_reader,
+        opener_params=None,
     ):
         """Instantiates a loader for different sources"""
         self.obj = obj
@@ -28,6 +37,10 @@ class BaseLoader:
         self.extensions = extensions
         self.file_reader = file_reader
         self.string_reader = string_reader
+        self.opener_params = opener_params or {
+            "mode": "r",
+            "encoding": obj.get("ENCODING_FOR_DYNACONF", "utf-8"),
+        }
 
     @staticmethod
     def warn_not_installed(obj, identifier):  # pragma: no cover
@@ -44,7 +57,7 @@ class BaseLoader:
 
         :param filename: Optional filename to load
         :param key: if provided load a single key
-        :param silent: if load erros should be silenced
+        :param silent: if load errors should be silenced
         """
 
         filename = filename or self.obj.get(self.identifier.upper())
@@ -75,17 +88,12 @@ class BaseLoader:
         for source_file in files:
             if source_file.endswith(self.extensions):
                 try:
-                    with io.open(
-                        source_file,
-                        encoding=self.obj.get(
-                            "ENCODING_FOR_DYNACONF", "utf-8"
-                        ),
-                    ) as open_file:
+                    with open(source_file, **self.opener_params) as open_file:
                         content = self.file_reader(open_file)
                         self.obj._loaded_files.append(source_file)
                         if content:
                             data[source_file] = content
-                except IOError as e:
+                except OSError as e:
                     if ".local." not in source_file:
                         warnings.warn(
                             f"{self.identifier}_loader: {source_file} "
@@ -118,6 +126,9 @@ class BaseLoader:
             # is there a `dynaconf_merge` on top level of file?
             file_merge = file_data.get("dynaconf_merge")
 
+            # is there a flag disabling dotted lookup on file?
+            file_dotted_lookup = file_data.get("dynaconf_dotted_lookup")
+
             for env in build_env_list(self.obj, self.env):
                 env = env.lower()  # lower for better comparison
 
@@ -131,15 +142,12 @@ class BaseLoader:
                 if not data:
                     continue
 
-                if env != self.obj.get("DEFAULT_ENV_FOR_DYNACONF").lower():
-                    identifier = f"{self.identifier}_{env}"
-                else:
-                    identifier = self.identifier
                 self._set_data_to_obj(
                     data,
-                    identifier,
+                    f"{self.identifier}_{env}",
                     file_merge,
                     key,
+                    file_dotted_lookup=file_dotted_lookup,
                 )
 
     def _set_data_to_obj(
@@ -148,6 +156,7 @@ class BaseLoader:
         identifier,
         file_merge=None,
         key=False,
+        file_dotted_lookup=None,
     ):
         """Calls settings.set to add the keys"""
         # data 1st level keys should be transformed to upper case.
@@ -160,11 +169,21 @@ class BaseLoader:
 
         # is there a `dynaconf_merge` inside an `[env]`?
         file_merge = file_merge or data.pop("DYNACONF_MERGE", False)
+
+        # If not passed or passed as None,
+        # look for inner [env] value, or default settings.
+        if file_dotted_lookup is None:
+            file_dotted_lookup = data.pop(
+                "DYNACONF_DOTTED_LOOKUP",
+                self.obj.get("DOTTED_LOOKUP_FOR_DYNACONF"),
+            )
+
         if not key:
             self.obj.update(
                 data,
                 loader_identifier=identifier,
                 merge=file_merge,
+                dotted_lookup=file_dotted_lookup,
             )
         elif key in data:
             self.obj.set(
@@ -172,4 +191,5 @@ class BaseLoader:
                 data.get(key),
                 loader_identifier=identifier,
                 merge=file_merge,
+                dotted_lookup=file_dotted_lookup,
             )
diff --git a/dynaconf/loaders/env_loader.py b/dynaconf/loaders/env_loader.py
index e7b13bd..779e9a4 100644
--- a/dynaconf/loaders/env_loader.py
+++ b/dynaconf/loaders/env_loader.py
@@ -1,8 +1,20 @@
+from __future__ import annotations
+
 from os import environ
 
+from dynaconf.utils import missing
 from dynaconf.utils import upperfy
 from dynaconf.utils.parse_conf import parse_conf_data
-from dynaconf.vendor.dotenv import cli as dotenv_cli
+
+DOTENV_IMPORTED = False
+try:
+    from dynaconf.vendor.dotenv import cli as dotenv_cli
+
+    DOTENV_IMPORTED = True
+except ImportError:
+    pass
+except FileNotFoundError:
+    pass
 
 
 IDENTIFIER = "env"
@@ -54,9 +66,8 @@ def load_from_env(
 
     # Load environment variables in bulk (when matching).
     else:
-        # Only known variables should be loaded from environment.
+        # Only known variables should be loaded from environment?
         ignore_unknown = obj.get("IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF")
-        known_keys = set(obj.store)
 
         trim_len = len(env_)
         data = {
@@ -69,16 +80,21 @@ def load_from_env(
                 # Ignore environment variables that haven't been
                 # pre-defined in settings space.
                 ignore_unknown
-                and key[trim_len:] not in known_keys
+                and obj.get(key[trim_len:], default=missing) is missing
             )
         }
         # Update the settings space based on gathered data from environment.
         if data:
+            filter_strategy = obj.get("FILTER_STRATEGY")
+            if filter_strategy:
+                data = filter_strategy(data)
             obj.update(data, loader_identifier=identifier)
 
 
 def write(settings_path, settings_data, **kwargs):
     """Write data to .env file"""
+    if not DOTENV_IMPORTED:
+        return
     for key, value in settings_data.items():
         quote_mode = (
             isinstance(value, str)
diff --git a/dynaconf/loaders/ini_loader.py b/dynaconf/loaders/ini_loader.py
index 7b83042..c3b56fd 100644
--- a/dynaconf/loaders/ini_loader.py
+++ b/dynaconf/loaders/ini_loader.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import io
 from pathlib import Path
 
@@ -51,7 +53,7 @@ def write(settings_path, settings_data, merge=True):
     """
     settings_path = Path(settings_path)
     if settings_path.exists() and merge:  # pragma: no cover
-        with io.open(
+        with open(
             str(settings_path), encoding=default_settings.ENCODING_FOR_DYNACONF
         ) as open_file:
             object_merge(ConfigObj(open_file).dict(), settings_data)
diff --git a/dynaconf/loaders/json_loader.py b/dynaconf/loaders/json_loader.py
index bfc81aa..72c1e34 100644
--- a/dynaconf/loaders/json_loader.py
+++ b/dynaconf/loaders/json_loader.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import io
 import json
 from pathlib import Path
@@ -58,12 +60,12 @@ def write(settings_path, settings_data, merge=True):
     """
     settings_path = Path(settings_path)
     if settings_path.exists() and merge:  # pragma: no cover
-        with io.open(
+        with open(
             str(settings_path), encoding=default_settings.ENCODING_FOR_DYNACONF
         ) as open_file:
             object_merge(json.load(open_file), settings_data)
 
-    with io.open(
+    with open(
         str(settings_path),
         "w",
         encoding=default_settings.ENCODING_FOR_DYNACONF,
diff --git a/dynaconf/loaders/py_loader.py b/dynaconf/loaders/py_loader.py
index bc95c94..f296459 100644
--- a/dynaconf/loaders/py_loader.py
+++ b/dynaconf/loaders/py_loader.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import errno
 import importlib
 import inspect
@@ -108,12 +110,12 @@ def import_from_filename(obj, filename, silent=False):  # pragma: no cover
     mod._is_error = False
     mod._error = None
     try:
-        with io.open(
+        with open(
             _find_file(filename),
             encoding=default_settings.ENCODING_FOR_DYNACONF,
         ) as config_file:
             exec(compile(config_file.read(), filename, "exec"), mod.__dict__)
-    except IOError as e:
+    except OSError as e:
         e.strerror = (
             f"py_loader: error loading file " f"({e.strerror} {filename})\n"
         )
@@ -136,7 +138,7 @@ def write(settings_path, settings_data, merge=True):
         existing = DynaconfDict()
         load(existing, str(settings_path))
         object_merge(existing, settings_data)
-    with io.open(
+    with open(
         str(settings_path),
         "w",
         encoding=default_settings.ENCODING_FOR_DYNACONF,
diff --git a/dynaconf/loaders/redis_loader.py b/dynaconf/loaders/redis_loader.py
index 906a35d..1123cb0 100644
--- a/dynaconf/loaders/redis_loader.py
+++ b/dynaconf/loaders/redis_loader.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from dynaconf.utils import build_env_list
 from dynaconf.utils import upperfy
 from dynaconf.utils.parse_conf import parse_conf_data
@@ -67,7 +69,7 @@ def write(obj, data=None, **kwargs):
         raise RuntimeError(
             "Redis is not configured \n"
             "export REDIS_ENABLED_FOR_DYNACONF=true\n"
-            "and configure the REDIS_FOR_DYNACONF_* variables"
+            "and configure the REDIS_*_FOR_DYNACONF variables"
         )
     client = StrictRedis(**obj.REDIS_FOR_DYNACONF)
     holder = obj.get("ENVVAR_PREFIX_FOR_DYNACONF").upper()
diff --git a/dynaconf/loaders/toml_loader.py b/dynaconf/loaders/toml_loader.py
index 8248957..f4f6e17 100644
--- a/dynaconf/loaders/toml_loader.py
+++ b/dynaconf/loaders/toml_loader.py
@@ -1,11 +1,14 @@
-import io
+from __future__ import annotations
+
+import warnings
 from pathlib import Path
 
 from dynaconf import default_settings
 from dynaconf.constants import TOML_EXTENSIONS
 from dynaconf.loaders.base import BaseLoader
 from dynaconf.utils import object_merge
-from dynaconf.vendor import toml
+from dynaconf.vendor import toml  # Backwards compatibility with uiri/toml
+from dynaconf.vendor import tomllib  # New tomllib stdlib on py3.11
 
 
 def load(obj, env=None, silent=True, key=None, filename=None):
@@ -20,19 +23,54 @@ def load(obj, env=None, silent=True, key=None, filename=None):
     :return: None
     """
 
-    loader = BaseLoader(
-        obj=obj,
-        env=env,
-        identifier="toml",
-        extensions=TOML_EXTENSIONS,
-        file_reader=toml.load,
-        string_reader=toml.loads,
-    )
-    loader.load(
-        filename=filename,
-        key=key,
-        silent=silent,
-    )
+    try:
+        loader = BaseLoader(
+            obj=obj,
+            env=env,
+            identifier="toml",
+            extensions=TOML_EXTENSIONS,
+            file_reader=tomllib.load,
+            string_reader=tomllib.loads,
+            opener_params={"mode": "rb"},
+        )
+        loader.load(
+            filename=filename,
+            key=key,
+            silent=silent,
+        )
+    except UnicodeDecodeError:  # pragma: no cover
+        """
+        NOTE: Compat functions exists to keep backwards compatibility with
+        the new tomllib library. The old library was called `toml` and
+        the new one is called `tomllib`.
+
+        The old lib uiri/toml allowed unicode characters and re-added files
+        as string.
+
+        The new tomllib (stdlib) does not allow unicode characters, only
+        utf-8 encoded, and read files as binary.
+
+        NOTE: In dynaconf 4.0.0 we will drop support for the old library
+        removing the compat functions and calling directly the new lib.
+        """
+        loader = BaseLoader(
+            obj=obj,
+            env=env,
+            identifier="toml",
+            extensions=TOML_EXTENSIONS,
+            file_reader=toml.load,
+            string_reader=toml.loads,
+        )
+        loader.load(
+            filename=filename,
+            key=key,
+            silent=silent,
+        )
+
+        warnings.warn(
+            "TOML files should have only UTF-8 encoded characters. "
+            "starting on 4.0.0 dynaconf will stop allowing invalid chars.",
+        )
 
 
 def write(settings_path, settings_data, merge=True):
@@ -44,17 +82,33 @@ def write(settings_path, settings_data, merge=True):
     """
     settings_path = Path(settings_path)
     if settings_path.exists() and merge:  # pragma: no cover
-        with io.open(
-            str(settings_path), encoding=default_settings.ENCODING_FOR_DYNACONF
+        try:  # tomllib first
+            with open(str(settings_path), "rb") as open_file:
+                object_merge(tomllib.load(open_file), settings_data)
+        except UnicodeDecodeError:  # pragma: no cover
+            # uiri/toml fallback (TBR on 4.0.0)
+            with open(
+                str(settings_path),
+                encoding=default_settings.ENCODING_FOR_DYNACONF,
+            ) as open_file:
+                object_merge(toml.load(open_file), settings_data)
+
+    try:  # tomllib first
+        with open(str(settings_path), "wb") as open_file:
+            tomllib.dump(encode_nulls(settings_data), open_file)
+    except UnicodeEncodeError:  # pragma: no cover
+        # uiri/toml fallback (TBR on 4.0.0)
+        with open(
+            str(settings_path),
+            "w",
+            encoding=default_settings.ENCODING_FOR_DYNACONF,
         ) as open_file:
-            object_merge(toml.load(open_file), settings_data)
-
-    with io.open(
-        str(settings_path),
-        "w",
-        encoding=default_settings.ENCODING_FOR_DYNACONF,
-    ) as open_file:
-        toml.dump(encode_nulls(settings_data), open_file)
+            toml.dump(encode_nulls(settings_data), open_file)
+
+        warnings.warn(
+            "TOML files should have only UTF-8 encoded characters. "
+            "starting on 4.0.0 dynaconf will stop allowing invalid chars.",
+        )
 
 
 def encode_nulls(data):
diff --git a/dynaconf/loaders/vault_loader.py b/dynaconf/loaders/vault_loader.py
index e5d6841..d816ffc 100644
--- a/dynaconf/loaders/vault_loader.py
+++ b/dynaconf/loaders/vault_loader.py
@@ -1,5 +1,7 @@
 # docker run -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' -p 8200:8200 vault
 # pip install hvac
+from __future__ import annotations
+
 from dynaconf.utils import build_env_list
 from dynaconf.utils.parse_conf import parse_conf_data
 
@@ -31,7 +33,7 @@ def get_client(obj):
         **{k: v for k, v in obj.VAULT_FOR_DYNACONF.items() if v is not None}
     )
     if obj.VAULT_ROLE_ID_FOR_DYNACONF is not None:
-        client.auth_approle(
+        client.auth.approle.login(
             role_id=obj.VAULT_ROLE_ID_FOR_DYNACONF,
             secret_id=obj.get("VAULT_SECRET_ID_FOR_DYNACONF"),
         )
@@ -56,7 +58,7 @@ def get_client(obj):
         "Vault authentication error: is VAULT_TOKEN_FOR_DYNACONF or "
         "VAULT_ROLE_ID_FOR_DYNACONF defined?"
     )
-    client.kv.default_kv_version = obj.VAULT_KV_VERSION_FOR_DYNACONF
+    client.secrets.kv.default_kv_version = obj.VAULT_KV_VERSION_FOR_DYNACONF
     return client
 
 
@@ -71,14 +73,27 @@ def load(obj, env=None, silent=None, key=None):
     """
     client = get_client(obj)
     try:
-        dirs = client.secrets.kv.list_secrets(
-            path=obj.VAULT_PATH_FOR_DYNACONF,
-            mount_point=obj.VAULT_MOUNT_POINT_FOR_DYNACONF,
-        )["data"]["keys"]
+        if obj.VAULT_KV_VERSION_FOR_DYNACONF == 2:
+            dirs = client.secrets.kv.v2.list_secrets(
+                path=obj.VAULT_PATH_FOR_DYNACONF,
+                mount_point=obj.VAULT_MOUNT_POINT_FOR_DYNACONF,
+            )["data"]["keys"]
+        else:
+            dirs = client.secrets.kv.v1.list_secrets(
+                path=obj.VAULT_PATH_FOR_DYNACONF,
+                mount_point=obj.VAULT_MOUNT_POINT_FOR_DYNACONF,
+            )["data"]["keys"]
     except InvalidPath:
         # The given path is not a directory
         dirs = []
-    env_list = dirs + build_env_list(obj, env)
+    # First look for secrets into environments less store
+    if not obj.ENVIRONMENTS_FOR_DYNACONF:
+        # By adding '', dynaconf will now read secrets from environments-less
+        # store which are not written by `dynaconf write` to Vault store
+        env_list = [obj.MAIN_ENV_FOR_DYNACONF.lower(), ""]
+    # Finally, look for secret into all the environments
+    else:
+        env_list = dirs + build_env_list(obj, env)
     for env in env_list:
         path = "/".join([obj.VAULT_PATH_FOR_DYNACONF, env])
         try:
@@ -99,7 +114,11 @@ def load(obj, env=None, silent=None, key=None):
             # extract the inner data
             data = data.get("data", {}).get("data", {})
         try:
-            if obj.VAULT_KV_VERSION_FOR_DYNACONF == 2 and data:
+            if (
+                obj.VAULT_KV_VERSION_FOR_DYNACONF == 2
+                and obj.ENVIRONMENTS_FOR_DYNACONF
+                and data
+            ):
                 data = data.get("data", {})
             if data and key:
                 value = parse_conf_data(
diff --git a/dynaconf/loaders/yaml_loader.py b/dynaconf/loaders/yaml_loader.py
index fa63150..37b0b6c 100644
--- a/dynaconf/loaders/yaml_loader.py
+++ b/dynaconf/loaders/yaml_loader.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import io
 from pathlib import Path
 from warnings import warn
@@ -65,12 +67,12 @@ def write(settings_path, settings_data, merge=True):
     """
     settings_path = Path(settings_path)
     if settings_path.exists() and merge:  # pragma: no cover
-        with io.open(
+        with open(
             str(settings_path), encoding=default_settings.ENCODING_FOR_DYNACONF
         ) as open_file:
             object_merge(yaml.safe_load(open_file), settings_data)
 
-    with io.open(
+    with open(
         str(settings_path),
         "w",
         encoding=default_settings.ENCODING_FOR_DYNACONF,
diff --git a/dynaconf/strategies/filtering.py b/dynaconf/strategies/filtering.py
index 12b49a0..ef1f51f 100644
--- a/dynaconf/strategies/filtering.py
+++ b/dynaconf/strategies/filtering.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from dynaconf.utils import upperfy
 
 
@@ -5,7 +7,7 @@ class PrefixFilter:
     def __init__(self, prefix):
         if not isinstance(prefix, str):
             raise TypeError("`SETTINGS_FILE_PREFIX` must be str")
-        self.prefix = "{}_".format(upperfy(prefix))
+        self.prefix = f"{upperfy(prefix)}_"
 
     def __call__(self, data):
         """Filter incoming data by prefix"""
diff --git a/dynaconf/test_settings.py b/dynaconf/test_settings.py
index 61e7638..3c43ec9 100644
--- a/dynaconf/test_settings.py
+++ b/dynaconf/test_settings.py
@@ -1,4 +1,6 @@
 # pragma: no cover
+from __future__ import annotations
+
 TESTING = True
 LOADERS_FOR_DYNACONF = [
     "dynaconf.loaders.env_loader",
diff --git a/dynaconf/utils/__init__.py b/dynaconf/utils/__init__.py
index 30d910f..2d1a8c1 100644
--- a/dynaconf/utils/__init__.py
+++ b/dynaconf/utils/__init__.py
@@ -5,13 +5,8 @@ import warnings
 from collections import defaultdict
 from json import JSONDecoder
 from typing import Any
-from typing import Dict
 from typing import Iterator
-from typing import List
-from typing import Optional
-from typing import Tuple
 from typing import TYPE_CHECKING
-from typing import Union
 
 
 if TYPE_CHECKING:  # pragma: no cover
@@ -34,7 +29,7 @@ if os.name == "nt":  # pragma: no cover
 
 
 def object_merge(
-    old: Any, new: Any, unique: bool = False, full_path: List[str] = None
+    old: Any, new: Any, unique: bool = False, full_path: list[str] = None
 ) -> Any:
     """
     Recursively merge two data structures, new is mutated in-place.
@@ -51,32 +46,48 @@ def object_merge(
         return new
 
     if isinstance(old, list) and isinstance(new, list):
+
+        # 726: allow local_merge to override global merge on lists
+        if "dynaconf_merge_unique" in new:
+            new.remove("dynaconf_merge_unique")
+            unique = True
+
         for item in old[::-1]:
             if unique and item in new:
                 continue
             new.insert(0, item)
 
     if isinstance(old, dict) and isinstance(new, dict):
-        existing_value = recursive_get(old, full_path)  # doesnt handle None
+        existing_value = recursive_get(old, full_path)  # doesn't handle None
         # Need to make every `None` on `_store` to be an wrapped `LazyNone`
 
-        for key, value in old.items():
+        # data coming from source, in `new` can be mix case: KEY4|key4|Key4
+        # data existing on `old` object has the correct case: key4|KEY4|Key4
+        # So we need to ensure that new keys matches the existing keys
+        for new_key in list(new.keys()):
+            correct_case_key = find_the_correct_casing(new_key, old)
+            if correct_case_key:
+                new[correct_case_key] = new.pop(new_key)
+
+        for old_key, value in old.items():
 
+            # This is for when the dict exists internally
+            # but the new value on the end of full path is the same
             if (
                 existing_value is not None
-                and key.lower() == full_path[-1].lower()
+                and old_key.lower() == full_path[-1].lower()
                 and existing_value is value
             ):
                 # Here Be The Dragons
                 # This comparison needs to be smarter
                 continue
 
-            if key not in new:
-                new[key] = value
+            if old_key not in new:
+                new[old_key] = value
             else:
                 object_merge(
                     value,
-                    new[key],
+                    new[old_key],
                     full_path=full_path[1:] if full_path else None,
                 )
 
@@ -86,15 +97,15 @@ def object_merge(
 
 
 def recursive_get(
-    obj: Union[DynaBox, Dict[str, int], Dict[str, Union[str, int]]],
-    names: Optional[List[str]],
+    obj: DynaBox | dict[str, int] | dict[str, str | int],
+    names: list[str] | None,
 ) -> Any:
     """Given a dot accessible object and a list of names `foo.bar.zaz`
-    gets recursivelly all names one by one obj.foo.bar.zaz.
+    gets recursively all names one by one obj.foo.bar.zaz.
     """
     if not names:
         return
-    head, tail = names[0], names[1:]
+    head, *tail = names
     result = getattr(obj, head, None)
     if not tail:
         return result
@@ -102,7 +113,7 @@ def recursive_get(
 
 
 def handle_metavalues(
-    old: Union[DynaBox, Dict[str, int], Dict[str, Union[str, int]]], new: Any
+    old: DynaBox | dict[str, int] | dict[str, str | int], new: Any
 ) -> None:
     """Cleanup of MetaValues on new dict"""
 
@@ -111,7 +122,6 @@ def handle_metavalues(
         # MetaValue instances
         if getattr(new[key], "_dynaconf_reset", False):  # pragma: no cover
             # a Reset on `new` triggers reasign of existing data
-            # @reset is deprecated on v3.0.0
             new[key] = new[key].unwrap()
         elif getattr(new[key], "_dynaconf_del", False):
             # a Del on `new` triggers deletion of existing data
@@ -178,7 +188,7 @@ class DynaconfDict(dict):
         self._not_installed_warnings = []
         self._validate_only = kwargs.pop("validate_only", None)
         self._validate_exclude = kwargs.pop("validate_exclude", None)
-        super(DynaconfDict, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
 
     def set(self, key: str, value: str, *args, **kwargs) -> None:
         self[key] = value
@@ -208,7 +218,7 @@ RENAMED_VARS = {
 }
 
 
-def compat_kwargs(kwargs: Dict[str, Any]) -> None:
+def compat_kwargs(kwargs: dict[str, Any]) -> None:
     """To keep backwards compat change the kwargs to new names"""
     warn_deprecations(kwargs)
     for old, new in RENAMED_VARS.items():
@@ -230,7 +240,7 @@ class Missing:
         """Respond to boolean duck-typing."""
         return False
 
-    def __eq__(self, other: Union[DynaBox, Missing]) -> bool:
+    def __eq__(self, other: DynaBox | Missing) -> bool:
         """Equality check for a singleton."""
 
         return isinstance(other, self.__class__)
@@ -249,7 +259,7 @@ class Missing:
 missing = Missing()
 
 
-def deduplicate(list_object: List[str]) -> List[str]:
+def deduplicate(list_object: list[str]) -> list[str]:
     """Rebuild `list_object` removing duplicated and keeping order"""
     new = []
     for item in list_object:
@@ -269,8 +279,8 @@ def warn_deprecations(data: Any) -> None:
 
 
 def trimmed_split(
-    s: str, seps: Union[str, Tuple[str, str]] = (";", ",")
-) -> List[str]:
+    s: str, seps: str | tuple[str, str] = (";", ",")
+) -> list[str]:
     """Given a string s, split is by one of one of the seps."""
     for sep in seps:
         if sep not in s:
@@ -280,7 +290,7 @@ def trimmed_split(
     return [s]  # raw un-splitted
 
 
-def ensure_a_list(data: Any) -> Union[List[int], List[str]]:
+def ensure_a_list(data: Any) -> list[int] | list[str]:
     """Ensure data is a list or wrap it in a list"""
     if not data:
         return []
@@ -292,9 +302,7 @@ def ensure_a_list(data: Any) -> Union[List[int], List[str]]:
     return [data]
 
 
-def build_env_list(
-    obj: Union[Settings, LazySettings], env: Optional[str]
-) -> List[str]:
+def build_env_list(obj: Settings | LazySettings, env: str | None) -> list[str]:
     """Build env list for loaders to iterate.
 
     Arguments:
@@ -305,27 +313,27 @@ def build_env_list(
         [str] -- A list of string names of the envs to load.
     """
     # add the [default] env
-    env_list = [obj.get("DEFAULT_ENV_FOR_DYNACONF")]
+    env_list = [(obj.get("DEFAULT_ENV_FOR_DYNACONF") or "default").lower()]
 
     # compatibility with older versions that still uses [dynaconf] as
     # [default] env
-    global_env = obj.get("ENVVAR_PREFIX_FOR_DYNACONF") or "DYNACONF"
+    global_env = (obj.get("ENVVAR_PREFIX_FOR_DYNACONF") or "dynaconf").lower()
     if global_env not in env_list:
         env_list.append(global_env)
 
     # add the current env
-    if obj.current_env and obj.current_env not in env_list:
-        env_list.append(obj.current_env)
+    current_env = obj.current_env
+    if current_env and current_env.lower() not in env_list:
+        env_list.append(current_env.lower())
 
     # add a manually set env
-    if env and env not in env_list:
-        env_list.append(env)
+    if env and env.lower() not in env_list:
+        env_list.append(env.lower())
 
     # add the [global] env
-    env_list.append("GLOBAL")
+    env_list.append("global")
 
-    # loaders are responsible to change to lower/upper cases
-    return [env.lower() for env in env_list]
+    return env_list
 
 
 def upperfy(key: str) -> str:
@@ -355,7 +363,7 @@ def upperfy(key: str) -> str:
     return key.upper()
 
 
-def multi_replace(text: str, patterns: Dict[str, str]) -> str:
+def multi_replace(text: str, patterns: dict[str, str]) -> str:
     """Replaces multiple pairs in a string
 
     Arguments:
@@ -372,7 +380,7 @@ def multi_replace(text: str, patterns: Dict[str, str]) -> str:
 
 def extract_json_objects(
     text: str, decoder: JSONDecoder = JSONDecoder()
-) -> Iterator[Dict[str, Union[int, Dict[Any, Any]]]]:
+) -> Iterator[dict[str, int | dict[Any, Any]]]:
     """Find JSON objects in text, and yield the decoded JSON data
 
     Does not attempt to look for JSON arrays, text, or other JSON types outside
@@ -393,7 +401,7 @@ def extract_json_objects(
 
 
 def recursively_evaluate_lazy_format(
-    value: Any, settings: Union[Settings, LazySettings]
+    value: Any, settings: Settings | LazySettings
 ) -> Any:
     """Given a value as a data structure, traverse all its members
     to find Lazy values and evaluate it.
@@ -431,3 +439,23 @@ def isnamedtupleinstance(value):
     if not isinstance(f, tuple):
         return False
     return all(type(n) == str for n in f)
+
+
+def find_the_correct_casing(key: str, data: dict[str, Any]) -> str | None:
+    """Given a key, find the proper casing in data
+
+    Arguments:
+        key {str} -- A key to be searched in data
+        data {dict} -- A dict to be searched
+
+    Returns:
+        str -- The proper casing of the key in data
+    """
+    if key in data:
+        return key
+    for k in data.keys():
+        if k.lower() == key.lower():
+            return k
+        if k.replace(" ", "_").lower() == key.lower():
+            return k
+    return None
diff --git a/dynaconf/utils/boxing.py b/dynaconf/utils/boxing.py
index 9a30453..ff78f12 100644
--- a/dynaconf/utils/boxing.py
+++ b/dynaconf/utils/boxing.py
@@ -1,8 +1,10 @@
+from __future__ import annotations
+
 import inspect
 from functools import wraps
 
+from dynaconf.utils import find_the_correct_casing
 from dynaconf.utils import recursively_evaluate_lazy_format
-from dynaconf.utils import upperfy
 from dynaconf.utils.functional import empty
 from dynaconf.vendor.box import Box
 
@@ -33,18 +35,18 @@ class DynaBox(Box):
     @evaluate_lazy_format
     def __getattr__(self, item, *args, **kwargs):
         try:
-            return super(DynaBox, self).__getattr__(item, *args, **kwargs)
+            return super().__getattr__(item, *args, **kwargs)
         except (AttributeError, KeyError):
-            n_item = item.lower() if item.isupper() else upperfy(item)
-            return super(DynaBox, self).__getattr__(n_item, *args, **kwargs)
+            n_item = find_the_correct_casing(item, self) or item
+            return super().__getattr__(n_item, *args, **kwargs)
 
     @evaluate_lazy_format
     def __getitem__(self, item, *args, **kwargs):
         try:
-            return super(DynaBox, self).__getitem__(item, *args, **kwargs)
+            return super().__getitem__(item, *args, **kwargs)
         except (AttributeError, KeyError):
-            n_item = item.lower() if item.isupper() else upperfy(item)
-            return super(DynaBox, self).__getitem__(n_item, *args, **kwargs)
+            n_item = find_the_correct_casing(item, self) or item
+            return super().__getitem__(n_item, *args, **kwargs)
 
     def __copy__(self):
         return self.__class__(
@@ -58,22 +60,11 @@ class DynaBox(Box):
             box_settings=self._box_config.get("box_settings"),
         )
 
-    def _case_insensitive_get(self, item, default=None):
-        """adds a bit of overhead but allows case insensitive get
-        See issue: #486
-        """
-        lower_self = {k.casefold(): v for k, v in self.items()}
-        return lower_self.get(item.casefold(), default)
-
     @evaluate_lazy_format
     def get(self, item, default=None, *args, **kwargs):
-        if item not in self:  # toggle case
-            item = item.lower() if item.isupper() else upperfy(item)
-        value = super(DynaBox, self).get(item, empty, *args, **kwargs)
-        if value is empty:
-            # see Issue: #486
-            return self._case_insensitive_get(item, default)
-        return value
+        n_item = find_the_correct_casing(item, self) or item
+        value = super().get(n_item, empty, *args, **kwargs)
+        return value if value is not empty else default
 
     def __dir__(self):
         keys = list(self.keys())
diff --git a/dynaconf/utils/files.py b/dynaconf/utils/files.py
index 3331db5..ec6fbd8 100644
--- a/dynaconf/utils/files.py
+++ b/dynaconf/utils/files.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import inspect
 import io
 import os
@@ -10,7 +12,7 @@ def _walk_to_root(path, break_at=None):
     Directories starting from the given directory up to the root or break_at
     """
     if not os.path.exists(path):  # pragma: no cover
-        raise IOError("Starting path not found")
+        raise OSError("Starting path not found")
 
     if os.path.isfile(path):  # pragma: no cover
         path = os.path.dirname(path)
@@ -42,10 +44,13 @@ def find_file(filename=".env", project_root=None, skip_files=None, **kwargs):
     - Current working directory
 
     For each path in the `search_tree` it will also look for an
-    aditional `./config` folder.
+    additional `./config` folder.
     """
     search_tree = []
-    work_dir = os.getcwd()
+    try:
+        work_dir = os.getcwd()
+    except FileNotFoundError:
+        return ""
     skip_files = skip_files or []
 
     # If filename is an absolute path and exists, just return it
@@ -84,7 +89,7 @@ def find_file(filename=".env", project_root=None, skip_files=None, **kwargs):
 
 def read_file(path, **kwargs):
     content = ""
-    with io.open(path, **kwargs) as open_file:
+    with open(path, **kwargs) as open_file:
         content = open_file.read().strip()
     return content
 
diff --git a/dynaconf/utils/functional.py b/dynaconf/utils/functional.py
index 147d26a..c9a93af 100644
--- a/dynaconf/utils/functional.py
+++ b/dynaconf/utils/functional.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import copy
 import operator
 
diff --git a/dynaconf/utils/parse_conf.py b/dynaconf/utils/parse_conf.py
index c42b07a..ac3262d 100644
--- a/dynaconf/utils/parse_conf.py
+++ b/dynaconf/utils/parse_conf.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import json
 import os
 import re
@@ -9,7 +11,9 @@ from dynaconf.utils import isnamedtupleinstance
 from dynaconf.utils import multi_replace
 from dynaconf.utils import recursively_evaluate_lazy_format
 from dynaconf.utils.boxing import DynaBox
+from dynaconf.utils.functional import empty
 from dynaconf.vendor import toml
+from dynaconf.vendor import tomllib
 
 try:
     from jinja2 import Environment
@@ -80,6 +84,9 @@ class Merge(MetaValue):
     _dynaconf_merge = True
 
     def __init__(self, value, box_settings, unique=False):
+        if unique:
+            self._dynaconf_merge_unique = True
+
         self.box_settings = box_settings
 
         self.value = parse_conf_data(
@@ -162,19 +169,26 @@ class Lazy:
 
     _dynaconf_lazy_format = True
 
-    def __init__(self, value, formatter=Formatters.python_formatter):
+    def __init__(
+        self, value=empty, formatter=Formatters.python_formatter, casting=None
+    ):
         self.value = value
         self.formatter = formatter
+        self.casting = casting
 
     @property
     def context(self):
         """Builds a context for formatting."""
         return {"env": os.environ, "this": self.settings}
 
-    def __call__(self, settings):
+    def __call__(self, settings, validator_object=None):
         """LazyValue triggers format lazily."""
         self.settings = settings
-        return self.formatter(self.value, **self.context)
+        self.context["_validator_object"] = validator_object
+        result = self.formatter(self.value, **self.context)
+        if self.casting is not None:
+            result = self.casting(result)
+        return result
 
     def __str__(self):
         """Gives string representation for the object."""
@@ -188,6 +202,11 @@ class Lazy:
         """Encodes this object values to be serializable to json"""
         return f"@{self.formatter} {self.value}"
 
+    def set_casting(self, casting):
+        """Set the casting and return the instance."""
+        self.casting = casting
+        return self
+
 
 def try_to_encode(value, callback=str):
     """Tries to encode a value by verifying existence of `_dynaconf_encode`"""
@@ -210,11 +229,25 @@ def evaluate_lazy_format(f):
 
 
 converters = {
-    "@str": str,
-    "@int": int,
-    "@float": float,
-    "@bool": lambda value: str(value).lower() in true_values,
-    "@json": json.loads,
+    "@str": lambda value: value.set_casting(str)
+    if isinstance(value, Lazy)
+    else str(value),
+    "@int": lambda value: value.set_casting(int)
+    if isinstance(value, Lazy)
+    else int(value),
+    "@float": lambda value: value.set_casting(float)
+    if isinstance(value, Lazy)
+    else float(value),
+    "@bool": lambda value: value.set_casting(
+        lambda x: str(x).lower() in true_values
+    )
+    if isinstance(value, Lazy)
+    else str(value).lower() in true_values,
+    "@json": lambda value: value.set_casting(
+        lambda x: json.loads(x.replace("'", '"'))
+    )
+    if isinstance(value, Lazy)
+    else json.loads(value),
     "@format": lambda value: Lazy(value),
     "@jinja": lambda value: Lazy(value, formatter=Formatters.jinja_formatter),
     # Meta Values to trigger pre assignment actions
@@ -230,6 +263,7 @@ converters = {
     "@comment": lambda value: None,
     "@null": lambda value: None,
     "@none": lambda value: None,
+    "@empty": lambda value: empty,
 }
 
 
@@ -244,10 +278,22 @@ def get_converter(converter_key, value, box_settings):
 
 def parse_with_toml(data):
     """Uses TOML syntax to parse data"""
-    try:
-        return toml.loads(f"key={data}")["key"]
-    except (toml.TomlDecodeError, KeyError):
-        return data
+    try:  # try tomllib first
+        try:
+            return tomllib.loads(f"key={data}")["key"]
+        except (tomllib.TOMLDecodeError, KeyError):
+            return data
+    except UnicodeDecodeError:  # pragma: no cover
+        # fallback to toml (TBR in 4.0.0)
+        try:
+            return toml.loads(f"key={data}")["key"]
+        except (toml.TomlDecodeError, KeyError):
+            return data
+        warnings.warn(
+            "TOML files should have only UTF-8 encoded characters. "
+            "starting on 4.0.0 dynaconf will stop allowing invalid chars.",
+            DeprecationWarning,
+        )
 
 
 def _parse_conf_data(data, tomlfy=False, box_settings=None):
@@ -265,8 +311,12 @@ def _parse_conf_data(data, tomlfy=False, box_settings=None):
     # not enforced to not break backwards compatibility with custom loaders
     box_settings = box_settings or {}
 
-    cast_toggler = os.environ.get("AUTO_CAST_FOR_DYNACONF", "true").lower()
-    castenabled = cast_toggler not in false_values
+    castenabled = box_settings.get("AUTO_CAST_FOR_DYNACONF", empty)
+    if castenabled is empty:
+        castenabled = (
+            os.environ.get("AUTO_CAST_FOR_DYNACONF", "true").lower()
+            not in false_values
+        )
 
     if (
         castenabled
@@ -274,10 +324,23 @@ def _parse_conf_data(data, tomlfy=False, box_settings=None):
         and isinstance(data, str)
         and data.startswith(tuple(converters.keys()))
     ):
-        parts = data.partition(" ")
-        converter_key = parts[0]
-        value = parts[-1]
-        value = get_converter(converter_key, value, box_settings)
+        # Check combination token is used
+        comb_token = re.match(
+            f"^({'|'.join(converters.keys())}) @(jinja|format)",
+            data,
+        )
+        if comb_token:
+            tokens = comb_token.group(0)
+            converter_key_list = tokens.split(" ")
+            value = data.replace(tokens, "").strip()
+        else:
+            parts = data.partition(" ")
+            converter_key_list = [parts[0]]
+            value = parts[-1]
+
+        # Parse the converters iteratively
+        for converter_key in converter_key_list[::-1]:
+            value = get_converter(converter_key, value, box_settings)
     else:
         value = parse_with_toml(data) if tomlfy else data
 
@@ -289,7 +352,7 @@ def _parse_conf_data(data, tomlfy=False, box_settings=None):
 
 def parse_conf_data(data, tomlfy=False, box_settings=None):
 
-    # fix for https://github.com/rochacbruno/dynaconf/issues/595
+    # fix for https://github.com/dynaconf/dynaconf/issues/595
     if isnamedtupleinstance(data):
         return data
 
@@ -297,7 +360,6 @@ def parse_conf_data(data, tomlfy=False, box_settings=None):
     box_settings = box_settings or {}
 
     if isinstance(data, (tuple, list)):
-
         # recursively parse each sequence item
         return [
             parse_conf_data(item, tomlfy=tomlfy, box_settings=box_settings)
diff --git a/dynaconf/validator.py b/dynaconf/validator.py
index 225f5be..b85269f 100644
--- a/dynaconf/validator.py
+++ b/dynaconf/validator.py
@@ -5,11 +5,7 @@ from itertools import chain
 from types import MappingProxyType
 from typing import Any
 from typing import Callable
-from typing import Dict
-from typing import List
-from typing import Optional
 from typing import Sequence
-from typing import Union
 
 from dynaconf import validator_conditions
 from dynaconf.utils import ensure_a_list
@@ -27,7 +23,12 @@ EQUALITY_ATTRS = (
 
 
 class ValidationError(Exception):
-    pass
+    """Raised when a validation fails"""
+
+    def __init__(self, message: str, *args, **kwargs):
+        self.details = kwargs.pop("details", [])
+        super().__init__(message, *args, **kwargs)
+        self.message = message
 
 
 class Validator:
@@ -100,15 +101,16 @@ class Validator:
     def __init__(
         self,
         *names: str,
-        must_exist: Optional[bool] = None,
-        required: Optional[bool] = None,  # alias for `must_exist`
-        condition: Optional[Callable[[Any], bool]] = None,
-        when: Optional[Validator] = None,
-        env: Optional[Union[str, Sequence[str]]] = None,
-        messages: Optional[Dict[str, str]] = None,
-        cast: Optional[Callable[[Any], Any]] = None,
-        default: Optional[Union[Any, Callable[[Any, Validator], Any]]] = empty,
-        description: Optional[str] = None,
+        must_exist: bool | None = None,
+        required: bool | None = None,  # alias for `must_exist`
+        condition: Callable[[Any], bool] | None = None,
+        when: Validator | None = None,
+        env: str | Sequence[str] | None = None,
+        messages: dict[str, str] | None = None,
+        cast: Callable[[Any], Any] | None = None,
+        default: Any | Callable[[Any, Validator], Any] | None = empty,
+        description: str | None = None,
+        apply_default_on_none: bool | None = False,
         **operations: Any,
     ) -> None:
         # Copy immutable MappingProxyType as a mutable dict
@@ -130,7 +132,11 @@ class Validator:
         self.operations = operations
         self.default = default
         self.description = description
-        self.envs: Optional[Sequence[str]] = None
+        self.envs: Sequence[str] | None = None
+        self.apply_default_on_none = apply_default_on_none
+
+        # See #585
+        self.is_type_of = operations.get("is_type_of")
 
         if isinstance(env, str):
             self.envs = [env]
@@ -162,8 +168,9 @@ class Validator:
     def validate(
         self,
         settings: Any,
-        only: Optional[Union[str, Sequence]] = None,
-        exclude: Optional[Union[str, Sequence]] = None,
+        only: str | Sequence | None = None,
+        exclude: str | Sequence | None = None,
+        only_current_env: bool = False,
     ) -> None:
         """Raise ValidationError if invalid"""
         # If only or exclude are not set, this value always passes startswith
@@ -189,6 +196,15 @@ class Validator:
                 # if when is invalid, return canceling validation flow
                 return
 
+        if only_current_env:
+            if settings.current_env.upper() in map(
+                lambda s: s.upper(), self.envs
+            ):
+                self._validate_items(
+                    settings, settings.current_env, only=only, exclude=exclude
+                )
+            return
+
         # If only using current_env, skip using_env decoration (reload)
         if (
             len(self.envs) == 1
@@ -207,9 +223,9 @@ class Validator:
     def _validate_items(
         self,
         settings: Any,
-        env: Optional[str] = None,
-        only: Optional[Union[str, Sequence]] = None,
-        exclude: Optional[Union[str, Sequence]] = None,
+        env: str | None = None,
+        only: str | Sequence | None = None,
+        exclude: str | Sequence | None = None,
     ) -> None:
         env = env or settings.current_env
         for name in self.names:
@@ -230,49 +246,73 @@ class Validator:
             else:
                 default_value = empty
 
-            value = self.cast(settings.setdefault(name, default_value))
+            # THIS IS A FIX FOR #585 in contrast with #799
+            # toml considers signed strings "+-1" as integers
+            # however existing users are passing strings
+            # to default on validator (see #585)
+            # The solution we added on #667 introduced a new problem
+            # This fix here makes it to work for both cases.
+            if (
+                isinstance(default_value, str)
+                and default_value.startswith(("+", "-"))
+                and self.is_type_of is str
+            ):
+                # avoid TOML from parsing "+-1" as integer
+                default_value = f"'{default_value}'"
+
+            value = settings.setdefault(
+                name,
+                default_value,
+                apply_default_on_none=self.apply_default_on_none,
+            )
 
             # is name required but not exists?
             if self.must_exist is True and value is empty:
-                raise ValidationError(
-                    self.messages["must_exist_true"].format(name=name, env=env)
+                _message = self.messages["must_exist_true"].format(
+                    name=name, env=env
                 )
+                raise ValidationError(_message, details=[(self, _message)])
 
             if self.must_exist is False and value is not empty:
-                raise ValidationError(
-                    self.messages["must_exist_false"].format(
-                        name=name, env=env
-                    )
+                _message = self.messages["must_exist_false"].format(
+                    name=name, env=env
                 )
+                raise ValidationError(_message, details=[(self, _message)])
 
             if self.must_exist in (False, None) and value is empty:
                 continue
 
+            if self.cast:
+                # value or default value already set
+                # by settings.setdefault above
+                # however we need to cast it
+                # so we call .set again
+                value = self.cast(settings.get(name))
+                settings.set(name, value)
+
             # is there a callable condition?
             if self.condition is not None:
                 if not self.condition(value):
-                    raise ValidationError(
-                        self.messages["condition"].format(
-                            name=name,
-                            function=self.condition.__name__,
-                            value=value,
-                            env=env,
-                        )
+                    _message = self.messages["condition"].format(
+                        name=name,
+                        function=self.condition.__name__,
+                        value=value,
+                        env=env,
                     )
+                    raise ValidationError(_message, details=[(self, _message)])
 
             # operations
             for op_name, op_value in self.operations.items():
                 op_function = getattr(validator_conditions, op_name)
                 if not op_function(value, op_value):
-                    raise ValidationError(
-                        self.messages["operations"].format(
-                            name=name,
-                            operation=op_function.__name__,
-                            op_value=op_value,
-                            value=value,
-                            env=env,
-                        )
+                    _message = self.messages["operations"].format(
+                        name=name,
+                        operation=op_function.__name__,
+                        op_value=op_value,
+                        value=value,
+                        env=env,
                     )
+                    raise ValidationError(_message, details=[(self, _message)])
 
 
 class CombinedValidator(Validator):
@@ -296,8 +336,9 @@ class CombinedValidator(Validator):
     def validate(
         self,
         settings: Any,
-        only: Optional[Union[str, Sequence]] = None,
-        exclude: Optional[Union[str, Sequence]] = None,
+        only: str | Sequence | None = None,
+        exclude: str | Sequence | None = None,
+        only_current_env: bool = False,
     ) -> None:  # pragma: no cover
         raise NotImplementedError(
             "subclasses OrValidator or AndValidator implements this method"
@@ -310,28 +351,33 @@ class OrValidator(CombinedValidator):
     def validate(
         self,
         settings: Any,
-        only: Optional[Union[str, Sequence]] = None,
-        exclude: Optional[Union[str, Sequence]] = None,
+        only: str | Sequence | None = None,
+        exclude: str | Sequence | None = None,
+        only_current_env: bool = False,
     ) -> None:
         """Ensure at least one of the validators are valid"""
         errors = []
         for validator in self.validators:
             try:
-                validator.validate(settings, only=only, exclude=exclude)
+                validator.validate(
+                    settings,
+                    only=only,
+                    exclude=exclude,
+                    only_current_env=only_current_env,
+                )
             except ValidationError as e:
                 errors.append(e)
                 continue
             else:
                 return
 
-        raise ValidationError(
-            self.messages["combined"].format(
-                errors=" or ".join(
-                    str(e).replace("combined validators failed ", "")
-                    for e in errors
-                )
+        _message = self.messages["combined"].format(
+            errors=" or ".join(
+                str(e).replace("combined validators failed ", "")
+                for e in errors
             )
         )
+        raise ValidationError(_message, details=[(self, _message)])
 
 
 class AndValidator(CombinedValidator):
@@ -340,34 +386,39 @@ class AndValidator(CombinedValidator):
     def validate(
         self,
         settings: Any,
-        only: Optional[Union[str, Sequence]] = None,
-        exclude: Optional[Union[str, Sequence]] = None,
+        only: str | Sequence | None = None,
+        exclude: str | Sequence | None = None,
+        only_current_env: bool = False,
     ) -> None:
         """Ensure both the validators are valid"""
         errors = []
         for validator in self.validators:
             try:
-                validator.validate(settings, only=only, exclude=exclude)
+                validator.validate(
+                    settings,
+                    only=only,
+                    exclude=exclude,
+                    only_current_env=only_current_env,
+                )
             except ValidationError as e:
                 errors.append(e)
                 continue
 
         if errors:
-            raise ValidationError(
-                self.messages["combined"].format(
-                    errors=" and ".join(
-                        str(e).replace("combined validators failed ", "")
-                        for e in errors
-                    )
+            _message = self.messages["combined"].format(
+                errors=" and ".join(
+                    str(e).replace("combined validators failed ", "")
+                    for e in errors
                 )
             )
+            raise ValidationError(_message, details=[(self, _message)])
 
 
 class ValidatorList(list):
     def __init__(
         self,
         settings: Any,
-        validators: Optional[Sequence[Validator]] = None,
+        validators: Sequence[Validator] | None = None,
         *args: Validator,
         **kwargs: Any,
     ) -> None:
@@ -375,11 +426,11 @@ class ValidatorList(list):
             args = list(args) + list(validators)  # type: ignore
         self._only = kwargs.pop("validate_only", None)
         self._exclude = kwargs.pop("validate_exclude", None)
-        super(ValidatorList, self).__init__(args, **kwargs)  # type: ignore
+        super().__init__(args, **kwargs)  # type: ignore
         self.settings = settings
 
     def register(self, *args: Validator, **kwargs: Validator):
-        validators: List[Validator] = list(
+        validators: list[Validator] = list(
             chain.from_iterable(kwargs.values())  # type: ignore
         )
         validators.extend(args)
@@ -387,12 +438,10 @@ class ValidatorList(list):
             if validator and validator not in self:
                 self.append(validator)
 
-    def descriptions(
-        self, flat: bool = False
-    ) -> Dict[str, Union[str, List[str]]]:
+    def descriptions(self, flat: bool = False) -> dict[str, str | list[str]]:
 
         if flat:
-            descriptions: Dict[str, Union[str, List[str]]] = {}
+            descriptions: dict[str, str | list[str]] = {}
         else:
             descriptions = defaultdict(list)
 
@@ -410,8 +459,40 @@ class ValidatorList(list):
 
     def validate(
         self,
-        only: Optional[Union[str, Sequence]] = None,
-        exclude: Optional[Union[str, Sequence]] = None,
+        only: str | Sequence | None = None,
+        exclude: str | Sequence | None = None,
+        only_current_env: bool = False,
+    ) -> None:
+        for validator in self:
+            validator.validate(
+                self.settings,
+                only=only,
+                exclude=exclude,
+                only_current_env=only_current_env,
+            )
+
+    def validate_all(
+        self,
+        only: str | Sequence | None = None,
+        exclude: str | Sequence | None = None,
+        only_current_env: bool = False,
     ) -> None:
+        errors = []
+        details = []
         for validator in self:
-            validator.validate(self.settings, only=only, exclude=exclude)
+            try:
+                validator.validate(
+                    self.settings,
+                    only=only,
+                    exclude=exclude,
+                    only_current_env=only_current_env,
+                )
+            except ValidationError as e:
+                errors.append(e)
+                details.append((validator, str(e)))
+                continue
+
+        if errors:
+            raise ValidationError(
+                "; ".join(str(e) for e in errors), details=details
+            )
diff --git a/dynaconf/validator_conditions.py b/dynaconf/validator_conditions.py
index cb1c3f5..96d1510 100644
--- a/dynaconf/validator_conditions.py
+++ b/dynaconf/validator_conditions.py
@@ -2,6 +2,7 @@
 """
 Implement basic assertions to be used in assertion action
 """
+from __future__ import annotations
 
 
 def eq(value, other):
@@ -75,10 +76,15 @@ def len_min(value, other):
 
 
 def len_max(value, other):
-    """Maximum lenght"""
+    """Maximum length"""
     return len(value) <= other
 
 
 def startswith(value, term):
     """returns value.startswith(term) result"""
     return value.startswith(term)
+
+
+def endswith(value, term):
+    """returns value.endswith(term) result"""
+    return value.endswith(term)
diff --git a/dynaconf/vendor/box/__init__.py b/dynaconf/vendor/box/__init__.py
index fb02ed8..6ff6531 100644
--- a/dynaconf/vendor/box/__init__.py
+++ b/dynaconf/vendor/box/__init__.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
 __author__='Chris Griffith'
 __version__='4.2.3'
 from .box import Box
diff --git a/dynaconf/vendor/box/box.py b/dynaconf/vendor/box/box.py
index 5e14910..baf9ca3 100644
--- a/dynaconf/vendor/box/box.py
+++ b/dynaconf/vendor/box/box.py
@@ -1,20 +1,18 @@
-_Z='keys'
-_Y='box_settings'
-_X='default_box_attr'
-_W='Box is frozen'
-_V='modify_tuples_box'
-_U='box_safe_prefix'
-_T='default_box_none_transform'
-_S='__created'
-_R='box_dots'
-_Q='box_duplicates'
-_P='ignore'
-_O='.'
-_N='strict'
-_M='box_recast'
-_L='box_intact_types'
-_K='default_box'
-_J='_'
+#!/usr/bin/env python
+_W='box_settings'
+_V='default_box_attr'
+_U='Box is frozen'
+_T='modify_tuples_box'
+_S='box_safe_prefix'
+_R='default_box_none_transform'
+_Q='__created'
+_P='box_dots'
+_O='box_duplicates'
+_N='ignore'
+_M='strict'
+_L='box_recast'
+_K='box_intact_types'
+_J='default_box'
 _I='utf-8'
 _H='_box_config'
 _G=True
@@ -37,7 +35,7 @@ _first_cap_re=re.compile('(.)([A-Z][a-z]+)')
 _all_cap_re=re.compile('([a-z0-9])([A-Z])')
 _list_pos_re=re.compile('\\[(\\d+)\\]')
 NO_DEFAULT=object()
-def _camel_killer(attr):D='\\1_\\2';A=attr;A=str(A);B=_first_cap_re.sub(D,A);C=_all_cap_re.sub(D,B);return re.sub(' *_+',_J,C.lower())
+def _camel_killer(attr):B='\\1_\\2';A=attr;A=str(A);C=_first_cap_re.sub(B,A);D=_all_cap_re.sub(B,C);return re.sub(' *_+','_',D.lower())
 def _recursive_tuples(iterable,box_class,recreate_tuples=_B,**E):
 	D=recreate_tuples;C=box_class;B=[]
 	for A in iterable:
@@ -49,21 +47,21 @@ def _parse_box_dots(item):
 	A=item
 	for (B,C) in enumerate(A):
 		if C=='[':return A[:B],A[B:]
-		elif C==_O:return A[:B],A[B+1:]
+		elif C=='.':return A[:B],A[B+1:]
 	raise BoxError('Could not split box dots properly')
-def _get_box_config():return{_S:_B,_C:{}}
+def _get_box_config():return{_Q:_B,_C:{}}
 class Box(dict):
-	_protected_keys=['to_dict','to_json','to_yaml','from_yaml','from_json','from_toml','to_toml','merge_update']+[A for A in dir({})if not A.startswith(_J)]
-	def __new__(A,*D,box_settings=_A,default_box=_B,default_box_attr=NO_DEFAULT,default_box_none_transform=_G,frozen_box=_B,camel_killer_box=_B,conversion_box=_G,modify_tuples_box=_B,box_safe_prefix='x',box_duplicates=_P,box_intact_types=(),box_recast=_A,box_dots=_B,**E):C=default_box_attr;B=super(Box,A).__new__(A,*D,**E);B._box_config=_get_box_config();B._box_config.update({_K:default_box,_X:A.__class__ if C is NO_DEFAULT else C,_T:default_box_none_transform,_E:conversion_box,_U:box_safe_prefix,_D:frozen_box,_F:camel_killer_box,_V:modify_tuples_box,_Q:box_duplicates,_L:tuple(box_intact_types),_M:box_recast,_R:box_dots,_Y:box_settings or{}});return B
-	def __init__(A,*B,box_settings=_A,default_box=_B,default_box_attr=NO_DEFAULT,default_box_none_transform=_G,frozen_box=_B,camel_killer_box=_B,conversion_box=_G,modify_tuples_box=_B,box_safe_prefix='x',box_duplicates=_P,box_intact_types=(),box_recast=_A,box_dots=_B,**F):
-		E=default_box_attr;super().__init__();A._box_config=_get_box_config();A._box_config.update({_K:default_box,_X:A.__class__ if E is NO_DEFAULT else E,_T:default_box_none_transform,_E:conversion_box,_U:box_safe_prefix,_D:frozen_box,_F:camel_killer_box,_V:modify_tuples_box,_Q:box_duplicates,_L:tuple(box_intact_types),_M:box_recast,_R:box_dots,_Y:box_settings or{}})
-		if not A._box_config[_E]and A._box_config[_Q]!=_P:raise BoxError('box_duplicates are only for conversion_boxes')
+	_protected_keys=['to_dict','to_json','to_yaml','from_yaml','from_json','from_toml','to_toml','merge_update']+[A for A in dir({})if not A.startswith('_')]
+	def __new__(A,*D,box_settings=_A,default_box=_B,default_box_attr=NO_DEFAULT,default_box_none_transform=_G,frozen_box=_B,camel_killer_box=_B,conversion_box=_G,modify_tuples_box=_B,box_safe_prefix='x',box_duplicates=_N,box_intact_types=(),box_recast=_A,box_dots=_B,**E):C=default_box_attr;B=super(Box,A).__new__(A,*(D),**E);B._box_config=_get_box_config();B._box_config.update({_J:default_box,_V:A.__class__ if C is NO_DEFAULT else C,_R:default_box_none_transform,_E:conversion_box,_S:box_safe_prefix,_D:frozen_box,_F:camel_killer_box,_T:modify_tuples_box,_O:box_duplicates,_K:tuple(box_intact_types),_L:box_recast,_P:box_dots,_W:box_settings or{}});return B
+	def __init__(A,*B,box_settings=_A,default_box=_B,default_box_attr=NO_DEFAULT,default_box_none_transform=_G,frozen_box=_B,camel_killer_box=_B,conversion_box=_G,modify_tuples_box=_B,box_safe_prefix='x',box_duplicates=_N,box_intact_types=(),box_recast=_A,box_dots=_B,**F):
+		E=default_box_attr;super().__init__();A._box_config=_get_box_config();A._box_config.update({_J:default_box,_V:A.__class__ if E is NO_DEFAULT else E,_R:default_box_none_transform,_E:conversion_box,_S:box_safe_prefix,_D:frozen_box,_F:camel_killer_box,_T:modify_tuples_box,_O:box_duplicates,_K:tuple(box_intact_types),_L:box_recast,_P:box_dots,_W:box_settings or{}})
+		if not A._box_config[_E]and A._box_config[_O]!=_N:raise BoxError('box_duplicates are only for conversion_boxes')
 		if len(B)==1:
 			if isinstance(B[0],str):raise BoxValueError('Cannot extrapolate Box from string')
 			if isinstance(B[0],Mapping):
 				for (D,C) in B[0].items():
 					if C is B[0]:C=A
-					if C is _A and A._box_config[_K]and A._box_config[_T]:continue
+					if C is _A and A._box_config[_J]and A._box_config[_R]:continue
 					A.__setitem__(D,C)
 			elif isinstance(B[0],Iterable):
 				for (D,C) in B[0]:A.__setitem__(D,C)
@@ -72,7 +70,7 @@ class Box(dict):
 		for (D,C) in F.items():
 			if B and isinstance(B[0],Mapping)and C is B[0]:C=A
 			A.__setitem__(D,C)
-		A._box_config[_S]=_G
+		A._box_config[_Q]=_G
 	def __add__(C,other):
 		A=other;B=C.copy()
 		if not isinstance(A,dict):raise BoxTypeError(f"Box can only merge two boxes or a box and a dictionary.")
@@ -84,7 +82,7 @@ class Box(dict):
 			return B
 		raise BoxTypeError('unhashable type: "Box"')
 	def __dir__(B):
-		D=string.ascii_letters+string.digits+_J;C=set(super().__dir__())
+		D=string.ascii_letters+string.digits+'_';C=set(super().__dir__())
 		for A in B.keys():
 			A=str(A)
 			if' 'not in A and A[0]not in string.digits and A not in kwlist:
@@ -101,9 +99,9 @@ class Box(dict):
 		C=key;A=default
 		if C not in B:
 			if A is NO_DEFAULT:
-				if B._box_config[_K]and B._box_config[_T]:return B.__get_default(C)
+				if B._box_config[_J]and B._box_config[_R]:return B.__get_default(C)
 				else:return _A
-			if isinstance(A,dict)and not isinstance(A,Box):return Box(A,box_settings=B._box_config.get(_Y))
+			if isinstance(A,dict)and not isinstance(A,Box):return Box(A,box_settings=B._box_config.get(_W))
 			if isinstance(A,list)and not isinstance(A,box.BoxList):return box.BoxList(A)
 			return A
 		return B[C]
@@ -118,7 +116,7 @@ class Box(dict):
 	def values(A):return[A[B]for B in A.keys()]
 	def items(A):return[(B,A[B])for B in A.keys()]
 	def __get_default(B,item):
-		A=B._box_config[_X]
+		A=B._box_config[_V]
 		if A in(B.__class__,dict):C=B.__class__(**B.__box_config())
 		elif isinstance(A,dict):C=B.__class__(**B.__box_config(),**A)
 		elif isinstance(A,list):C=box.BoxList(**B.__box_config())
@@ -133,34 +131,34 @@ class Box(dict):
 		return A
 	def __recast(A,item,value):
 		C=value;B=item
-		if A._box_config[_M]and B in A._box_config[_M]:
-			try:return A._box_config[_M][B](C)
-			except ValueError:raise BoxValueError(f"Cannot convert {C} to {A._box_config[_M][B]}") from _A
+		if A._box_config[_L]and B in A._box_config[_L]:
+			try:return A._box_config[_L][B](C)
+			except ValueError:raise BoxValueError(f"Cannot convert {C} to {A._box_config[_L][B]}") from _A
 		return C
 	def __convert_and_store(B,item,value):
 		C=item;A=value
 		if B._box_config[_E]:D=B._safe_attr(C);B._box_config[_C][D]=C
 		if isinstance(A,(int,float,str,bytes,bytearray,bool,complex,set,frozenset)):return super().__setitem__(C,A)
-		if B._box_config[_L]and isinstance(A,B._box_config[_L]):return super().__setitem__(C,A)
+		if B._box_config[_K]and isinstance(A,B._box_config[_K]):return super().__setitem__(C,A)
 		if isinstance(A,dict)and not isinstance(A,Box):A=B.__class__(A,**B.__box_config())
 		elif isinstance(A,list)and not isinstance(A,box.BoxList):
-			if B._box_config[_D]:A=_recursive_tuples(A,B.__class__,recreate_tuples=B._box_config[_V],**B.__box_config())
+			if B._box_config[_D]:A=_recursive_tuples(A,B.__class__,recreate_tuples=B._box_config[_T],**B.__box_config())
 			else:A=box.BoxList(A,box_class=B.__class__,**B.__box_config())
-		elif B._box_config[_V]and isinstance(A,tuple):A=_recursive_tuples(A,B.__class__,recreate_tuples=_G,**B.__box_config())
+		elif B._box_config[_T]and isinstance(A,tuple):A=_recursive_tuples(A,B.__class__,recreate_tuples=_G,**B.__box_config())
 		super().__setitem__(C,A)
 	def __getitem__(B,item,_ignore_default=_B):
 		A=item
 		try:return super().__getitem__(A)
 		except KeyError as E:
 			if A==_H:raise BoxKeyError('_box_config should only exist as an attribute and is never defaulted') from _A
-			if B._box_config[_R]and isinstance(A,str)and(_O in A or'['in A):
+			if B._box_config[_P]and isinstance(A,str)and('.'in A or'['in A):
 				C,F=_parse_box_dots(A)
 				if C in B.keys():
 					if hasattr(B[C],'__getitem__'):return B[C][F]
 			if B._box_config[_F]and isinstance(A,str):
 				D=_camel_killer(A)
 				if D in B.keys():return super().__getitem__(D)
-			if B._box_config[_K]and not _ignore_default:return B.__get_default(A)
+			if B._box_config[_J]and not _ignore_default:return B.__get_default(A)
 			raise BoxKeyError(str(E)) from _A
 	def __getattr__(A,item):
 		B=item
@@ -173,24 +171,24 @@ class Box(dict):
 			if A._box_config[_E]:
 				D=A._safe_attr(B)
 				if D in A._box_config[_C]:return A.__getitem__(A._box_config[_C][D])
-			if A._box_config[_K]:return A.__get_default(B)
+			if A._box_config[_J]:return A.__get_default(B)
 			raise BoxKeyError(str(E)) from _A
 		return C
 	def __setitem__(A,key,value):
 		C=value;B=key
-		if B!=_H and A._box_config[_S]and A._box_config[_D]:raise BoxError(_W)
-		if A._box_config[_R]and isinstance(B,str)and _O in B:
+		if B!=_H and A._box_config[_Q]and A._box_config[_D]:raise BoxError(_U)
+		if A._box_config[_P]and isinstance(B,str)and'.'in B:
 			D,E=_parse_box_dots(B)
 			if D in A.keys():
 				if hasattr(A[D],'__setitem__'):return A[D].__setitem__(E,C)
 		C=A.__recast(B,C)
 		if B not in A.keys()and A._box_config[_F]:
 			if A._box_config[_F]and isinstance(B,str):B=_camel_killer(B)
-		if A._box_config[_E]and A._box_config[_Q]!=_P:A._conversion_checks(B)
+		if A._box_config[_E]and A._box_config[_O]!=_N:A._conversion_checks(B)
 		A.__convert_and_store(B,C)
 	def __setattr__(A,key,value):
 		C=value;B=key
-		if B!=_H and A._box_config[_D]and A._box_config[_S]:raise BoxError(_W)
+		if B!=_H and A._box_config[_D]and A._box_config[_Q]:raise BoxError(_U)
 		if B in A._protected_keys:raise BoxKeyError(f'Key name "{B}" is protected')
 		if B==_H:return object.__setattr__(A,B,C)
 		C=A.__recast(B,C);D=A._safe_attr(B)
@@ -198,9 +196,9 @@ class Box(dict):
 		A.__setitem__(B,C)
 	def __delitem__(A,key):
 		B=key
-		if A._box_config[_D]:raise BoxError(_W)
-		if B not in A.keys()and A._box_config[_R]and isinstance(B,str)and _O in B:
-			C,E=B.split(_O,1)
+		if A._box_config[_D]:raise BoxError(_U)
+		if B not in A.keys()and A._box_config[_P]and isinstance(B,str)and'.'in B:
+			C,E=B.split('.',1)
 			if C in A.keys()and isinstance(A[C],dict):return A[C].__delitem__(E)
 		if B not in A.keys()and A._box_config[_F]:
 			if A._box_config[_F]and isinstance(B,str):
@@ -209,7 +207,7 @@ class Box(dict):
 		super().__delitem__(B)
 	def __delattr__(A,item):
 		B=item
-		if A._box_config[_D]:raise BoxError(_W)
+		if A._box_config[_D]:raise BoxError(_U)
 		if B==_H:raise BoxError('"_box_config" is protected')
 		if B in A._protected_keys:raise BoxKeyError(f'Key name "{B}" is protected')
 		try:A.__delitem__(B)
@@ -249,7 +247,7 @@ class Box(dict):
 	def update(C,__m=_A,**D):
 		B=__m
 		if B:
-			if hasattr(B,_Z):
+			if hasattr(B,'keys'):
 				for A in B:C.__convert_and_store(A,B[A])
 			else:
 				for (A,E) in B:C.__convert_and_store(A,E)
@@ -257,7 +255,7 @@ class Box(dict):
 	def merge_update(A,__m=_A,**E):
 		C=__m
 		def D(k,v):
-			B=A._box_config[_L]and isinstance(v,A._box_config[_L])
+			B=A._box_config[_K]and isinstance(v,A._box_config[_K])
 			if isinstance(v,dict)and not B:
 				v=A.__class__(v,**A.__box_config())
 				if k in A and isinstance(A[k],dict):
@@ -267,7 +265,7 @@ class Box(dict):
 			if isinstance(v,list)and not B:v=box.BoxList(v,**A.__box_config())
 			A.__setitem__(k,v)
 		if C:
-			if hasattr(C,_Z):
+			if hasattr(C,'keys'):
 				for B in C:D(B,C[B])
 			else:
 				for (B,F) in C:D(B,F)
@@ -279,48 +277,48 @@ class Box(dict):
 		if isinstance(A,list):A=box.BoxList(A,box_class=B.__class__,**B.__box_config())
 		B[C]=A;return A
 	def _safe_attr(C,attr):
-		B=attr;G=string.ascii_letters+string.digits+_J
-		if isinstance(B,tuple):B=_J.join([str(A)for A in B])
-		B=B.decode(_I,_P)if isinstance(B,bytes)else str(B)
+		B=attr;G=string.ascii_letters+string.digits+'_'
+		if isinstance(B,tuple):B='_'.join([str(A)for A in B])
+		B=B.decode(_I,_N)if isinstance(B,bytes)else str(B)
 		if C.__box_config()[_F]:B=_camel_killer(B)
 		A=[];D=0
 		for (E,F) in enumerate(B):
 			if F in G:D=E;A.append(F)
 			elif not A:continue
-			elif D==E-1:A.append(_J)
+			elif D==E-1:A.append('_')
 		A=''.join(A)[:D+1]
 		try:int(A[0])
 		except (ValueError,IndexError):pass
-		else:A=f"{C.__box_config()[_U]}{A}"
-		if A in kwlist:A=f"{C.__box_config()[_U]}{A}"
+		else:A=f"{C.__box_config()[_S]}{A}"
+		if A in kwlist:A=f"{C.__box_config()[_S]}{A}"
 		return A
 	def _conversion_checks(A,item):
 		B=A._safe_attr(item)
 		if B in A._box_config[_C]:
 			C=[f"{item}({B})",f"{A._box_config[_C][B]}({B})"]
-			if A._box_config[_Q].startswith('warn'):warnings.warn(f"Duplicate conversion attributes exist: {C}",BoxWarning)
+			if A._box_config[_O].startswith('warn'):warnings.warn(f"Duplicate conversion attributes exist: {C}",BoxWarning)
 			else:raise BoxError(f"Duplicate conversion attributes exist: {C}")
-	def to_json(A,filename=_A,encoding=_I,errors=_N,**B):return _to_json(A.to_dict(),filename=filename,encoding=encoding,errors=errors,**B)
+	def to_json(A,filename=_A,encoding=_I,errors=_M,**B):return _to_json(A.to_dict(),filename=filename,encoding=encoding,errors=errors,**B)
 	@classmethod
-	def from_json(E,json_string=_A,filename=_A,encoding=_I,errors=_N,**A):
+	def from_json(E,json_string=_A,filename=_A,encoding=_I,errors=_M,**A):
 		D={}
 		for B in A.copy():
 			if B in BOX_PARAMETERS:D[B]=A.pop(B)
 		C=_from_json(json_string,filename=filename,encoding=encoding,errors=errors,**A)
 		if not isinstance(C,dict):raise BoxError(f"json data not returned as a dictionary, but rather a {type(C).__name__}")
 		return E(C,**D)
-	def to_yaml(A,filename=_A,default_flow_style=_B,encoding=_I,errors=_N,**B):return _to_yaml(A.to_dict(),filename=filename,default_flow_style=default_flow_style,encoding=encoding,errors=errors,**B)
+	def to_yaml(A,filename=_A,default_flow_style=_B,encoding=_I,errors=_M,**B):return _to_yaml(A.to_dict(),filename=filename,default_flow_style=default_flow_style,encoding=encoding,errors=errors,**B)
 	@classmethod
-	def from_yaml(E,yaml_string=_A,filename=_A,encoding=_I,errors=_N,**A):
+	def from_yaml(E,yaml_string=_A,filename=_A,encoding=_I,errors=_M,**A):
 		D={}
 		for B in A.copy():
 			if B in BOX_PARAMETERS:D[B]=A.pop(B)
 		C=_from_yaml(yaml_string=yaml_string,filename=filename,encoding=encoding,errors=errors,**A)
 		if not isinstance(C,dict):raise BoxError(f"yaml data not returned as a dictionary but rather a {type(C).__name__}")
 		return E(C,**D)
-	def to_toml(A,filename=_A,encoding=_I,errors=_N):return _to_toml(A.to_dict(),filename=filename,encoding=encoding,errors=errors)
+	def to_toml(A,filename=_A,encoding=_I,errors=_M):return _to_toml(A.to_dict(),filename=filename,encoding=encoding,errors=errors)
 	@classmethod
-	def from_toml(D,toml_string=_A,filename=_A,encoding=_I,errors=_N,**B):
+	def from_toml(D,toml_string=_A,filename=_A,encoding=_I,errors=_M,**B):
 		C={}
 		for A in B.copy():
 			if A in BOX_PARAMETERS:C[A]=B.pop(A)
diff --git a/dynaconf/vendor/box/box_list.py b/dynaconf/vendor/box/box_list.py
index 9c03a67..50584c9 100644
--- a/dynaconf/vendor/box/box_list.py
+++ b/dynaconf/vendor/box/box_list.py
@@ -1,4 +1,4 @@
-_H='toml'
+#!/usr/bin/env python
 _G='box_dots'
 _F='BoxList is frozen'
 _E='frozen_box'
@@ -44,11 +44,11 @@ class BoxList(list):
 			return super(BoxList,B).__getitem__(E).__setitem__(A[len(D.group()):].lstrip('.'),C)
 		super(BoxList,B).__setitem__(A,C)
 	def _is_intact_type(A,obj):
-		C='box_intact_types'
+		B='box_intact_types'
 		try:
-			if A.box_options.get(C)and isinstance(obj,A.box_options[C]):return True
-		except AttributeError as B:
-			if'box_options'in A.__dict__:raise BoxKeyError(B)
+			if A.box_options.get(B)and isinstance(obj,A.box_options[B]):return True
+		except AttributeError as C:
+			if'box_options'in A.__dict__:raise BoxKeyError(C)
 		return _D
 	def append(A,p_object):
 		B=p_object
@@ -109,9 +109,9 @@ class BoxList(list):
 		C=_from_yaml(yaml_string=yaml_string,filename=filename,encoding=encoding,errors=errors,**A)
 		if not isinstance(C,list):raise BoxError(f"yaml data not returned as a list but rather a {type(C).__name__}")
 		return E(C,**D)
-	def to_toml(A,filename=_A,key_name=_H,encoding=_B,errors=_C):return _to_toml({key_name:A.to_list()},filename=filename,encoding=encoding,errors=errors)
+	def to_toml(A,filename=_A,key_name='toml',encoding=_B,errors=_C):return _to_toml({key_name:A.to_list()},filename=filename,encoding=encoding,errors=errors)
 	@classmethod
-	def from_toml(F,toml_string=_A,filename=_A,key_name=_H,encoding=_B,errors=_C,**C):
+	def from_toml(F,toml_string=_A,filename=_A,key_name='toml',encoding=_B,errors=_C,**C):
 		A=key_name;D={}
 		for B in list(C.keys()):
 			if B in BOX_PARAMETERS:D[B]=C.pop(B)
diff --git a/dynaconf/vendor/box/config_box.py b/dynaconf/vendor/box/config_box.py
index 1194963..d9934e5 100644
--- a/dynaconf/vendor/box/config_box.py
+++ b/dynaconf/vendor/box/config_box.py
@@ -1,27 +1,24 @@
-_H='getint'
-_G='getfloat'
-_F='getboolean'
-_E='list'
-_D='float'
-_C='int'
-_B='bool'
+#!/usr/bin/env python
+_D='getint'
+_C='getfloat'
+_B='getboolean'
 _A=None
 from dynaconf.vendor.box.box import Box
 class ConfigBox(Box):
-	_protected_keys=dir(Box)+[_B,_C,_D,_E,_F,_G,_H]
+	_protected_keys=dir(Box)+['bool','int','float','list',_B,_C,_D]
 	def __getattr__(A,item):
 		try:return super().__getattr__(item)
 		except AttributeError:return super().__getattr__(item.lower())
-	def __dir__(A):return super().__dir__()+[_B,_C,_D,_E,_F,_G,_H]
-	def bool(C,item,default=_A):
-		E=False;B=default;A=item
-		try:A=C.__getattr__(A)
-		except AttributeError as D:
+	def __dir__(A):return super().__dir__()+['bool','int','float','list',_B,_C,_D]
+	def bool(D,item,default=_A):
+		C=False;B=default;A=item
+		try:A=D.__getattr__(A)
+		except AttributeError as E:
 			if B is not _A:return B
-			raise D
+			raise E
 		if isinstance(A,(bool,int)):return bool(A)
-		if isinstance(A,str)and A.lower()in('n','no','false','f','0'):return E
-		return True if A else E
+		if isinstance(A,str)and A.lower()in('n','no','false','f','0'):return C
+		return True if A else C
 	def int(C,item,default=_A):
 		B=default;A=item
 		try:A=C.__getattr__(A)
diff --git a/dynaconf/vendor/box/converters.py b/dynaconf/vendor/box/converters.py
index 93cdcfb..5b420a5 100644
--- a/dynaconf/vendor/box/converters.py
+++ b/dynaconf/vendor/box/converters.py
@@ -1,5 +1,4 @@
-_G='r'
-_F='w'
+#!/usr/bin/env python
 _E=False
 _D=True
 _C='strict'
@@ -9,7 +8,7 @@ import csv,json,sys,warnings
 from pathlib import Path
 import dynaconf.vendor.ruamel.yaml as yaml
 from dynaconf.vendor.box.exceptions import BoxError,BoxWarning
-from dynaconf.vendor import toml
+from dynaconf.vendor import tomllib as toml
 BOX_PARAMETERS='default_box','default_box_attr','conversion_box','frozen_box','camel_killer_box','box_safe_prefix','box_duplicates','ordered_box','default_box_none_transform','box_dots','modify_tuples_box','box_intact_types','box_recast'
 def _exists(filename,create=_E):
 	A=filename;B=Path(A)
@@ -23,13 +22,13 @@ def _to_json(obj,filename=_A,encoding=_B,errors=_C,**C):
 	A=filename;B=json.dumps(obj,ensure_ascii=_E,**C)
 	if A:
 		_exists(A,create=_D)
-		with open(A,_F,encoding=encoding,errors=errors)as D:D.write(B if sys.version_info>=(3,0)else B.decode(_B))
+		with open(A,'w',encoding=encoding,errors=errors)as D:D.write(B if sys.version_info>=(3,0)else B.decode(_B))
 	else:return B
 def _from_json(json_string=_A,filename=_A,encoding=_B,errors=_C,multiline=_E,**B):
 	D=json_string;A=filename
 	if A:
 		_exists(A)
-		with open(A,_G,encoding=encoding,errors=errors)as E:
+		with open(A,'r',encoding=encoding,errors=errors)as E:
 			if multiline:C=[json.loads(A.strip(),**B)for A in E if A.strip()and not A.strip().startswith('#')]
 			else:C=json.load(E,**B)
 	elif D:C=json.loads(D,**B)
@@ -39,14 +38,14 @@ def _to_yaml(obj,filename=_A,default_flow_style=_E,encoding=_B,errors=_C,**C):
 	B=default_flow_style;A=filename
 	if A:
 		_exists(A,create=_D)
-		with open(A,_F,encoding=encoding,errors=errors)as D:yaml.dump(obj,stream=D,default_flow_style=B,**C)
+		with open(A,'w',encoding=encoding,errors=errors)as D:yaml.dump(obj,stream=D,default_flow_style=B,**C)
 	else:return yaml.dump(obj,default_flow_style=B,**C)
 def _from_yaml(yaml_string=_A,filename=_A,encoding=_B,errors=_C,**A):
-	F='Loader';C=yaml_string;B=filename
-	if F not in A:A[F]=yaml.SafeLoader
+	E='Loader';C=yaml_string;B=filename
+	if E not in A:A[E]=yaml.SafeLoader
 	if B:
 		_exists(B)
-		with open(B,_G,encoding=encoding,errors=errors)as E:D=yaml.load(E,**A)
+		with open(B,'r',encoding=encoding,errors=errors)as F:D=yaml.load(F,**A)
 	elif C:D=yaml.load(C,**A)
 	else:raise BoxError('from_yaml requires a string or filename')
 	return D
@@ -54,13 +53,13 @@ def _to_toml(obj,filename=_A,encoding=_B,errors=_C):
 	A=filename
 	if A:
 		_exists(A,create=_D)
-		with open(A,_F,encoding=encoding,errors=errors)as B:toml.dump(obj,B)
+		with open(A,'w',encoding=encoding,errors=errors)as B:toml.dump(obj,B)
 	else:return toml.dumps(obj)
 def _from_toml(toml_string=_A,filename=_A,encoding=_B,errors=_C):
 	B=toml_string;A=filename
 	if A:
 		_exists(A)
-		with open(A,_G,encoding=encoding,errors=errors)as D:C=toml.load(D)
+		with open(A,'r',encoding=encoding,errors=errors)as D:C=toml.load(D)
 	elif B:C=toml.loads(B)
 	else:raise BoxError('from_toml requires a string or filename')
 	return C
@@ -70,9 +69,9 @@ def _to_csv(box_list,filename,encoding=_B,errors=_C):
 		if list(E.keys())!=C:raise BoxError('BoxList must contain the same dictionary structure for every item to convert to csv')
 	if B:
 		_exists(B,create=_D)
-		with open(B,_F,encoding=encoding,errors=errors,newline='')as F:
+		with open(B,'w',encoding=encoding,errors=errors,newline='')as F:
 			D=csv.DictWriter(F,fieldnames=C);D.writeheader()
 			for G in A:D.writerow(G)
 def _from_csv(filename,encoding=_B,errors=_C):
 	A=filename;_exists(A)
-	with open(A,_G,encoding=encoding,errors=errors,newline='')as B:C=csv.DictReader(B);return[A for A in C]
\ No newline at end of file
+	with open(A,'r',encoding=encoding,errors=errors,newline='')as B:C=csv.DictReader(B);return[A for A in C]
\ No newline at end of file
diff --git a/dynaconf/vendor/box/exceptions.py b/dynaconf/vendor/box/exceptions.py
index 66199e7..8133455 100644
--- a/dynaconf/vendor/box/exceptions.py
+++ b/dynaconf/vendor/box/exceptions.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
 class BoxError(Exception):0
 class BoxKeyError(BoxError,KeyError,AttributeError):0
 class BoxTypeError(BoxError,TypeError):0
diff --git a/dynaconf/vendor/box/from_file.py b/dynaconf/vendor/box/from_file.py
index daa1137..5e0f484 100644
--- a/dynaconf/vendor/box/from_file.py
+++ b/dynaconf/vendor/box/from_file.py
@@ -1,7 +1,8 @@
+#!/usr/bin/env python
 from json import JSONDecodeError
 from pathlib import Path
 from typing import Union
-from dynaconf.vendor.toml import TomlDecodeError
+from dynaconf.vendor.tomllib import TOMLDecodeError
 from dynaconf.vendor.ruamel.yaml import YAMLError
 from .exceptions import BoxError
 from .box import Box
@@ -17,7 +18,7 @@ def _to_yaml(data):
 	except BoxError:return BoxList.from_yaml(data)
 def _to_toml(data):
 	try:return Box.from_toml(data)
-	except TomlDecodeError:raise BoxError('File is not TOML as expected')
+	except TOMLDecodeError:raise BoxError('File is not TOML as expected')
 def box_from_file(file,file_type=None,encoding='utf-8',errors='strict'):
 	C=file_type;A=file
 	if not isinstance(A,Path):A=Path(A)
diff --git a/dynaconf/vendor/box/shorthand_box.py b/dynaconf/vendor/box/shorthand_box.py
index b6da19c..2347405 100644
--- a/dynaconf/vendor/box/shorthand_box.py
+++ b/dynaconf/vendor/box/shorthand_box.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
 from dynaconf.vendor.box.box import Box
 class SBox(Box):
 	_protected_keys=dir({})+['to_dict','to_json','to_yaml','json','yaml','from_yaml','from_json','dict','toml','from_toml','to_toml']
diff --git a/dynaconf/vendor/click/_bashcomplete.py b/dynaconf/vendor/click/_bashcomplete.py
index e27049d..7f7c2e8 100644
--- a/dynaconf/vendor/click/_bashcomplete.py
+++ b/dynaconf/vendor/click/_bashcomplete.py
@@ -1,9 +1,7 @@
-_I='COMP_CWORD'
-_H='COMP_WORDS'
-_G='fish'
-_F='zsh'
-_E='bash'
-_D='_'
+_G='COMP_CWORD'
+_F='COMP_WORDS'
+_E='zsh'
+_D='bash'
 _C=False
 _B=None
 _A=True
@@ -19,9 +17,9 @@ WORDBREAK='='
 COMPLETION_SCRIPT_BASH='\n%(complete_func)s() {\n    local IFS=$\'\n\'\n    COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\\n                   COMP_CWORD=$COMP_CWORD \\\n                   %(autocomplete_var)s=complete $1 ) )\n    return 0\n}\n\n%(complete_func)setup() {\n    local COMPLETION_OPTIONS=""\n    local BASH_VERSION_ARR=(${BASH_VERSION//./ })\n    # Only BASH version 4.4 and later have the nosort option.\n    if [ ${BASH_VERSION_ARR[0]} -gt 4 ] || ([ ${BASH_VERSION_ARR[0]} -eq 4 ] && [ ${BASH_VERSION_ARR[1]} -ge 4 ]); then\n        COMPLETION_OPTIONS="-o nosort"\n    fi\n\n    complete $COMPLETION_OPTIONS -F %(complete_func)s %(script_names)s\n}\n\n%(complete_func)setup\n'
 COMPLETION_SCRIPT_ZSH='\n#compdef %(script_names)s\n\n%(complete_func)s() {\n    local -a completions\n    local -a completions_with_descriptions\n    local -a response\n    (( ! $+commands[%(script_names)s] )) && return 1\n\n    response=("${(@f)$( env COMP_WORDS="${words[*]}" \\\n                        COMP_CWORD=$((CURRENT-1)) \\\n                        %(autocomplete_var)s="complete_zsh" \\\n                        %(script_names)s )}")\n\n    for key descr in ${(kv)response}; do\n      if [[ "$descr" == "_" ]]; then\n          completions+=("$key")\n      else\n          completions_with_descriptions+=("$key":"$descr")\n      fi\n    done\n\n    if [ -n "$completions_with_descriptions" ]; then\n        _describe -V unsorted completions_with_descriptions -U\n    fi\n\n    if [ -n "$completions" ]; then\n        compadd -U -V unsorted -a completions\n    fi\n    compstate[insert]="automenu"\n}\n\ncompdef %(complete_func)s %(script_names)s\n'
 COMPLETION_SCRIPT_FISH='complete --no-files --command %(script_names)s --arguments "(env %(autocomplete_var)s=complete_fish COMP_WORDS=(commandline -cp) COMP_CWORD=(commandline -t) %(script_names)s)"'
-_completion_scripts={_E:COMPLETION_SCRIPT_BASH,_F:COMPLETION_SCRIPT_ZSH,_G:COMPLETION_SCRIPT_FISH}
+_completion_scripts={_D:COMPLETION_SCRIPT_BASH,_E:COMPLETION_SCRIPT_ZSH,'fish':COMPLETION_SCRIPT_FISH}
 _invalid_ident_char_re=re.compile('[^a-zA-Z0-9_]')
-def get_completion_script(prog_name,complete_var,shell):A=prog_name;B=_invalid_ident_char_re.sub('',A.replace('-',_D));C=_completion_scripts.get(shell,COMPLETION_SCRIPT_BASH);return (C%{'complete_func':f"_{B}_completion",'script_names':A,'autocomplete_var':complete_var}).strip()+';'
+def get_completion_script(prog_name,complete_var,shell):A=prog_name;B=_invalid_ident_char_re.sub('',A.replace('-','_'));C=_completion_scripts.get(shell,COMPLETION_SCRIPT_BASH);return (C%{'complete_func':f"_{B}_completion",'script_names':A,'autocomplete_var':complete_var}).strip()+';'
 def resolve_ctx(cli,prog_name,args):
 	B=args;A=cli.make_context(prog_name,B,resilient_parsing=_A);B=A.protected_args+A.args
 	while B:
@@ -90,25 +88,25 @@ def get_choices(cli,prog_name,args,incomplete):
 		if is_incomplete_argument(C.params,A):return get_user_autocompletions(C,D,B,A)
 	add_subcommand_completions(C,B,E);return sorted(E)
 def do_complete(cli,prog_name,include_descriptions):
-	B=split_arg_string(os.environ[_H]);C=int(os.environ[_I]);E=B[1:C]
+	B=split_arg_string(os.environ[_F]);C=int(os.environ[_G]);E=B[1:C]
 	try:D=B[C]
 	except IndexError:D=''
 	for A in get_choices(cli,prog_name,E,D):
 		echo(A[0])
-		if include_descriptions:echo(A[1]if A[1]else _D)
+		if include_descriptions:echo(A[1]if A[1]else'_')
 	return _A
 def do_complete_fish(cli,prog_name):
-	B=split_arg_string(os.environ[_H]);C=os.environ[_I];D=B[1:]
+	B=split_arg_string(os.environ[_F]);C=os.environ[_G];D=B[1:]
 	for A in get_choices(cli,prog_name,D,C):
 		if A[1]:echo(f"{A[0]}\t{A[1]}")
 		else:echo(A[0])
 	return _A
 def bashcomplete(cli,prog_name,complete_var,complete_instr):
 	C=complete_instr;B=prog_name
-	if _D in C:D,A=C.split(_D,1)
-	else:D=C;A=_E
+	if'_'in C:D,A=C.split('_',1)
+	else:D=C;A=_D
 	if D=='source':echo(get_completion_script(B,complete_var,A));return _A
 	elif D=='complete':
-		if A==_G:return do_complete_fish(cli,B)
-		elif A in{_E,_F}:return do_complete(cli,B,A==_F)
+		if A=='fish':return do_complete_fish(cli,B)
+		elif A in{_D,_E}:return do_complete(cli,B,A==_E)
 	return _C
\ No newline at end of file
diff --git a/dynaconf/vendor/click/_compat.py b/dynaconf/vendor/click/_compat.py
index f1eb2b4..e293268 100644
--- a/dynaconf/vendor/click/_compat.py
+++ b/dynaconf/vendor/click/_compat.py
@@ -1,9 +1,6 @@
-_L='stderr'
-_K='stdout'
-_J='stdin'
-_I='buffer'
-_H='ascii'
-_G='win'
+_I='stderr'
+_H='stdout'
+_G='buffer'
 _F='utf-8'
 _E='encoding'
 _D='replace'
@@ -13,9 +10,9 @@ _A=None
 import codecs,io,os,re,sys
 from weakref import WeakKeyDictionary
 CYGWIN=sys.platform.startswith('cygwin')
-MSYS2=sys.platform.startswith(_G)and'GCC'in sys.version
+MSYS2=sys.platform.startswith('win')and'GCC'in sys.version
 APP_ENGINE='APPENGINE_RUNTIME'in os.environ and'Development/'in os.environ.get('SERVER_SOFTWARE','')
-WIN=sys.platform.startswith(_G)and not APP_ENGINE and not MSYS2
+WIN=sys.platform.startswith('win')and not APP_ENGINE and not MSYS2
 DEFAULT_COLUMNS=80
 auto_wrap_for_ansi=_A
 colorama=_A
@@ -28,7 +25,7 @@ def _make_text_stream(stream,encoding,errors,force_readable=_B,force_writable=_B
 	if B is _A:B=_D
 	return _NonClosingTextIOWrapper(C,A,B,line_buffering=_C,force_readable=force_readable,force_writable=force_writable)
 def is_ascii_encoding(encoding):
-	try:return codecs.lookup(encoding).name==_H
+	try:return codecs.lookup(encoding).name=='ascii'
 	except LookupError:return _B
 def get_best_encoding(stream):
 	A=getattr(stream,_E,_A)or sys.getdefaultencoding()
@@ -84,14 +81,14 @@ def _is_binary_writer(stream,default=_B):
 def _find_binary_reader(stream):
 	A=stream
 	if _is_binary_reader(A,_B):return A
-	B=getattr(A,_I,_A)
+	B=getattr(A,_G,_A)
 	if B is not _A and _is_binary_reader(B,_C):return B
 def _find_binary_writer(stream):
 	A=stream
 	if _is_binary_writer(A,_B):return A
-	B=getattr(A,_I,_A)
+	B=getattr(A,_G,_A)
 	if B is not _A and _is_binary_writer(B,_C):return B
-def _stream_is_misconfigured(stream):return is_ascii_encoding(getattr(stream,_E,_A)or _H)
+def _stream_is_misconfigured(stream):return is_ascii_encoding(getattr(stream,_E,_A)or'ascii')
 def _is_compat_stream_attr(stream,attr,value):A=value;B=getattr(stream,attr,_A);return B==A or A is _A and B is not _A
 def _is_compatible_text_stream(stream,encoding,errors):A=stream;return _is_compat_stream_attr(A,_E,encoding)and _is_compat_stream_attr(A,'errors',errors)
 def _force_correct_text_stream(text_stream,encoding,errors,is_binary,find_binary,force_readable=_B,force_writable=_B):
@@ -146,17 +143,17 @@ def _wrap_io_open(file,mode,encoding,errors):
 	if'b'in A:return open(file,A)
 	return open(file,A,encoding=encoding,errors=errors)
 def open_stream(filename,mode='r',encoding=_A,errors='strict',atomic=_B):
-	P='x';O='a';N='w';E=errors;D=encoding;B=filename;A=mode;G='b'in A
+	E=errors;D=encoding;B=filename;A=mode;G='b'in A
 	if B=='-':
-		if any((B in A for B in[N,O,P])):
+		if any((B in A for B in['w','a','x'])):
 			if G:return get_binary_stdout(),_B
 			return get_text_stdout(encoding=D,errors=E),_B
 		if G:return get_binary_stdin(),_B
 		return get_text_stdin(encoding=D,errors=E),_B
 	if not atomic:return _wrap_io_open(B,A,D,E),_C
-	if O in A:raise ValueError("Appending to an existing file is not supported, because that would involve an expensive `copy`-operation to a temporary file. Open the file in normal `w`-mode and copy explicitly if that's what you're after.")
-	if P in A:raise ValueError('Use the `overwrite`-parameter instead.')
-	if N not in A:raise ValueError('Atomic writes only make sense with `w`-mode.')
+	if'a'in A:raise ValueError("Appending to an existing file is not supported, because that would involve an expensive `copy`-operation to a temporary file. Open the file in normal `w`-mode and copy explicitly if that's what you're after.")
+	if'x'in A:raise ValueError('Use the `overwrite`-parameter instead.')
+	if'w'not in A:raise ValueError('Atomic writes only make sense with `w`-mode.')
 	import errno as I,random as K
 	try:C=os.stat(B).st_mode
 	except OSError:C=_A
@@ -236,5 +233,5 @@ def _make_cached_stream_func(src_func,wrapper_func):
 _default_text_stdin=_make_cached_stream_func(lambda:sys.stdin,get_text_stdin)
 _default_text_stdout=_make_cached_stream_func(lambda:sys.stdout,get_text_stdout)
 _default_text_stderr=_make_cached_stream_func(lambda:sys.stderr,get_text_stderr)
-binary_streams={_J:get_binary_stdin,_K:get_binary_stdout,_L:get_binary_stderr}
-text_streams={_J:get_text_stdin,_K:get_text_stdout,_L:get_text_stderr}
\ No newline at end of file
+binary_streams={'stdin':get_binary_stdin,_H:get_binary_stdout,_I:get_binary_stderr}
+text_streams={'stdin':get_text_stdin,_H:get_text_stdout,_I:get_text_stderr}
\ No newline at end of file
diff --git a/dynaconf/vendor/click/_termui_impl.py b/dynaconf/vendor/click/_termui_impl.py
index b18a9f2..b082d2a 100644
--- a/dynaconf/vendor/click/_termui_impl.py
+++ b/dynaconf/vendor/click/_termui_impl.py
@@ -1,7 +1,5 @@
-_H='replace'
-_G='less'
-_F='You need to use progress bars in a with block.'
-_E=' '
+_F='replace'
+_E='You need to use progress bars in a with block.'
 _D='\n'
 _C=False
 _B=True
@@ -23,7 +21,7 @@ def _length_hint(obj):
 		if A is NotImplemented or not isinstance(A,int)or A<0:return _A
 		return A
 class ProgressBar:
-	def __init__(A,iterable,length=_A,fill_char='#',empty_char=_E,bar_template='%(bar)s',info_sep='  ',show_eta=_B,show_percent=_A,show_pos=_C,item_show_func=_A,label=_A,file=_A,color=_A,width=30):
+	def __init__(A,iterable,length=_A,fill_char='#',empty_char=' ',bar_template='%(bar)s',info_sep='  ',show_eta=_B,show_percent=_A,show_pos=_C,item_show_func=_A,label=_A,file=_A,color=_A,width=30):
 		E=width;D=file;C=iterable;B=length;A.fill_char=fill_char;A.empty_char=empty_char;A.bar_template=bar_template;A.info_sep=info_sep;A.show_eta=show_eta;A.show_percent=show_percent;A.show_pos=show_pos;A.item_show_func=item_show_func;A.label=label or''
 		if D is _A:D=_default_text_stdout()
 		A.file=D;A.color=color;A.width=E;A.autowidth=E==0
@@ -35,7 +33,7 @@ class ProgressBar:
 	def __enter__(A):A.entered=_B;A.render_progress();return A
 	def __exit__(A,exc_type,exc_value,tb):A.render_finish()
 	def __iter__(A):
-		if not A.entered:raise RuntimeError(_F)
+		if not A.entered:raise RuntimeError(_E)
 		A.render_progress();return A.generator()
 	def __next__(A):return next(iter(A))
 	def is_fast(A):return time.time()-A.start<=A.short_limit
@@ -92,13 +90,13 @@ class ProgressBar:
 		B=[]
 		if A.autowidth:
 			H=A.width;A.width=0;I=term_len(A.format_progress_line());D=max(0,G()[0]-I)
-			if D<H:B.append(BEFORE_BAR);B.append(_E*A.max_width);A.max_width=D
+			if D<H:B.append(BEFORE_BAR);B.append(' '*A.max_width);A.max_width=D
 			A.width=D
 		F=A.width
 		if A.max_width is not _A:F=A.max_width
 		B.append(BEFORE_BAR);C=A.format_progress_line();E=term_len(C)
 		if A.max_width is _A or A.max_width<E:A.max_width=E
-		B.append(C);B.append(_E*(F-E));C=''.join(B)
+		B.append(C);B.append(' '*(F-E));C=''.join(B)
 		if C!=A._last_line and not A.is_fast():A._last_line=C;echo(C,file=A.file,color=A.color,nl=_C);A.file.flush()
 	def make_step(A,n_steps):
 		A.pos+=n_steps
@@ -114,13 +112,13 @@ class ProgressBar:
 		A.render_progress()
 	def finish(A):A.eta_known=0;A.current_item=_A;A.finished=_B
 	def generator(A):
-		if not A.entered:raise RuntimeError(_F)
+		if not A.entered:raise RuntimeError(_E)
 		if A.is_hidden:yield from A.iter
 		else:
 			for B in A.iter:A.current_item=B;yield B;A.update(1)
 			A.finish();A.render_progress()
 def pager(generator,color=_A):
-	H='system';B=color;A=generator;C=_default_text_stdout()
+	F='system';B=color;A=generator;C=_default_text_stdout()
 	if not isatty(sys.stdin)or not isatty(C):return _nullpager(C,A,B)
 	D=(os.environ.get('PAGER',_A)or'').strip()
 	if D:
@@ -128,23 +126,23 @@ def pager(generator,color=_A):
 		return _pipepager(A,D,B)
 	if os.environ.get('TERM')in('dumb','emacs'):return _nullpager(C,A,B)
 	if WIN or sys.platform.startswith('os2'):return _tempfilepager(A,'more <',B)
-	if hasattr(os,H)and os.system('(less) 2>/dev/null')==0:return _pipepager(A,_G,B)
-	import tempfile as F;G,E=F.mkstemp();os.close(G)
+	if hasattr(os,F)and os.system('(less) 2>/dev/null')==0:return _pipepager(A,'less',B)
+	import tempfile as G;H,E=G.mkstemp();os.close(H)
 	try:
-		if hasattr(os,H)and os.system(f'more "{E}"')==0:return _pipepager(A,'more',B)
+		if hasattr(os,F)and os.system(f'more "{E}"')==0:return _pipepager(A,'more',B)
 		return _nullpager(C,A,B)
 	finally:os.unlink(E)
 def _pipepager(generator,cmd,color):
-	I='LESS';A=color;import subprocess as E;F=dict(os.environ);G=cmd.rsplit('/',1)[-1].split()
-	if A is _A and G[0]==_G:
-		C=f"{os.environ.get(I,'')}{_E.join(G[1:])}"
-		if not C:F[I]='-R';A=_B
+	H='LESS';A=color;import subprocess as E;F=dict(os.environ);G=cmd.rsplit('/',1)[-1].split()
+	if A is _A and G[0]=='less':
+		C=f"{os.environ.get(H,'')}{' '.join(G[1:])}"
+		if not C:F[H]='-R';A=_B
 		elif'r'in C or'R'in C:A=_B
-	B=E.Popen(cmd,shell=_B,stdin=E.PIPE,env=F);H=get_best_encoding(B.stdin)
+	B=E.Popen(cmd,shell=_B,stdin=E.PIPE,env=F);I=get_best_encoding(B.stdin)
 	try:
 		for D in generator:
 			if not A:D=strip_ansi(D)
-			B.stdin.write(D.encode(H,_H))
+			B.stdin.write(D.encode(I,_F))
 	except (OSError,KeyboardInterrupt):pass
 	else:B.stdin.close()
 	while _B:
@@ -182,21 +180,21 @@ class Editor:
 			if F!=0:raise ClickException(f"{B}: Editing failed!")
 		except OSError as G:raise ClickException(f"{B}: Editing failed: {G}")
 	def edit(D,text):
-		L='\r\n';K='utf-8-sig';A=text;import tempfile as H;A=A or'';E=type(A)in[bytes,bytearray]
+		I='\r\n';H='utf-8-sig';A=text;import tempfile as J;A=A or'';E=type(A)in[bytes,bytearray]
 		if not E and A and not A.endswith(_D):A+=_D
-		I,B=H.mkstemp(prefix='editor-',suffix=D.extension)
+		K,B=J.mkstemp(prefix='editor-',suffix=D.extension)
 		try:
 			if not E:
-				if WIN:F=K;A=A.replace(_D,L)
+				if WIN:F=H;A=A.replace(_D,I)
 				else:F='utf-8'
 				A=A.encode(F)
-			C=os.fdopen(I,'wb');C.write(A);C.close();J=os.path.getmtime(B);D.edit_file(B)
-			if D.require_save and os.path.getmtime(B)==J:return _A
+			C=os.fdopen(K,'wb');C.write(A);C.close();L=os.path.getmtime(B);D.edit_file(B)
+			if D.require_save and os.path.getmtime(B)==L:return _A
 			C=open(B,'rb')
 			try:G=C.read()
 			finally:C.close()
 			if E:return G
-			else:return G.decode(K).replace(L,_D)
+			else:return G.decode(H).replace(I,_D)
 		finally:os.unlink(B)
 def open_url(url,wait=_C,locate=_C):
 	F='"';D=locate;C=wait;A=url;import subprocess as G
@@ -257,6 +255,6 @@ else:
 		except termios.error:pass
 	def getchar(echo):
 		with raw_terminal()as B:
-			A=os.read(B,32);A=A.decode(get_best_encoding(sys.stdin),_H)
+			A=os.read(B,32);A=A.decode(get_best_encoding(sys.stdin),_F)
 			if echo and isatty(sys.stdout):sys.stdout.write(A)
 			_translate_ch_to_exc(A);return A
\ No newline at end of file
diff --git a/dynaconf/vendor/click/_unicodefun.py b/dynaconf/vendor/click/_unicodefun.py
index 792053f..639e5af 100644
--- a/dynaconf/vendor/click/_unicodefun.py
+++ b/dynaconf/vendor/click/_unicodefun.py
@@ -1,28 +1,28 @@
 import codecs,os
 def _verify_python_env():
-	M='.utf8';L='.utf-8';J=None;I='ascii'
-	try:import locale as A;G=codecs.lookup(A.getpreferredencoding()).name
-	except Exception:G=I
-	if G!=I:return
+	L='.utf8';K='.utf-8';H=None;G='ascii'
+	try:import locale as A;I=codecs.lookup(A.getpreferredencoding()).name
+	except Exception:I=G
+	if I!=G:return
 	B=''
 	if os.name=='posix':
 		import subprocess as D
 		try:C=D.Popen(['locale','-a'],stdout=D.PIPE,stderr=D.PIPE).communicate()[0]
 		except OSError:C=b''
-		E=set();H=False
-		if isinstance(C,bytes):C=C.decode(I,'replace')
-		for K in C.splitlines():
-			A=K.strip()
-			if A.lower().endswith((L,M)):
+		E=set();J=False
+		if isinstance(C,bytes):C=C.decode(G,'replace')
+		for M in C.splitlines():
+			A=M.strip()
+			if A.lower().endswith((K,L)):
 				E.add(A)
-				if A.lower()in('c.utf8','c.utf-8'):H=True
+				if A.lower()in('c.utf8','c.utf-8'):J=True
 		B+='\n\n'
 		if not E:B+='Additional information: on this system no suitable UTF-8 locales were discovered. This most likely requires resolving by reconfiguring the locale system.'
-		elif H:B+='This system supports the C.UTF-8 locale which is recommended. You might be able to resolve your issue by exporting the following environment variables:\n\n    export LC_ALL=C.UTF-8\n    export LANG=C.UTF-8'
+		elif J:B+='This system supports the C.UTF-8 locale which is recommended. You might be able to resolve your issue by exporting the following environment variables:\n\n    export LC_ALL=C.UTF-8\n    export LANG=C.UTF-8'
 		else:B+=f"This system lists some UTF-8 supporting locales that you can pick from. The following suitable locales were discovered: {', '.join(sorted(E))}"
-		F=J
+		F=H
 		for A in (os.environ.get('LC_ALL'),os.environ.get('LANG')):
-			if A and A.lower().endswith((L,M)):F=A
-			if A is not J:break
-		if F is not J:B+=f"\n\nClick discovered that you exported a UTF-8 locale but the locale system could not pick up from it because it does not exist. The exported locale is {F!r} but it is not supported"
+			if A and A.lower().endswith((K,L)):F=A
+			if A is not H:break
+		if F is not H:B+=f"\n\nClick discovered that you exported a UTF-8 locale but the locale system could not pick up from it because it does not exist. The exported locale is {F!r} but it is not supported"
 	raise RuntimeError(f"Click will abort further execution because Python was configured to use ASCII as encoding for the environment. Consult https://click.palletsprojects.com/unicode-support/ for mitigation steps.{B}")
\ No newline at end of file
diff --git a/dynaconf/vendor/click/core.py b/dynaconf/vendor/click/core.py
index fe475eb..6a3fee9 100644
--- a/dynaconf/vendor/click/core.py
+++ b/dynaconf/vendor/click/core.py
@@ -1,9 +1,5 @@
-_I='default'
-_H=' / '
-_G='...'
-_F='nargs'
-_E='-'
-_D='_'
+_E='default'
+_D='nargs'
 _C=True
 _B=False
 _A=None
@@ -44,7 +40,7 @@ def _maybe_show_deprecated_notice(cmd):
 def fast_exit(code):sys.stdout.flush();sys.stderr.flush();os._exit(code)
 def _bashcomplete(cmd,prog_name,complete_var=_A):
 	B=prog_name;A=complete_var
-	if A is _A:A=f"_{B}_COMPLETE".replace(_E,_D).upper()
+	if A is _A:A=f"_{B}_COMPLETE".replace('-','_').upper()
 	C=os.environ.get(A)
 	if not C:return
 	from ._bashcomplete import bashcomplete as D
@@ -105,7 +101,7 @@ class Context:
 		if C is _A:
 			if B is not _A and B.auto_envvar_prefix is not _A and A.info_name is not _A:C=f"{B.auto_envvar_prefix}_{A.info_name.upper()}"
 		else:C=C.upper()
-		if C is not _A:C=C.replace(_E,_D)
+		if C is not _A:C=C.replace('-','_')
 		A.auto_envvar_prefix=C
 		if N is _A and B is not _A:N=B.color
 		A.color=N;A.show_default=show_default;A._close_callbacks=[];A._depth=0;A._source_by_paramname={}
@@ -167,7 +163,7 @@ class Context:
 				if D.name not in E and D.expose_value:E[D.name]=D.get_default(G)
 		B=B[2:]
 		with augment_usage_errors(F):
-			with G:return A(*B,**E)
+			with G:return A(*(B),**E)
 	def forward(*E,**A):
 		B,D=E[:2]
 		if not isinstance(D,Command):raise TypeError('Callback is not a command.')
@@ -218,7 +214,7 @@ class BaseCommand:
 		except Abort:
 			if not D:raise
 			echo('Aborted!',file=sys.stderr);sys.exit(1)
-	def __call__(A,*B,**C):return A.main(*B,**C)
+	def __call__(A,*B,**C):return A.main(*(B),**C)
 class Command(BaseCommand):
 	def __init__(A,name,context_settings=_A,callback=_A,params=_A,help=_A,epilog=_A,short_help=_A,options_metavar='[OPTIONS]',add_help_option=_C,no_args_is_help=_B,hidden=_B,deprecated=_B):
 		B='\x0c';BaseCommand.__init__(A,name,context_settings);A.callback=callback;A.params=params or[]
@@ -305,7 +301,7 @@ class MultiCommand(Command):
 		def B(f):
 			B=A.result_callback
 			if B is _A or replace:A.result_callback=f;return f
-			def C(__value,*A,**C):return f(B(__value,*A,**C),*A,**C)
+			def C(__value,*A,**C):return f(B(__value,*(A),**C),*(A),**C)
 			A.result_callback=D=update_wrapper(C,f);return D
 		return B
 	def format_commands(F,ctx,formatter):
@@ -367,11 +363,11 @@ class Group(MultiCommand):
 		_check_multicommand(C,A,B,register=_C);C.commands[A]=B
 	def command(B,*C,**D):
 		from .decorators import command as E
-		def A(f):A=E(*C,**D)(f);B.add_command(A);return A
+		def A(f):A=E(*(C),**D)(f);B.add_command(A);return A
 		return A
 	def group(B,*C,**D):
 		from .decorators import group
-		def A(f):A=group(*C,**D)(f);B.add_command(A);return A
+		def A(f):A=group(*(C),**D)(f);B.add_command(A);return A
 		return A
 	def get_command(A,ctx,cmd_name):return A.commands.get(cmd_name)
 	def list_commands(A,ctx):return sorted(A.commands)
@@ -404,7 +400,7 @@ class Parameter:
 		if A.metavar is not _A:return A.metavar
 		B=A.type.get_metavar(A)
 		if B is _A:B=A.type.name.upper()
-		if A.nargs!=1:B+=_G
+		if A.nargs!=1:B+='...'
 		return B
 	def get_default(A,ctx):
 		if callable(A.default):B=A.default()
@@ -472,12 +468,12 @@ class Parameter:
 		return C,args
 	def get_help_record(A,ctx):0
 	def get_usage_pieces(A,ctx):return[]
-	def get_error_hint(A,ctx):B=A.opts or[A.human_readable_name];return _H.join((repr(A)for A in B))
+	def get_error_hint(A,ctx):B=A.opts or[A.human_readable_name];return ' / '.join((repr(A)for A in B))
 class Option(Parameter):
 	param_type_name='option'
 	def __init__(A,param_decls=_A,show_default=_B,prompt=_B,confirmation_prompt=_B,hide_input=_B,is_flag=_A,flag_value=_A,multiple=_B,count=_B,allow_from_autoenv=_C,type=_A,help=_A,hidden=_B,show_choices=_C,show_envvar=_B,**G):
-		F=count;D=prompt;C=flag_value;B=is_flag;H=G.get(_I,_missing)is _missing;Parameter.__init__(A,param_decls,type=type,**G)
-		if D is _C:E=A.name.replace(_D,' ').capitalize()
+		F=count;D=prompt;C=flag_value;B=is_flag;H=G.get(_E,_missing)is _missing;Parameter.__init__(A,param_decls,type=type,**G)
+		if D is _C:E=A.name.replace('_',' ').capitalize()
 		elif D is _B:E=_A
 		else:E=D
 		A.prompt=E;A.confirmation_prompt=confirmation_prompt;A.hide_input=hide_input;A.hidden=hidden
@@ -502,14 +498,14 @@ class Option(Parameter):
 			if A.count:
 				if A.multiple:raise TypeError('Options cannot be multiple and count at the same time.')
 				elif A.is_flag:raise TypeError('Options cannot be count and flags at the same time.')
-	def _parse_decls(J,decls,expose_value):
-		I='/';C=[];F=[];A=_A;D=[]
+	def _parse_decls(I,decls,expose_value):
+		C=[];F=[];A=_A;D=[]
 		for B in decls:
 			if B.isidentifier():
 				if A is not _A:raise TypeError('Name defined twice')
 				A=B
 			else:
-				H=';'if B[:1]==I else I
+				H=';'if B[:1]=='/'else'/'
 				if H in B:
 					E,G=B.split(H,1);E=E.rstrip()
 					if E:D.append(split_opt(E));C.append(E)
@@ -517,7 +513,7 @@ class Option(Parameter):
 					if G:F.append(G.lstrip())
 				else:D.append(split_opt(B));C.append(B)
 		if A is _A and D:
-			D.sort(key=lambda x:-len(x[0]));A=D[0][1].replace(_E,_D).lower()
+			D.sort(key=lambda x:-len(x[0]));A=D[0][1].replace('-','_').lower()
 			if not A.isidentifier():A=_A
 		if A is _A:
 			if not expose_value:return _A,C,F
@@ -525,17 +521,17 @@ class Option(Parameter):
 		if not C and not F:raise TypeError(f"No options defined but a name was passed ({A}). Did you mean to declare an argument instead of an option?")
 		return A,C,F
 	def add_to_parser(A,parser,ctx):
-		C=parser;B={'dest':A.name,_F:A.nargs,'obj':A}
+		C=parser;B={'dest':A.name,_D:A.nargs,'obj':A}
 		if A.multiple:D='append'
 		elif A.count:D='count'
 		else:D='store'
 		if A.is_flag:
-			B.pop(_F,_A);E=f"{D}_const"
+			B.pop(_D,_A);E=f"{D}_const"
 			if A.is_bool_flag and A.secondary_opts:C.add_option(A.opts,action=E,const=_C,**B);C.add_option(A.secondary_opts,action=E,const=_B,**B)
 			else:C.add_option(A.opts,action=E,const=A.flag_value,**B)
 		else:B['action']=D;C.add_option(A.opts,**B)
 	def get_help_record(A,ctx):
-		K=', ';E=ctx
+		E=ctx
 		if A.hidden:return
 		F=[]
 		def G(opts):
@@ -550,16 +546,16 @@ class Option(Parameter):
 			B=A.envvar
 			if B is _A:
 				if A.allow_from_autoenv and E.auto_envvar_prefix is not _A:B=f"{E.auto_envvar_prefix}_{A.name.upper()}"
-			if B is not _A:J=K.join((str(A)for A in B))if isinstance(B,(list,tuple))else B;C.append(f"env var: {J}")
+			if B is not _A:J=', '.join((str(A)for A in B))if isinstance(B,(list,tuple))else B;C.append(f"env var: {J}")
 		if A.default is not _A and(A.show_default or E.show_default):
 			if isinstance(A.show_default,str):D=f"({A.show_default})"
-			elif isinstance(A.default,(list,tuple)):D=K.join((str(B)for B in A.default))
+			elif isinstance(A.default,(list,tuple)):D=', '.join((str(B)for B in A.default))
 			elif inspect.isfunction(A.default):D='(dynamic)'
 			else:D=A.default
 			C.append(f"default: {D}")
 		if A.required:C.append('required')
 		if C:I=';'.join(C);help=f"{help}  [{I}]"if help else f"[{I}]"
-		return ('; 'if F else _H).join(H),help
+		return ('; 'if F else' / ').join(H),help
 	def get_default(A,ctx):
 		if A.is_flag and not A.is_bool_flag:
 			for B in ctx.command.params:
@@ -591,8 +587,8 @@ class Argument(Parameter):
 	def __init__(B,param_decls,required=_A,**C):
 		A=required
 		if A is _A:
-			if C.get(_I)is not _A:A=_B
-			else:A=C.get(_F,1)>0
+			if C.get(_E)is not _A:A=_B
+			else:A=C.get(_D,1)>0
 		Parameter.__init__(B,param_decls,required=A,**C)
 		if B.default is not _A and B.nargs<0:raise TypeError('nargs=-1 in combination with a default value is not supported.')
 	@property
@@ -605,14 +601,14 @@ class Argument(Parameter):
 		B=A.type.get_metavar(A)
 		if not B:B=A.name.upper()
 		if not A.required:B=f"[{B}]"
-		if A.nargs!=1:B+=_G
+		if A.nargs!=1:B+='...'
 		return B
 	def _parse_decls(D,decls,expose_value):
 		A=decls
 		if not A:
 			if not expose_value:return _A,[],[]
 			raise TypeError('Could not determine name for argument')
-		if len(A)==1:B=C=A[0];B=B.replace(_E,_D).lower()
+		if len(A)==1:B=C=A[0];B=B.replace('-','_').lower()
 		else:raise TypeError(f"Arguments take exactly one parameter declaration, got {len(A)}.")
 		return B,[C],[]
 	def get_usage_pieces(A,ctx):return[A.make_metavar()]
diff --git a/dynaconf/vendor/click/decorators.py b/dynaconf/vendor/click/decorators.py
index 888b3e0..9bc02b8 100644
--- a/dynaconf/vendor/click/decorators.py
+++ b/dynaconf/vendor/click/decorators.py
@@ -18,11 +18,11 @@ from .globals import get_current_context
 from .utils import echo
 def pass_context(f):
 	'Marks a callback as wanting to receive the current context\n    object as first argument.\n    '
-	def A(*A,**B):return f(get_current_context(),*A,**B)
+	def A(*A,**B):return f(get_current_context(),*(A),**B)
 	return update_wrapper(A,f)
 def pass_obj(f):
 	'Similar to :func:`pass_context`, but only pass the object on the\n    context onwards (:attr:`Context.obj`).  This is useful if that object\n    represents the state of a nested system.\n    '
-	def A(*A,**B):return f(get_current_context().obj,*A,**B)
+	def A(*A,**B):return f(get_current_context().obj,*(A),**B)
 	return update_wrapper(A,f)
 def make_pass_decorator(object_type,ensure=_D):
 	"Given an object type this creates a decorator that will work\n    similar to :func:`pass_obj` but instead of passing the object of the\n    current context, it will find the innermost context of type\n    :func:`object_type`.\n\n    This generates a decorator that works roughly like this::\n\n        from functools import update_wrapper\n\n        def decorator(f):\n            @pass_context\n            def new_func(ctx, *args, **kwargs):\n                obj = ctx.find_object(object_type)\n                return ctx.invoke(f, obj, *args, **kwargs)\n            return update_wrapper(new_func, f)\n        return decorator\n\n    :param object_type: the type of the object to pass.\n    :param ensure: if set to `True`, a new object will be created and\n                   remembered on the context if it's not there yet.\n    ";A=object_type
@@ -32,7 +32,7 @@ def make_pass_decorator(object_type,ensure=_D):
 			if ensure:C=B.ensure_object(A)
 			else:C=B.find_object(A)
 			if C is _A:raise RuntimeError(f"Managed to invoke callback without a context object of type {A.__name__!r} existing.")
-			return B.invoke(f,C,*D,**E)
+			return B.invoke(f,C,*(D),**E)
 		return update_wrapper(B,f)
 	return B
 def _make_command(f,name,attrs,cls):
@@ -74,11 +74,11 @@ def confirmation_option(*B,**A):
 	def C(f):
 		def C(ctx,param,value):
 			if not value:ctx.abort()
-		A.setdefault(_F,_C);A.setdefault(_G,C);A.setdefault(_H,_D);A.setdefault(_I,'Do you want to continue?');A.setdefault(_B,'Confirm the action without prompting.');return option(*B or('--yes',),**A)(f)
+		A.setdefault(_F,_C);A.setdefault(_G,C);A.setdefault(_H,_D);A.setdefault(_I,'Do you want to continue?');A.setdefault(_B,'Confirm the action without prompting.');return option(*(B or('--yes',)),**A)(f)
 	return C
 def password_option(*B,**A):
 	"Shortcut for password prompts.\n\n    This is equivalent to decorating a function with :func:`option` with\n    the following parameters::\n\n        @click.command()\n        @click.option('--password', prompt=True, confirmation_prompt=True,\n                      hide_input=True)\n        def changeadmin(password):\n            pass\n    "
-	def C(f):A.setdefault(_I,_C);A.setdefault('confirmation_prompt',_C);A.setdefault('hide_input',_C);return option(*B or('--password',),**A)(f)
+	def C(f):A.setdefault(_I,_C);A.setdefault('confirmation_prompt',_C);A.setdefault('hide_input',_C);return option(*(B or('--password',)),**A)(f)
 	return C
 def version_option(version=_A,*B,**A):
 	"Adds a ``--version`` option which immediately ends the program\n    printing out the version number.  This is implemented as an eager\n    option that prints the version and exits the program in the callback.\n\n    :param version: the version number to show.  If not provided Click\n                    attempts an auto discovery via setuptools.\n    :param prog_name: the name of the program (defaults to autodetection)\n    :param message: custom message to show instead of the default\n                    (``'%(prog)s, version %(version)s'``)\n    :param others: everything else is forwarded to :func:`option`.\n    ";D=version
@@ -103,7 +103,7 @@ def version_option(version=_A,*B,**A):
 							if K.module_name==E:B=F.version;break
 				if B is _A:raise RuntimeError('Could not determine version')
 			echo(H%{'prog':C,'version':B},color=A.color);A.exit()
-		A.setdefault(_F,_C);A.setdefault(_H,_D);A.setdefault(_J,_C);A.setdefault(_B,'Show the version and exit.');A[_G]=C;return option(*B or('--version',),**A)(f)
+		A.setdefault(_F,_C);A.setdefault(_H,_D);A.setdefault(_J,_C);A.setdefault(_B,'Show the version and exit.');A[_G]=C;return option(*(B or('--version',)),**A)(f)
 	return C
 def help_option(*B,**A):
 	'Adds a ``--help`` option which immediately ends the program\n    printing out the help page.  This is usually unnecessary to add as\n    this is added by default to all commands unless suppressed.\n\n    Like :func:`version_option`, this is implemented as eager option that\n    prints in the callback and exits.\n\n    All arguments are forwarded to :func:`option`.\n    '
@@ -111,5 +111,5 @@ def help_option(*B,**A):
 		def C(ctx,param,value):
 			A=ctx
 			if value and not A.resilient_parsing:echo(A.get_help(),color=A.color);A.exit()
-		A.setdefault(_F,_C);A.setdefault(_H,_D);A.setdefault(_B,'Show this message and exit.');A.setdefault(_J,_C);A[_G]=C;return option(*B or('--help',),**A)(f)
+		A.setdefault(_F,_C);A.setdefault(_H,_D);A.setdefault(_B,'Show this message and exit.');A.setdefault(_J,_C);A[_G]=C;return option(*(B or('--help',)),**A)(f)
 	return C
\ No newline at end of file
diff --git a/dynaconf/vendor/click/globals.py b/dynaconf/vendor/click/globals.py
index e0b71c5..efcfd35 100644
--- a/dynaconf/vendor/click/globals.py
+++ b/dynaconf/vendor/click/globals.py
@@ -1,4 +1,3 @@
-_A=None
 from threading import local
 _local=local()
 def get_current_context(silent=False):
@@ -7,8 +6,8 @@ def get_current_context(silent=False):
 		if not silent:raise RuntimeError('There is no active click context.')
 def push_context(ctx):_local.__dict__.setdefault('stack',[]).append(ctx)
 def pop_context():_local.stack.pop()
-def resolve_color_default(color=_A):
+def resolve_color_default(color=None):
 	A=color
-	if A is not _A:return A
+	if A is not None:return A
 	B=get_current_context(silent=True)
-	if B is not _A:return B.color
\ No newline at end of file
+	if B is not None:return B.color
\ No newline at end of file
diff --git a/dynaconf/vendor/click/parser.py b/dynaconf/vendor/click/parser.py
index 769c403..24d2c6c 100644
--- a/dynaconf/vendor/click/parser.py
+++ b/dynaconf/vendor/click/parser.py
@@ -1,4 +1,3 @@
-_D=False
 _C='append'
 _B='store'
 _A=None
@@ -84,7 +83,7 @@ class ParsingState:
 	def __init__(A,rargs):A.opts={};A.largs=[];A.rargs=rargs;A.order=[]
 class OptionParser:
 	def __init__(A,ctx=_A):
-		B=ctx;A.ctx=B;A.allow_interspersed_args=True;A.ignore_unknown_options=_D
+		B=ctx;A.ctx=B;A.allow_interspersed_args=True;A.ignore_unknown_options=False
 		if B is not _A:A.allow_interspersed_args=B.allow_interspersed_args;A.ignore_unknown_options=B.ignore_unknown_options
 		A._short_opt={};A._long_opt={};A._opt_prefixes={'-','--'};A._args=[]
 	def add_option(B,opts,dest,action=_A,nargs=1,const=_A,obj=_A):
@@ -129,7 +128,7 @@ class OptionParser:
 		else:G=_A
 		F.process(G,B)
 	def _match_short_opt(B,arg,state):
-		D=arg;A=state;J=_D;F=1;K=D[0];G=[]
+		D=arg;A=state;J=False;F=1;K=D[0];G=[]
 		for L in D[1:]:
 			H=normalize_opt(f"{K}{L}",B.ctx);E=B._short_opt.get(H);F+=1
 			if not E:
@@ -146,8 +145,8 @@ class OptionParser:
 			if J:break
 		if B.ignore_unknown_options and G:A.largs.append(f"{K}{''.join(G)}")
 	def _process_opts(B,arg,state):
-		G='=';C=state;A=arg;D=_A
-		if G in A:E,D=A.split(G,1)
+		C=state;A=arg;D=_A
+		if'='in A:E,D=A.split('=',1)
 		else:E=A
 		F=normalize_opt(E,B.ctx)
 		try:B._match_long_opt(F,D,C)
diff --git a/dynaconf/vendor/click/testing.py b/dynaconf/vendor/click/testing.py
index f78bc5f..7abd9d3 100644
--- a/dynaconf/vendor/click/testing.py
+++ b/dynaconf/vendor/click/testing.py
@@ -1,6 +1,5 @@
-_E='replace'
-_D=False
-_C='\n'
+_D='replace'
+_C=False
 _B='\r\n'
 _A=None
 import contextlib,io,os,shlex,shutil,sys,tempfile
@@ -28,22 +27,22 @@ class Result:
 	@property
 	def output(self):return self.stdout
 	@property
-	def stdout(self):return self.stdout_bytes.decode(self.runner.charset,_E).replace(_B,_C)
+	def stdout(self):return self.stdout_bytes.decode(self.runner.charset,_D).replace(_B,'\n')
 	@property
 	def stderr(self):
 		A=self
 		if A.stderr_bytes is _A:raise ValueError('stderr not separately captured')
-		return A.stderr_bytes.decode(A.runner.charset,_E).replace(_B,_C)
+		return A.stderr_bytes.decode(A.runner.charset,_D).replace(_B,'\n')
 	def __repr__(A):B=repr(A.exception)if A.exception else'okay';return f"<{type(A).__name__} {B}>"
 class CliRunner:
-	def __init__(A,charset='utf-8',env=_A,echo_stdin=_D,mix_stderr=True):A.charset=charset;A.env=env or{};A.echo_stdin=echo_stdin;A.mix_stderr=mix_stderr
+	def __init__(A,charset='utf-8',env=_A,echo_stdin=_C,mix_stderr=True):A.charset=charset;A.env=env or{};A.echo_stdin=echo_stdin;A.mix_stderr=mix_stderr
 	def get_default_prog_name(A,cli):return cli.name or'root'
 	def make_env(C,overrides=_A):
 		A=overrides;B=dict(C.env)
 		if A:B.update(A)
 		return B
 	@contextlib.contextmanager
-	def isolation(self,input=_A,env=_A,color=_D):
+	def isolation(self,input=_A,env=_A,color=_C):
 		D=env;A=self;input=make_input_stream(input,A.charset);H=sys.stdin;I=sys.stdout;J=sys.stderr;K=formatting.FORCED_WIDTH;formatting.FORCED_WIDTH=80;D=A.make_env(D);E=io.BytesIO()
 		if A.echo_stdin:input=EchoingStdin(input,E)
 		input=io.TextIOWrapper(input,encoding=A.charset);sys.stdout=io.TextIOWrapper(E,encoding=A.charset)
@@ -77,7 +76,7 @@ class CliRunner:
 					except Exception:pass
 				else:os.environ[B]=C
 			sys.stdout=I;sys.stderr=J;sys.stdin=H;termui.visible_prompt_func=Q;termui.hidden_prompt_func=R;termui._getchar=S;utils.should_strip_ansi=T;formatting.FORCED_WIDTH=K
-	def invoke(B,cli,args=_A,input=_A,env=_A,catch_exceptions=True,color=_D,**G):
+	def invoke(B,cli,args=_A,input=_A,env=_A,catch_exceptions=True,color=_C,**G):
 		C=args;E=_A
 		with B.isolation(input=input,env=env,color=color)as H:
 			F=_A;A=0
@@ -89,7 +88,7 @@ class CliRunner:
 				E=sys.exc_info();A=D.code
 				if A is _A:A=0
 				if A!=0:F=D
-				if not isinstance(A,int):sys.stdout.write(str(A));sys.stdout.write(_C);A=1
+				if not isinstance(A,int):sys.stdout.write(str(A));sys.stdout.write('\n');A=1
 			except Exception as D:
 				if not catch_exceptions:raise
 				F=D;A=1;E=sys.exc_info()
diff --git a/dynaconf/vendor/click/types.py b/dynaconf/vendor/click/types.py
index 30ee5fa..d0824f0 100644
--- a/dynaconf/vendor/click/types.py
+++ b/dynaconf/vendor/click/types.py
@@ -1,4 +1,3 @@
-_F='text'
 _E='replace'
 _D='utf-8'
 _C=True
@@ -38,11 +37,11 @@ class FuncParamType(ParamType):
 			except UnicodeError:A=A.decode(_D,_E)
 			B.fail(A,param,ctx)
 class UnprocessedParamType(ParamType):
-	name=_F
+	name='text'
 	def convert(A,value,param,ctx):return value
 	def __repr__(A):return'UNPROCESSED'
 class StringParamType(ParamType):
-	name=_F
+	name='text'
 	def convert(D,value,param,ctx):
 		A=value
 		if isinstance(A,bytes):
diff --git a/dynaconf/vendor/click/utils.py b/dynaconf/vendor/click/utils.py
index e0cf442..772066c 100644
--- a/dynaconf/vendor/click/utils.py
+++ b/dynaconf/vendor/click/utils.py
@@ -9,7 +9,7 @@ echo_native_types=str,bytes,bytearray
 def _posixify(name):return '-'.join(name.split()).lower()
 def safecall(func):
 	def A(*A,**B):
-		try:return func(*A,**B)
+		try:return func(*(A),**B)
 		except Exception:pass
 	return A
 def make_str(value):
diff --git a/dynaconf/vendor/dotenv/__init__.py b/dynaconf/vendor/dotenv/__init__.py
index 25aa760..597ee6e 100644
--- a/dynaconf/vendor/dotenv/__init__.py
+++ b/dynaconf/vendor/dotenv/__init__.py
@@ -4,7 +4,7 @@ from .main import load_dotenv,get_key,set_key,unset_key,find_dotenv,dotenv_value
 if IS_TYPE_CHECKING:from typing import Any,Optional
 def load_ipython_extension(ipython):from .ipython import load_ipython_extension as A;A(ipython)
 def get_cli_string(path=_A,action=_A,key=_A,value=_A,quote=_A):
-	E=' ';D=quote;C=action;B=value;A=['dotenv']
+	D=quote;C=action;B=value;A=['dotenv']
 	if D:A.append('-q %s'%D)
 	if path:A.append('-f %s'%path)
 	if C:
@@ -12,7 +12,7 @@ def get_cli_string(path=_A,action=_A,key=_A,value=_A,quote=_A):
 		if key:
 			A.append(key)
 			if B:
-				if E in B:A.append('"%s"'%B)
+				if' 'in B:A.append('"%s"'%B)
 				else:A.append(B)
-	return E.join(A).strip()
+	return ' '.join(A).strip()
 __all__=['get_cli_string','load_dotenv','dotenv_values','get_key','set_key','unset_key','find_dotenv','load_ipython_extension']
\ No newline at end of file
diff --git a/dynaconf/vendor/dotenv/compat.py b/dynaconf/vendor/dotenv/compat.py
index 09aad2f..a901be1 100644
--- a/dynaconf/vendor/dotenv/compat.py
+++ b/dynaconf/vendor/dotenv/compat.py
@@ -1,4 +1,3 @@
-_A='utf-8'
 import sys
 PY2=sys.version_info[0]==2
 if PY2:from StringIO import StringIO
@@ -10,9 +9,9 @@ def is_type_checking():
 IS_TYPE_CHECKING=is_type_checking()
 if IS_TYPE_CHECKING:from typing import Text
 def to_env(text):
-	if PY2:return text.encode(sys.getfilesystemencoding()or _A)
+	if PY2:return text.encode(sys.getfilesystemencoding()or'utf-8')
 	else:return text
 def to_text(string):
 	A=string
-	if PY2:return A.decode(_A)
+	if PY2:return A.decode('utf-8')
 	else:return A
\ No newline at end of file
diff --git a/dynaconf/vendor/dotenv/ipython.py b/dynaconf/vendor/dotenv/ipython.py
index 47b92bc..7db908f 100644
--- a/dynaconf/vendor/dotenv/ipython.py
+++ b/dynaconf/vendor/dotenv/ipython.py
@@ -11,8 +11,8 @@ class IPythonDotEnv(Magics):
 	@argument('dotenv_path',nargs='?',type=str,default='.env',help='Search in increasingly higher folders for the `dotenv_path`')
 	@line_magic
 	def dotenv(self,line):
-		C=True;A=parse_argstring(self.dotenv,line);B=A.dotenv_path
-		try:B=find_dotenv(B,C,C)
+		A=parse_argstring(self.dotenv,line);B=A.dotenv_path
+		try:B=find_dotenv(B,True,True)
 		except IOError:print('cannot find .env file');return
 		load_dotenv(B,verbose=A.verbose,override=A.override)
 def load_ipython_extension(ipython):ipython.register_magics(IPythonDotEnv)
\ No newline at end of file
diff --git a/dynaconf/vendor/dotenv/main.py b/dynaconf/vendor/dotenv/main.py
index 343e298..eee673a 100644
--- a/dynaconf/vendor/dotenv/main.py
+++ b/dynaconf/vendor/dotenv/main.py
@@ -1,5 +1,4 @@
 from __future__ import absolute_import,print_function,unicode_literals
-_E='.env'
 _D='always'
 _C=True
 _B=False
@@ -30,7 +29,7 @@ class DotEnv:
 		elif os.path.isfile(A.dotenv_path):
 			with io.open(A.dotenv_path,encoding=A.encoding)as B:yield B
 		else:
-			if A.verbose:logger.info('Python-dotenv could not find configuration file %s.',A.dotenv_path or _E)
+			if A.verbose:logger.info('Python-dotenv could not find configuration file %s.',A.dotenv_path or'.env')
 			yield StringIO('')
 	def dict(A):
 		if A._dict:return A._dict
@@ -60,10 +59,10 @@ def rewrite(path):
 		raise
 	else:shutil.move(A.name,path)
 def set_key(dotenv_path,key_to_set,value_to_set,quote_mode=_D):
-	K='"';E=quote_mode;C=dotenv_path;B=key_to_set;A=value_to_set;A=A.strip("'").strip(K)
+	E=quote_mode;C=dotenv_path;B=key_to_set;A=value_to_set;A=A.strip("'").strip('"')
 	if not os.path.exists(C):logger.warning("Can't write to %s - it doesn't exist.",C);return _A,B,A
 	if' 'in A:E=_D
-	if E==_D:F='"{}"'.format(A.replace(K,'\\"'))
+	if E==_D:F='"{}"'.format(A.replace('"','\\"'))
 	else:F=A
 	G='{}={}\n'.format(B,F)
 	with rewrite(C)as(J,D):
@@ -95,18 +94,18 @@ def _walk_to_root(path):
 	if os.path.isfile(A):A=os.path.dirname(A)
 	C=_A;B=os.path.abspath(A)
 	while C!=B:yield B;D=os.path.abspath(os.path.join(B,os.path.pardir));C,B=B,D
-def find_dotenv(filename=_E,raise_error_if_not_found=_B,usecwd=_B):
-	H='.py'
-	def E():B='__file__';A=__import__('__main__',_A,_A,fromlist=[B]);return not hasattr(A,B)
-	if usecwd or E()or getattr(sys,'frozen',_B):B=os.getcwd()
+def find_dotenv(filename='.env',raise_error_if_not_found=_B,usecwd=_B):
+	E='.py'
+	def F():A='__file__';B=__import__('__main__',_A,_A,fromlist=[A]);return not hasattr(B,A)
+	if usecwd or F()or getattr(sys,'frozen',_B):B=os.getcwd()
 	else:
 		A=sys._getframe()
-		if PY2 and not __file__.endswith(H):C=__file__.rsplit('.',1)[0]+H
+		if PY2 and not __file__.endswith(E):C=__file__.rsplit('.',1)[0]+E
 		else:C=__file__
 		while A.f_code.co_filename==C:assert A.f_back is not _A;A=A.f_back
-		F=A.f_code.co_filename;B=os.path.dirname(os.path.abspath(F))
-	for G in _walk_to_root(B):
-		D=os.path.join(G,filename)
+		G=A.f_code.co_filename;B=os.path.dirname(os.path.abspath(G))
+	for H in _walk_to_root(B):
+		D=os.path.join(H,filename)
 		if os.path.isfile(D):return D
 	if raise_error_if_not_found:raise IOError('File not found')
 	return''
diff --git a/dynaconf/vendor/dotenv/parser.py b/dynaconf/vendor/dotenv/parser.py
index 65f4f31..b752784 100644
--- a/dynaconf/vendor/dotenv/parser.py
+++ b/dynaconf/vendor/dotenv/parser.py
@@ -1,9 +1,5 @@
-_I='error'
-_H='original'
-_G='value'
-_F='key'
-_E='Binding'
-_D='line'
+_E='original'
+_D='Binding'
 _C='string'
 _B='Original'
 _A=None
@@ -26,8 +22,8 @@ _end_of_line=make_regex('[^\\S\\r\\n]*(?:\\r\\n|\\n|\\r|$)')
 _rest_of_line=make_regex('[^\\r\\n]*(?:\\r|\\n|\\r\\n)?')
 _double_quote_escapes=make_regex('\\\\[\\\\\'\\"abfnrtv]')
 _single_quote_escapes=make_regex("\\\\[\\\\']")
-try:import typing;Original=typing.NamedTuple(_B,[(_C,typing.Text),(_D,int)]);Binding=typing.NamedTuple(_E,[(_F,typing.Optional[typing.Text]),(_G,typing.Optional[typing.Text]),(_H,Original),(_I,bool)])
-except ImportError:from collections import namedtuple;Original=namedtuple(_B,[_C,_D]);Binding=namedtuple(_E,[_F,_G,_H,_I])
+try:import typing;Original=typing.NamedTuple(_B,[(_C,typing.Text),('line',int)]);Binding=typing.NamedTuple(_D,[('key',typing.Optional[typing.Text]),('value',typing.Optional[typing.Text]),(_E,Original),('error',bool)])
+except ImportError:from collections import namedtuple;Original=namedtuple(_B,[_C,'line']);Binding=namedtuple(_D,['key','value',_E,'error'])
 class Position:
 	def __init__(A,chars,line):A.chars=chars;A.line=line
 	@classmethod
@@ -71,14 +67,14 @@ def parse_value(reader):
 	elif B in('','\n','\r'):return''
 	else:return parse_unquoted_value(A)
 def parse_binding(reader):
-	D=False;A=reader;A.set_mark()
+	C=False;A=reader;A.set_mark()
 	try:
 		A.read_regex(_multiline_whitespace)
-		if not A.has_next():return Binding(key=_A,value=_A,original=A.get_marked(),error=D)
-		A.read_regex(_export);C=parse_key(A);A.read_regex(_whitespace)
+		if not A.has_next():return Binding(key=_A,value=_A,original=A.get_marked(),error=C)
+		A.read_regex(_export);D=parse_key(A);A.read_regex(_whitespace)
 		if A.peek(1)=='=':A.read_regex(_equal_sign);B=parse_value(A)
 		else:B=_A
-		A.read_regex(_comment);A.read_regex(_end_of_line);return Binding(key=C,value=B,original=A.get_marked(),error=D)
+		A.read_regex(_comment);A.read_regex(_end_of_line);return Binding(key=D,value=B,original=A.get_marked(),error=C)
 	except Error:A.read_regex(_rest_of_line);return Binding(key=_A,value=_A,original=A.get_marked(),error=True)
 def parse_stream(stream):
 	A=Reader(stream)
diff --git a/dynaconf/vendor/ruamel/yaml/__init__.py b/dynaconf/vendor/ruamel/yaml/__init__.py
index ac49423..9a272b8 100644
--- a/dynaconf/vendor/ruamel/yaml/__init__.py
+++ b/dynaconf/vendor/ruamel/yaml/__init__.py
@@ -1,10 +1,8 @@
 from __future__ import print_function,absolute_import,division,unicode_literals
-_B='yaml'
-_A=False
-if _A:from typing import Dict,Any
-_package_data=dict(full_package_name='ruamel.yaml',version_info=(0,16,10),__version__='0.16.10',author='Anthon van der Neut',author_email='a.van.der.neut@ruamel.eu',description='ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order',entry_points=None,since=2014,extras_require={':platform_python_implementation=="CPython" and python_version<="2.7"':['ruamel.ordereddict'],':platform_python_implementation=="CPython" and python_version<"3.9"':['ruamel.yaml.clib>=0.1.2'],'jinja2':['ruamel.yaml.jinja2>=0.2'],'docs':['ryd']},classifiers=['Programming Language :: Python :: 2.7','Programming Language :: Python :: 3.5','Programming Language :: Python :: 3.6','Programming Language :: Python :: 3.7','Programming Language :: Python :: 3.8','Programming Language :: Python :: Implementation :: CPython','Programming Language :: Python :: Implementation :: PyPy','Programming Language :: Python :: Implementation :: Jython','Topic :: Software Development :: Libraries :: Python Modules','Topic :: Text Processing :: Markup','Typing :: Typed'],keywords='yaml 1.2 parser round-trip preserve quotes order config',read_the_docs=_B,supported=[(2,7),(3,5)],tox=dict(env='*',deps='ruamel.std.pathlib',fl8excl='_test/lib'),universal=True,rtfd=_B)
+if False:from typing import Dict,Any
+_package_data=dict(full_package_name='ruamel.yaml',version_info=(0,16,10),__version__='0.16.10',author='Anthon van der Neut',author_email='a.van.der.neut@ruamel.eu',description='ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order',entry_points=None,since=2014,extras_require={':platform_python_implementation=="CPython" and python_version<="2.7"':['ruamel.ordereddict'],':platform_python_implementation=="CPython" and python_version<"3.9"':['ruamel.yaml.clib>=0.1.2'],'jinja2':['ruamel.yaml.jinja2>=0.2'],'docs':['ryd']},classifiers=['Programming Language :: Python :: 2.7','Programming Language :: Python :: 3.5','Programming Language :: Python :: 3.6','Programming Language :: Python :: 3.7','Programming Language :: Python :: 3.8','Programming Language :: Python :: Implementation :: CPython','Programming Language :: Python :: Implementation :: PyPy','Programming Language :: Python :: Implementation :: Jython','Topic :: Software Development :: Libraries :: Python Modules','Topic :: Text Processing :: Markup','Typing :: Typed'],keywords='yaml 1.2 parser round-trip preserve quotes order config',read_the_docs='yaml',supported=[(2,7),(3,5)],tox=dict(env='*',deps='ruamel.std.pathlib',fl8excl='_test/lib'),universal=True,rtfd='yaml')
 version_info=_package_data['version_info']
 __version__=_package_data['__version__']
 try:from .cyaml import *;__with_libyaml__=True
-except (ImportError,ValueError):__with_libyaml__=_A
+except (ImportError,ValueError):__with_libyaml__=False
 from dynaconf.vendor.ruamel.yaml.main import *
\ No newline at end of file
diff --git a/dynaconf/vendor/ruamel/yaml/anchor.py b/dynaconf/vendor/ruamel/yaml/anchor.py
index 8327508..cb2d673 100644
--- a/dynaconf/vendor/ruamel/yaml/anchor.py
+++ b/dynaconf/vendor/ruamel/yaml/anchor.py
@@ -1,7 +1,6 @@
-_A=False
-if _A:from typing import Any,Dict,Optional,List,Union,Optional,Iterator
+if False:from typing import Any,Dict,Optional,List,Union,Optional,Iterator
 anchor_attrib='_yaml_anchor'
 class Anchor:
 	__slots__='value','always_dump';attrib=anchor_attrib
-	def __init__(A):A.value=None;A.always_dump=_A
+	def __init__(A):A.value=None;A.always_dump=False
 	def __repr__(A):B=', (always dump)'if A.always_dump else'';return 'Anchor({!r}{})'.format(A.value,B)
\ No newline at end of file
diff --git a/dynaconf/vendor/ruamel/yaml/comments.py b/dynaconf/vendor/ruamel/yaml/comments.py
index da872f8..1f80924 100644
--- a/dynaconf/vendor/ruamel/yaml/comments.py
+++ b/dynaconf/vendor/ruamel/yaml/comments.py
@@ -1,7 +1,5 @@
 from __future__ import absolute_import,print_function
-_G='_od'
-_F='CommentedMap'
-_E='# '
+_E='CommentedMap'
 _D=True
 _C='\n'
 _B=False
@@ -14,7 +12,7 @@ from .anchor import Anchor
 if PY2:from collections import MutableSet,Sized,Set,Mapping
 else:from collections.abc import MutableSet,Sized,Set,Mapping
 if _B:from typing import Any,Dict,Optional,List,Union,Optional,Iterator
-__all__=['CommentedSeq','CommentedKeySeq',_F,'CommentedOrderedMap','CommentedSet','comment_attrib','merge_attrib']
+__all__=['CommentedSeq','CommentedKeySeq',_E,'CommentedOrderedMap','CommentedSet','comment_attrib','merge_attrib']
 comment_attrib='_yaml_comment'
 format_attrib='_yaml_format'
 line_col_attrib='_yaml_line_col'
@@ -96,10 +94,10 @@ class CommentedBase:
 		A=comment;from .error import CommentMark as C;from .tokens import CommentToken as D;E=B._yaml_get_pre_comment()
 		if A[-1]==_C:A=A[:-1]
 		F=C(indent)
-		for G in A.split(_C):E.append(D(_E+G+_C,F,_A))
+		for G in A.split(_C):E.append(D('# '+G+_C,F,_A))
 	def yaml_set_comment_before_after_key(J,key,before=_A,indent=0,after=_A,after_indent=_A):
 		H=indent;E=after_indent;B=after;A=before;from dynaconf.vendor.ruamel.yaml.error import CommentMark as I;from dynaconf.vendor.ruamel.yaml.tokens import CommentToken as K
-		def F(s,mark):return K((_E if s else'')+s+_C,mark,_A)
+		def F(s,mark):return K(('# 'if s else'')+s+_C,mark,_A)
 		if E is _A:E=H+2
 		if A and len(A)>1 and A[-1]==_C:A=A[:-1]
 		if B and B[-1]==_C:B=B[:-1]
@@ -117,13 +115,13 @@ class CommentedBase:
 		if not hasattr(A,Format.attrib):setattr(A,Format.attrib,Format())
 		return getattr(A,Format.attrib)
 	def yaml_add_eol_comment(C,comment,key=NoComment,column=_A):
-		H='#';B=column;A=comment;from .tokens import CommentToken as D;from .error import CommentMark as E
+		B=column;A=comment;from .tokens import CommentToken as D;from .error import CommentMark as E
 		if B is _A:
 			try:B=C._yaml_get_column(key)
 			except AttributeError:B=0
-		if A[0]!=H:A=_E+A
+		if A[0]!='#':A='# '+A
 		if B is _A:
-			if A[0]==H:A=' '+A;B=0
+			if A[0]=='#':A=' '+A;B=0
 		F=E(B);G=[D(A,F,_A),_A];C._yaml_add_eol_comment(G,key=key)
 	@property
 	def lc(self):
@@ -158,7 +156,7 @@ class CommentedBase:
 	def _yaml_get_column(A,key):raise NotImplementedError
 class CommentedSeq(MutableSliceableSequence,list,CommentedBase):
 	__slots__=Comment.attrib,'_lst'
-	def __init__(A,*B,**C):list.__init__(A,*B,**C)
+	def __init__(A,*B,**C):list.__init__(A,*(B),**C)
 	def __getsingleitem__(A,idx):return list.__getitem__(A,idx)
 	def __setsingleitem__(B,idx,value):
 		C=idx;A=value
@@ -269,7 +267,7 @@ class CommentedMapValuesView(CommentedMapView):
 		for B in A._mapping._keys():yield A._mapping[B]
 class CommentedMap(ordereddict,CommentedBase):
 	__slots__=Comment.attrib,'_ok','_ref'
-	def __init__(A,*B,**C):A._ok=set();A._ref=[];ordereddict.__init__(A,*B,**C)
+	def __init__(A,*B,**C):A._ok=set();A._ref=[];ordereddict.__init__(A,*(B),**C)
 	def _yaml_add_comment(A,comment,key=NoComment,value=NoComment):
 		C=value;B=comment
 		if key is not NoComment:A.yaml_key_comment_extend(key,B);return
@@ -342,7 +340,7 @@ class CommentedMap(ordereddict,CommentedBase):
 	def get(A,key,default=_A):
 		try:return A.__getitem__(key)
 		except:return default
-	def __repr__(A):return ordereddict.__repr__(A).replace(_F,'ordereddict')
+	def __repr__(A):return ordereddict.__repr__(A).replace(_E,'ordereddict')
 	def non_merged_items(A):
 		for B in ordereddict.__iter__(A):
 			if B in A._ok:yield(B,ordereddict.__getitem__(A,B))
@@ -409,10 +407,10 @@ class CommentedMap(ordereddict,CommentedBase):
 @classmethod
 def raise_immutable(cls,*A,**B):raise TypeError('{} objects are immutable'.format(cls.__name__))
 class CommentedKeyMap(CommentedBase,Mapping):
-	__slots__=Comment.attrib,_G
+	__slots__=Comment.attrib,'_od'
 	def __init__(A,*B,**C):
-		if hasattr(A,_G):raise_immutable(A)
-		try:A._od=ordereddict(*B,**C)
+		if hasattr(A,'_od'):raise_immutable(A)
+		try:A._od=ordereddict(*(B),**C)
 		except TypeError:
 			if PY2:A._od=ordereddict(B[0].items())
 			else:raise
@@ -474,12 +472,12 @@ class TaggedScalar(CommentedBase):
 		if tag is not _A:A.yaml_set_tag(tag)
 	def __str__(A):return A.value
 def dump_comments(d,name='',sep='.',out=sys.stdout):
-	G='ca';E='{}\n';D=out;C=sep;A=name
-	if isinstance(d,dict)and hasattr(d,G):
+	E='{}\n';D=out;C=sep;A=name
+	if isinstance(d,dict)and hasattr(d,'ca'):
 		if A:sys.stdout.write(E.format(A))
 		D.write(E.format(d.ca))
 		for B in d:dump_comments(d[B],name=A+C+B if A else B,sep=C,out=D)
-	elif isinstance(d,list)and hasattr(d,G):
+	elif isinstance(d,list)and hasattr(d,'ca'):
 		if A:sys.stdout.write(E.format(A))
 		D.write(E.format(d.ca))
 		for (F,B) in enumerate(d):dump_comments(B,name=A+C+str(F)if A else str(F),sep=C,out=D)
\ No newline at end of file
diff --git a/dynaconf/vendor/ruamel/yaml/compat.py b/dynaconf/vendor/ruamel/yaml/compat.py
index 0512ad7..c8033f7 100644
--- a/dynaconf/vendor/ruamel/yaml/compat.py
+++ b/dynaconf/vendor/ruamel/yaml/compat.py
@@ -66,7 +66,7 @@ class Nprint:
 	def __init__(A,file_name=_A):A._max_print=_A;A._count=_A;A._file_name=file_name
 	def __call__(A,*E,**F):
 		if not bool(_debug):return
-		B=sys.stdout if A._file_name is _A else open(A._file_name,'a');C=print;D=F.copy();D['file']=B;C(*E,**D);B.flush()
+		B=sys.stdout if A._file_name is _A else open(A._file_name,'a');C=print;D=F.copy();D['file']=B;C(*(E),**D);B.flush()
 		if A._max_print is not _A:
 			if A._count is _A:A._count=A._max_print
 			A._count-=1
@@ -107,7 +107,7 @@ class MutableSliceableSequence(MutableSequence):
 			D=A.indices(len(C));E=(D[1]-D[0]-1)//D[2]+1
 			if E<len(B):raise TypeError('too many elements in value {} < {}'.format(E,len(B)))
 			elif E>len(B):raise TypeError('not enough elements in value {} > {}'.format(E,len(B)))
-			for (G,H) in enumerate(range(*D)):C[H]=B[G]
+			for (G,H) in enumerate(range(*(D))):C[H]=B[G]
 	def __delitem__(A,index):
 		B=index
 		if not isinstance(B,slice):return A.__delsingleitem__(B)
diff --git a/dynaconf/vendor/ruamel/yaml/composer.py b/dynaconf/vendor/ruamel/yaml/composer.py
index 9a0f8f0..37a24d2 100644
--- a/dynaconf/vendor/ruamel/yaml/composer.py
+++ b/dynaconf/vendor/ruamel/yaml/composer.py
@@ -1,5 +1,4 @@
 from __future__ import absolute_import,print_function
-_B='typ'
 _A=None
 import warnings
 from .error import MarkedYAMLError,ReusedAnchorWarning
@@ -17,12 +16,12 @@ class Composer:
 	@property
 	def parser(self):
 		A=self
-		if hasattr(A.loader,_B):A.loader.parser
+		if hasattr(A.loader,'typ'):A.loader.parser
 		return A.loader._parser
 	@property
 	def resolver(self):
 		A=self
-		if hasattr(A.loader,_B):A.loader.resolver
+		if hasattr(A.loader,'typ'):A.loader.resolver
 		return A.loader._resolver
 	def check_node(A):
 		if A.parser.check_event(StreamStartEvent):A.parser.get_event()
diff --git a/dynaconf/vendor/ruamel/yaml/constructor.py b/dynaconf/vendor/ruamel/yaml/constructor.py
index 2400e6b..9897b80 100644
--- a/dynaconf/vendor/ruamel/yaml/constructor.py
+++ b/dynaconf/vendor/ruamel/yaml/constructor.py
@@ -1,61 +1,53 @@
 from __future__ import print_function,absolute_import,division
-_AD='expected the empty value, but found %r'
-_AC='cannot find module %r (%s)'
-_AB='expected non-empty name appended to the tag'
-_AA='tag:yaml.org,2002:map'
-_A9='tag:yaml.org,2002:seq'
-_A8='tag:yaml.org,2002:set'
-_A7='tag:yaml.org,2002:pairs'
-_A6='tag:yaml.org,2002:omap'
-_A5='tag:yaml.org,2002:timestamp'
-_A4='tag:yaml.org,2002:binary'
-_A3='tag:yaml.org,2002:float'
-_A2='tag:yaml.org,2002:int'
-_A1='tag:yaml.org,2002:bool'
-_A0='tag:yaml.org,2002:null'
-_z='could not determine a constructor for the tag %r'
-_y='second'
-_x='minute'
-_w='day'
-_v='month'
-_u='year'
-_t='failed to construct timestamp from "{}"'
-_s='decodebytes'
-_r='failed to convert base64 data into ascii: %s'
-_q='.nan'
-_p='.inf'
-_o='expected a mapping or list of mappings for merging, but found %s'
-_n='expected a mapping for merging, but found %s'
-_m='                        Duplicate keys will become an error in future releases, and are errors\n                        by default when using the new API.\n                        '
-_l='\n                        To suppress this check see:\n                           http://yaml.readthedocs.io/en/latest/api.html#duplicate-keys\n                        '
-_k='tag:yaml.org,2002:merge'
-_j='                    Duplicate keys will become an error in future releases, and are errors\n                    by default when using the new API.\n                    '
-_i='\n                    To suppress this check see:\n                        http://yaml.readthedocs.io/en/latest/api.html#duplicate-keys\n                    '
-_h='expected a sequence node, but found %s'
-_g='expected a scalar node, but found %s'
-_f='typ'
-_e='while constructing a Python module'
-_d='expected a single mapping item, but found %d items'
-_c='expected a mapping of length 1, but found %s'
-_b='expected a sequence, but found %s'
-_a='failed to decode base64 data: %s'
-_Z='tag:yaml.org,2002:value'
-_Y='found duplicate key "{}"'
-_X='found unhashable key'
-_W='found unacceptable key (%s)'
-_V='__setstate__'
-_U='tz_hour'
-_T='hour'
-_S='ascii'
-_R='tag:yaml.org,2002:str'
-_Q='utf-8'
-_P='expected a mapping node, but found %s'
-_O='tz_minute'
-_N='e'
-_M='+-'
-_L='while constructing an ordered map'
-_K='tz_sign'
-_J='-'
+_A5='expected the empty value, but found %r'
+_A4='cannot find module %r (%s)'
+_A3='expected non-empty name appended to the tag'
+_A2='tag:yaml.org,2002:map'
+_A1='tag:yaml.org,2002:seq'
+_A0='tag:yaml.org,2002:set'
+_z='tag:yaml.org,2002:pairs'
+_y='tag:yaml.org,2002:omap'
+_x='tag:yaml.org,2002:timestamp'
+_w='tag:yaml.org,2002:binary'
+_v='tag:yaml.org,2002:float'
+_u='tag:yaml.org,2002:int'
+_t='tag:yaml.org,2002:bool'
+_s='tag:yaml.org,2002:null'
+_r='could not determine a constructor for the tag %r'
+_q='second'
+_p='minute'
+_o='failed to construct timestamp from "{}"'
+_n='decodebytes'
+_m='failed to convert base64 data into ascii: %s'
+_l='expected a mapping or list of mappings for merging, but found %s'
+_k='expected a mapping for merging, but found %s'
+_j='                        Duplicate keys will become an error in future releases, and are errors\n                        by default when using the new API.\n                        '
+_i='\n                        To suppress this check see:\n                           http://yaml.readthedocs.io/en/latest/api.html#duplicate-keys\n                        '
+_h='tag:yaml.org,2002:merge'
+_g='                    Duplicate keys will become an error in future releases, and are errors\n                    by default when using the new API.\n                    '
+_f='\n                    To suppress this check see:\n                        http://yaml.readthedocs.io/en/latest/api.html#duplicate-keys\n                    '
+_e='expected a sequence node, but found %s'
+_d='expected a scalar node, but found %s'
+_c='while constructing a Python module'
+_b='expected a single mapping item, but found %d items'
+_a='expected a mapping of length 1, but found %s'
+_Z='expected a sequence, but found %s'
+_Y='failed to decode base64 data: %s'
+_X='tag:yaml.org,2002:value'
+_W='found duplicate key "{}"'
+_V='found unhashable key'
+_U='found unacceptable key (%s)'
+_T='__setstate__'
+_S='tz_hour'
+_R='hour'
+_Q='ascii'
+_P='tag:yaml.org,2002:str'
+_O='utf-8'
+_N='expected a mapping node, but found %s'
+_M='tz_minute'
+_L='+-'
+_K='while constructing an ordered map'
+_J='tz_sign'
 _I='fraction'
 _H='.'
 _G=':'
@@ -93,12 +85,12 @@ class BaseConstructor:
 		self.loader=loader;self.yaml_base_dict_type=dict;self.yaml_base_list_type=list;self.constructed_objects={};self.recursive_objects={};self.state_generators=[];self.deep_construct=_B;self._preserve_quotes=preserve_quotes;self.allow_duplicate_keys=version_tnf((0,15,1),(0,16))
 	@property
 	def composer(self):
-		if hasattr(self.loader,_f):return self.loader.composer
+		if hasattr(self.loader,'typ'):return self.loader.composer
 		try:return self.loader._composer
 		except AttributeError:sys.stdout.write('slt {}\n'.format(type(self)));sys.stdout.write('slc {}\n'.format(self.loader._composer));sys.stdout.write('{}\n'.format(dir(self)));raise
 	@property
 	def resolver(self):
-		if hasattr(self.loader,_f):return self.loader.resolver
+		if hasattr(self.loader,'typ'):return self.loader.resolver
 		return self.loader._resolver
 	def check_data(self):return self.composer.check_node()
 	def get_data(self):
@@ -143,13 +135,13 @@ class BaseConstructor:
 			else:self.state_generators.append(generator)
 		return data
 	def construct_scalar(self,node):
-		if not isinstance(node,ScalarNode):raise ConstructorError(_A,_A,_g%node.id,node.start_mark)
+		if not isinstance(node,ScalarNode):raise ConstructorError(_A,_A,_d%node.id,node.start_mark)
 		return node.value
 	def construct_sequence(self,node,deep=_B):
-		if not isinstance(node,SequenceNode):raise ConstructorError(_A,_A,_h%node.id,node.start_mark)
+		if not isinstance(node,SequenceNode):raise ConstructorError(_A,_A,_e%node.id,node.start_mark)
 		return[self.construct_object(child,deep=deep)for child in node.value]
 	def construct_mapping(self,node,deep=_B):
-		if not isinstance(node,MappingNode):raise ConstructorError(_A,_A,_P%node.id,node.start_mark)
+		if not isinstance(node,MappingNode):raise ConstructorError(_A,_A,_N%node.id,node.start_mark)
 		total_mapping=self.yaml_base_dict_type()
 		if getattr(node,'merge',_A)is not _A:todo=[(node.merge,_B),(node.value,_B)]
 		else:todo=[(node.value,_C)]
@@ -161,8 +153,8 @@ class BaseConstructor:
 					if isinstance(key,list):key=tuple(key)
 				if PY2:
 					try:hash(key)
-					except TypeError as exc:raise ConstructorError(_E,node.start_mark,_W%exc,key_node.start_mark)
-				elif not isinstance(key,Hashable):raise ConstructorError(_E,node.start_mark,_X,key_node.start_mark)
+					except TypeError as exc:raise ConstructorError(_E,node.start_mark,_U%exc,key_node.start_mark)
+				elif not isinstance(key,Hashable):raise ConstructorError(_E,node.start_mark,_V,key_node.start_mark)
 				value=self.construct_object(value_node,deep=deep)
 				if check:
 					if self.check_mapping_key(node,key_node,mapping,key,value):mapping[key]=value
@@ -174,24 +166,24 @@ class BaseConstructor:
 			if not self.allow_duplicate_keys:
 				mk=mapping.get(key)
 				if PY2:
-					if isinstance(key,unicode):key=key.encode(_Q)
-					if isinstance(value,unicode):value=value.encode(_Q)
-					if isinstance(mk,unicode):mk=mk.encode(_Q)
-				args=[_E,node.start_mark,'found duplicate key "{}" with value "{}" (original value: "{}")'.format(key,value,mk),key_node.start_mark,_i,_j]
-				if self.allow_duplicate_keys is _A:warnings.warn(DuplicateKeyFutureWarning(*args))
-				else:raise DuplicateKeyError(*args)
+					if isinstance(key,unicode):key=key.encode(_O)
+					if isinstance(value,unicode):value=value.encode(_O)
+					if isinstance(mk,unicode):mk=mk.encode(_O)
+				args=[_E,node.start_mark,'found duplicate key "{}" with value "{}" (original value: "{}")'.format(key,value,mk),key_node.start_mark,_f,_g]
+				if self.allow_duplicate_keys is _A:warnings.warn(DuplicateKeyFutureWarning(*(args)))
+				else:raise DuplicateKeyError(*(args))
 			return _B
 		return _C
 	def check_set_key(self,node,key_node,setting,key):
 		if key in setting:
 			if not self.allow_duplicate_keys:
 				if PY2:
-					if isinstance(key,unicode):key=key.encode(_Q)
-				args=['while constructing a set',node.start_mark,_Y.format(key),key_node.start_mark,_i,_j]
-				if self.allow_duplicate_keys is _A:warnings.warn(DuplicateKeyFutureWarning(*args))
-				else:raise DuplicateKeyError(*args)
+					if isinstance(key,unicode):key=key.encode(_O)
+				args=['while constructing a set',node.start_mark,_W.format(key),key_node.start_mark,_f,_g]
+				if self.allow_duplicate_keys is _A:warnings.warn(DuplicateKeyFutureWarning(*(args)))
+				else:raise DuplicateKeyError(*(args))
 	def construct_pairs(self,node,deep=_B):
-		if not isinstance(node,MappingNode):raise ConstructorError(_A,_A,_P%node.id,node.start_mark)
+		if not isinstance(node,MappingNode):raise ConstructorError(_A,_A,_N%node.id,node.start_mark)
 		pairs=[]
 		for (key_node,value_node) in node.value:key=self.construct_object(key_node,deep=deep);value=self.construct_object(value_node,deep=deep);pairs.append((key,value))
 		return pairs
@@ -207,29 +199,29 @@ class SafeConstructor(BaseConstructor):
 	def construct_scalar(self,node):
 		if isinstance(node,MappingNode):
 			for (key_node,value_node) in node.value:
-				if key_node.tag==_Z:return self.construct_scalar(value_node)
+				if key_node.tag==_X:return self.construct_scalar(value_node)
 		return BaseConstructor.construct_scalar(self,node)
 	def flatten_mapping(self,node):
 		merge=[];index=0
 		while index<len(node.value):
 			key_node,value_node=node.value[index]
-			if key_node.tag==_k:
+			if key_node.tag==_h:
 				if merge:
 					if self.allow_duplicate_keys:del node.value[index];index+=1;continue
-					args=[_E,node.start_mark,_Y.format(key_node.value),key_node.start_mark,_l,_m]
-					if self.allow_duplicate_keys is _A:warnings.warn(DuplicateKeyFutureWarning(*args))
-					else:raise DuplicateKeyError(*args)
+					args=[_E,node.start_mark,_W.format(key_node.value),key_node.start_mark,_i,_j]
+					if self.allow_duplicate_keys is _A:warnings.warn(DuplicateKeyFutureWarning(*(args)))
+					else:raise DuplicateKeyError(*(args))
 				del node.value[index]
 				if isinstance(value_node,MappingNode):self.flatten_mapping(value_node);merge.extend(value_node.value)
 				elif isinstance(value_node,SequenceNode):
 					submerge=[]
 					for subnode in value_node.value:
-						if not isinstance(subnode,MappingNode):raise ConstructorError(_E,node.start_mark,_n%subnode.id,subnode.start_mark)
+						if not isinstance(subnode,MappingNode):raise ConstructorError(_E,node.start_mark,_k%subnode.id,subnode.start_mark)
 						self.flatten_mapping(subnode);submerge.append(subnode.value)
 					submerge.reverse()
 					for value in submerge:merge.extend(value)
-				else:raise ConstructorError(_E,node.start_mark,_o%value_node.id,value_node.start_mark)
-			elif key_node.tag==_Z:key_node.tag=_R;index+=1
+				else:raise ConstructorError(_E,node.start_mark,_l%value_node.id,value_node.start_mark)
+			elif key_node.tag==_X:key_node.tag=_P;index+=1
 			else:index+=1
 		if bool(merge):node.merge=merge;node.value=merge+node.value
 	def construct_mapping(self,node,deep=_B):
@@ -240,8 +232,8 @@ class SafeConstructor(BaseConstructor):
 	def construct_yaml_bool(self,node):value=self.construct_scalar(node);return self.bool_values[value.lower()]
 	def construct_yaml_int(self,node):
 		value_s=to_str(self.construct_scalar(node));value_s=value_s.replace(_D,'');sign=+1
-		if value_s[0]==_J:sign=-1
-		if value_s[0]in _M:value_s=value_s[1:]
+		if value_s[0]=='-':sign=-1
+		if value_s[0]in _L:value_s=value_s[1:]
 		if value_s==_F:return 0
 		elif value_s.startswith('0b'):return sign*int(value_s[2:],2)
 		elif value_s.startswith('0x'):return sign*int(value_s[2:],16)
@@ -257,93 +249,93 @@ class SafeConstructor(BaseConstructor):
 	nan_value=-inf_value/inf_value
 	def construct_yaml_float(self,node):
 		value_so=to_str(self.construct_scalar(node));value_s=value_so.replace(_D,'').lower();sign=+1
-		if value_s[0]==_J:sign=-1
-		if value_s[0]in _M:value_s=value_s[1:]
-		if value_s==_p:return sign*self.inf_value
-		elif value_s==_q:return self.nan_value
+		if value_s[0]=='-':sign=-1
+		if value_s[0]in _L:value_s=value_s[1:]
+		if value_s=='.inf':return sign*self.inf_value
+		elif value_s=='.nan':return self.nan_value
 		elif self.resolver.processing_version!=(1,2)and _G in value_s:
 			digits=[float(part)for part in value_s.split(_G)];digits.reverse();base=1;value=0.0
 			for digit in digits:value+=digit*base;base*=60
 			return sign*value
 		else:
-			if self.resolver.processing_version!=(1,2)and _N in value_s:
-				mantissa,exponent=value_s.split(_N)
+			if self.resolver.processing_version!=(1,2)and'e'in value_s:
+				mantissa,exponent=value_s.split('e')
 				if _H not in mantissa:warnings.warn(MantissaNoDotYAML1_1Warning(node,value_so))
 			return sign*float(value_s)
 	if PY3:
 		def construct_yaml_binary(self,node):
-			try:value=self.construct_scalar(node).encode(_S)
-			except UnicodeEncodeError as exc:raise ConstructorError(_A,_A,_r%exc,node.start_mark)
+			try:value=self.construct_scalar(node).encode(_Q)
+			except UnicodeEncodeError as exc:raise ConstructorError(_A,_A,_m%exc,node.start_mark)
 			try:
-				if hasattr(base64,_s):return base64.decodebytes(value)
+				if hasattr(base64,_n):return base64.decodebytes(value)
 				else:return base64.decodestring(value)
-			except binascii.Error as exc:raise ConstructorError(_A,_A,_a%exc,node.start_mark)
+			except binascii.Error as exc:raise ConstructorError(_A,_A,_Y%exc,node.start_mark)
 	else:
 		def construct_yaml_binary(self,node):
 			value=self.construct_scalar(node)
 			try:return to_str(value).decode('base64')
-			except (binascii.Error,UnicodeEncodeError)as exc:raise ConstructorError(_A,_A,_a%exc,node.start_mark)
+			except (binascii.Error,UnicodeEncodeError)as exc:raise ConstructorError(_A,_A,_Y%exc,node.start_mark)
 	timestamp_regexp=RegExp('^(?P<year>[0-9][0-9][0-9][0-9])\n          -(?P<month>[0-9][0-9]?)\n          -(?P<day>[0-9][0-9]?)\n          (?:((?P<t>[Tt])|[ \\t]+)   # explictly not retaining extra spaces\n          (?P<hour>[0-9][0-9]?)\n          :(?P<minute>[0-9][0-9])\n          :(?P<second>[0-9][0-9])\n          (?:\\.(?P<fraction>[0-9]*))?\n          (?:[ \\t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)\n          (?::(?P<tz_minute>[0-9][0-9]))?))?)?$',re.X)
 	def construct_yaml_timestamp(self,node,values=_A):
 		if values is _A:
 			try:match=self.timestamp_regexp.match(node.value)
 			except TypeError:match=_A
-			if match is _A:raise ConstructorError(_A,_A,_t.format(node.value),node.start_mark)
+			if match is _A:raise ConstructorError(_A,_A,_o.format(node.value),node.start_mark)
 			values=match.groupdict()
-		year=int(values[_u]);month=int(values[_v]);day=int(values[_w])
-		if not values[_T]:return datetime.date(year,month,day)
-		hour=int(values[_T]);minute=int(values[_x]);second=int(values[_y]);fraction=0
+		year=int(values['year']);month=int(values['month']);day=int(values['day'])
+		if not values[_R]:return datetime.date(year,month,day)
+		hour=int(values[_R]);minute=int(values[_p]);second=int(values[_q]);fraction=0
 		if values[_I]:
 			fraction_s=values[_I][:6]
 			while len(fraction_s)<6:fraction_s+=_F
 			fraction=int(fraction_s)
 			if len(values[_I])>6 and int(values[_I][6])>4:fraction+=1
 		delta=_A
-		if values[_K]:
-			tz_hour=int(values[_U]);minutes=values[_O];tz_minute=int(minutes)if minutes else 0;delta=datetime.timedelta(hours=tz_hour,minutes=tz_minute)
-			if values[_K]==_J:delta=-delta
+		if values[_J]:
+			tz_hour=int(values[_S]);minutes=values[_M];tz_minute=int(minutes)if minutes else 0;delta=datetime.timedelta(hours=tz_hour,minutes=tz_minute)
+			if values[_J]=='-':delta=-delta
 		data=datetime.datetime(year,month,day,hour,minute,second,fraction)
 		if delta:data-=delta
 		return data
 	def construct_yaml_omap(self,node):
 		omap=ordereddict();yield omap
-		if not isinstance(node,SequenceNode):raise ConstructorError(_L,node.start_mark,_b%node.id,node.start_mark)
+		if not isinstance(node,SequenceNode):raise ConstructorError(_K,node.start_mark,_Z%node.id,node.start_mark)
 		for subnode in node.value:
-			if not isinstance(subnode,MappingNode):raise ConstructorError(_L,node.start_mark,_c%subnode.id,subnode.start_mark)
-			if len(subnode.value)!=1:raise ConstructorError(_L,node.start_mark,_d%len(subnode.value),subnode.start_mark)
+			if not isinstance(subnode,MappingNode):raise ConstructorError(_K,node.start_mark,_a%subnode.id,subnode.start_mark)
+			if len(subnode.value)!=1:raise ConstructorError(_K,node.start_mark,_b%len(subnode.value),subnode.start_mark)
 			key_node,value_node=subnode.value[0];key=self.construct_object(key_node);assert key not in omap;value=self.construct_object(value_node);omap[key]=value
 	def construct_yaml_pairs(self,node):
 		A='while constructing pairs';pairs=[];yield pairs
-		if not isinstance(node,SequenceNode):raise ConstructorError(A,node.start_mark,_b%node.id,node.start_mark)
+		if not isinstance(node,SequenceNode):raise ConstructorError(A,node.start_mark,_Z%node.id,node.start_mark)
 		for subnode in node.value:
-			if not isinstance(subnode,MappingNode):raise ConstructorError(A,node.start_mark,_c%subnode.id,subnode.start_mark)
-			if len(subnode.value)!=1:raise ConstructorError(A,node.start_mark,_d%len(subnode.value),subnode.start_mark)
+			if not isinstance(subnode,MappingNode):raise ConstructorError(A,node.start_mark,_a%subnode.id,subnode.start_mark)
+			if len(subnode.value)!=1:raise ConstructorError(A,node.start_mark,_b%len(subnode.value),subnode.start_mark)
 			key_node,value_node=subnode.value[0];key=self.construct_object(key_node);value=self.construct_object(value_node);pairs.append((key,value))
 	def construct_yaml_set(self,node):data=set();yield data;value=self.construct_mapping(node);data.update(value)
 	def construct_yaml_str(self,node):
 		value=self.construct_scalar(node)
 		if PY3:return value
-		try:return value.encode(_S)
+		try:return value.encode(_Q)
 		except UnicodeEncodeError:return value
 	def construct_yaml_seq(self,node):data=self.yaml_base_list_type();yield data;data.extend(self.construct_sequence(node))
 	def construct_yaml_map(self,node):data=self.yaml_base_dict_type();yield data;value=self.construct_mapping(node);data.update(value)
 	def construct_yaml_object(self,node,cls):
 		data=cls.__new__(cls);yield data
-		if hasattr(data,_V):state=self.construct_mapping(node,deep=_C);data.__setstate__(state)
+		if hasattr(data,_T):state=self.construct_mapping(node,deep=_C);data.__setstate__(state)
 		else:state=self.construct_mapping(node);data.__dict__.update(state)
-	def construct_undefined(self,node):raise ConstructorError(_A,_A,_z%utf8(node.tag),node.start_mark)
-SafeConstructor.add_constructor(_A0,SafeConstructor.construct_yaml_null)
-SafeConstructor.add_constructor(_A1,SafeConstructor.construct_yaml_bool)
-SafeConstructor.add_constructor(_A2,SafeConstructor.construct_yaml_int)
-SafeConstructor.add_constructor(_A3,SafeConstructor.construct_yaml_float)
-SafeConstructor.add_constructor(_A4,SafeConstructor.construct_yaml_binary)
-SafeConstructor.add_constructor(_A5,SafeConstructor.construct_yaml_timestamp)
-SafeConstructor.add_constructor(_A6,SafeConstructor.construct_yaml_omap)
-SafeConstructor.add_constructor(_A7,SafeConstructor.construct_yaml_pairs)
-SafeConstructor.add_constructor(_A8,SafeConstructor.construct_yaml_set)
-SafeConstructor.add_constructor(_R,SafeConstructor.construct_yaml_str)
-SafeConstructor.add_constructor(_A9,SafeConstructor.construct_yaml_seq)
-SafeConstructor.add_constructor(_AA,SafeConstructor.construct_yaml_map)
+	def construct_undefined(self,node):raise ConstructorError(_A,_A,_r%utf8(node.tag),node.start_mark)
+SafeConstructor.add_constructor(_s,SafeConstructor.construct_yaml_null)
+SafeConstructor.add_constructor(_t,SafeConstructor.construct_yaml_bool)
+SafeConstructor.add_constructor(_u,SafeConstructor.construct_yaml_int)
+SafeConstructor.add_constructor(_v,SafeConstructor.construct_yaml_float)
+SafeConstructor.add_constructor(_w,SafeConstructor.construct_yaml_binary)
+SafeConstructor.add_constructor(_x,SafeConstructor.construct_yaml_timestamp)
+SafeConstructor.add_constructor(_y,SafeConstructor.construct_yaml_omap)
+SafeConstructor.add_constructor(_z,SafeConstructor.construct_yaml_pairs)
+SafeConstructor.add_constructor(_A0,SafeConstructor.construct_yaml_set)
+SafeConstructor.add_constructor(_P,SafeConstructor.construct_yaml_str)
+SafeConstructor.add_constructor(_A1,SafeConstructor.construct_yaml_seq)
+SafeConstructor.add_constructor(_A2,SafeConstructor.construct_yaml_map)
 SafeConstructor.add_constructor(_A,SafeConstructor.construct_undefined)
 if PY2:
 	class classobj:0
@@ -352,12 +344,12 @@ class Constructor(SafeConstructor):
 	def construct_python_unicode(self,node):return self.construct_scalar(node)
 	if PY3:
 		def construct_python_bytes(self,node):
-			try:value=self.construct_scalar(node).encode(_S)
-			except UnicodeEncodeError as exc:raise ConstructorError(_A,_A,_r%exc,node.start_mark)
+			try:value=self.construct_scalar(node).encode(_Q)
+			except UnicodeEncodeError as exc:raise ConstructorError(_A,_A,_m%exc,node.start_mark)
 			try:
-				if hasattr(base64,_s):return base64.decodebytes(value)
+				if hasattr(base64,_n):return base64.decodebytes(value)
 				else:return base64.decodestring(value)
-			except binascii.Error as exc:raise ConstructorError(_A,_A,_a%exc,node.start_mark)
+			except binascii.Error as exc:raise ConstructorError(_A,_A,_Y%exc,node.start_mark)
 	def construct_python_long(self,node):
 		val=self.construct_yaml_int(node)
 		if PY3:return val
@@ -365,13 +357,13 @@ class Constructor(SafeConstructor):
 	def construct_python_complex(self,node):return complex(self.construct_scalar(node))
 	def construct_python_tuple(self,node):return tuple(self.construct_sequence(node))
 	def find_python_module(self,name,mark):
-		if not name:raise ConstructorError(_e,mark,_AB,mark)
+		if not name:raise ConstructorError(_c,mark,_A3,mark)
 		try:__import__(name)
-		except ImportError as exc:raise ConstructorError(_e,mark,_AC%(utf8(name),exc),mark)
+		except ImportError as exc:raise ConstructorError(_c,mark,_A4%(utf8(name),exc),mark)
 		return sys.modules[name]
 	def find_python_name(self,name,mark):
 		A='while constructing a Python object'
-		if not name:raise ConstructorError(A,mark,_AB,mark)
+		if not name:raise ConstructorError(A,mark,_A3,mark)
 		if _H in name:
 			lname=name.split(_H);lmodule_name=lname;lobject_name=[]
 			while len(lmodule_name)>1:
@@ -380,7 +372,7 @@ class Constructor(SafeConstructor):
 				except ImportError:continue
 		else:module_name=builtins_module;lobject_name=[name]
 		try:__import__(module_name)
-		except ImportError as exc:raise ConstructorError(A,mark,_AC%(utf8(module_name),exc),mark)
+		except ImportError as exc:raise ConstructorError(A,mark,_A4%(utf8(module_name),exc),mark)
 		module=sys.modules[module_name];object_name=_H.join(lobject_name);obj=module
 		while lobject_name:
 			if not hasattr(obj,lobject_name[0]):raise ConstructorError(A,mark,'cannot find %r in the module %r'%(utf8(object_name),module.__name__),mark)
@@ -388,31 +380,31 @@ class Constructor(SafeConstructor):
 		return obj
 	def construct_python_name(self,suffix,node):
 		value=self.construct_scalar(node)
-		if value:raise ConstructorError('while constructing a Python name',node.start_mark,_AD%utf8(value),node.start_mark)
+		if value:raise ConstructorError('while constructing a Python name',node.start_mark,_A5%utf8(value),node.start_mark)
 		return self.find_python_name(suffix,node.start_mark)
 	def construct_python_module(self,suffix,node):
 		value=self.construct_scalar(node)
-		if value:raise ConstructorError(_e,node.start_mark,_AD%utf8(value),node.start_mark)
+		if value:raise ConstructorError(_c,node.start_mark,_A5%utf8(value),node.start_mark)
 		return self.find_python_module(suffix,node.start_mark)
 	def make_python_instance(self,suffix,node,args=_A,kwds=_A,newobj=_B):
 		if not args:args=[]
 		if not kwds:kwds={}
 		cls=self.find_python_name(suffix,node.start_mark)
 		if PY3:
-			if newobj and isinstance(cls,type):return cls.__new__(cls,*args,**kwds)
-			else:return cls(*args,**kwds)
+			if newobj and isinstance(cls,type):return cls.__new__(cls,*(args),**kwds)
+			else:return cls(*(args),**kwds)
 		elif newobj and isinstance(cls,type(classobj))and not args and not kwds:instance=classobj();instance.__class__=cls;return instance
-		elif newobj and isinstance(cls,type):return cls.__new__(cls,*args,**kwds)
-		else:return cls(*args,**kwds)
+		elif newobj and isinstance(cls,type):return cls.__new__(cls,*(args),**kwds)
+		else:return cls(*(args),**kwds)
 	def set_python_instance_state(self,instance,state):
-		if hasattr(instance,_V):instance.__setstate__(state)
+		if hasattr(instance,_T):instance.__setstate__(state)
 		else:
 			slotstate={}
 			if isinstance(state,tuple)and len(state)==2:state,slotstate=state
 			if hasattr(instance,'__dict__'):instance.__dict__.update(state)
 			elif state:slotstate.update(state)
 			for (key,value) in slotstate.items():setattr(instance,key,value)
-	def construct_python_object(self,suffix,node):instance=self.make_python_instance(suffix,node,newobj=_C);self.recursive_objects[node]=instance;yield instance;deep=hasattr(instance,_V);state=self.construct_mapping(node,deep=deep);self.set_python_instance_state(instance,state)
+	def construct_python_object(self,suffix,node):instance=self.make_python_instance(suffix,node,newobj=_C);self.recursive_objects[node]=instance;yield instance;deep=hasattr(instance,_T);state=self.construct_mapping(node,deep=deep);self.set_python_instance_state(instance,state)
 	def construct_python_object_apply(self,suffix,node,newobj=_B):
 		if isinstance(node,SequenceNode):args=self.construct_sequence(node,deep=_C);kwds={};state={};listitems=[];dictitems={}
 		else:value=self.construct_mapping(node,deep=_C);args=value.get('args',[]);kwds=value.get('kwds',{});state=value.get('state',{});listitems=value.get('listitems',[]);dictitems=value.get('dictitems',{})
@@ -443,7 +435,7 @@ Constructor.add_multi_constructor('tag:yaml.org,2002:python/object/new:',Constru
 class RoundTripConstructor(SafeConstructor):
 	def construct_scalar(self,node):
 		A='\x07'
-		if not isinstance(node,ScalarNode):raise ConstructorError(_A,_A,_g%node.id,node.start_mark)
+		if not isinstance(node,ScalarNode):raise ConstructorError(_A,_A,_d%node.id,node.start_mark)
 		if node.style=='|'and isinstance(node.value,text_type):
 			lss=LiteralScalarString(node.value,anchor=node.anchor)
 			if node.comment and node.comment[1]:lss.comment=node.comment[1][0]
@@ -469,8 +461,8 @@ class RoundTripConstructor(SafeConstructor):
 		except ValueError:underscore=_A
 		except IndexError:underscore=_A
 		value_s=value_su.replace(_D,'');sign=+1
-		if value_s[0]==_J:sign=-1
-		if value_s[0]in _M:value_s=value_s[1:]
+		if value_s[0]=='-':sign=-1
+		if value_s[0]in _L:value_s=value_s[1:]
 		if value_s==_F:return 0
 		elif value_s.startswith('0b'):
 			if self.resolver.processing_version>(1,1)and value_s[2]==_F:width=len(value_s[2:])
@@ -500,7 +492,6 @@ class RoundTripConstructor(SafeConstructor):
 		elif node.anchor:return ScalarInt(sign*int(value_s),width=_A,anchor=node.anchor)
 		else:return sign*int(value_s)
 	def construct_yaml_float(self,node):
-		A='E'
 		def leading_zeros(v):
 			lead0=0;idx=0
 			while idx<len(v)and v[idx]in'0.':
@@ -508,32 +499,32 @@ class RoundTripConstructor(SafeConstructor):
 				idx+=1
 			return lead0
 		m_sign=_B;value_so=to_str(self.construct_scalar(node));value_s=value_so.replace(_D,'').lower();sign=+1
-		if value_s[0]==_J:sign=-1
-		if value_s[0]in _M:m_sign=value_s[0];value_s=value_s[1:]
-		if value_s==_p:return sign*self.inf_value
-		if value_s==_q:return self.nan_value
+		if value_s[0]=='-':sign=-1
+		if value_s[0]in _L:m_sign=value_s[0];value_s=value_s[1:]
+		if value_s=='.inf':return sign*self.inf_value
+		if value_s=='.nan':return self.nan_value
 		if self.resolver.processing_version!=(1,2)and _G in value_s:
 			digits=[float(part)for part in value_s.split(_G)];digits.reverse();base=1;value=0.0
 			for digit in digits:value+=digit*base;base*=60
 			return sign*value
-		if _N in value_s:
-			try:mantissa,exponent=value_so.split(_N);exp=_N
-			except ValueError:mantissa,exponent=value_so.split(A);exp=A
+		if'e'in value_s:
+			try:mantissa,exponent=value_so.split('e');exp='e'
+			except ValueError:mantissa,exponent=value_so.split('E');exp='E'
 			if self.resolver.processing_version!=(1,2):
 				if _H not in mantissa:warnings.warn(MantissaNoDotYAML1_1Warning(node,value_so))
 			lead0=leading_zeros(mantissa);width=len(mantissa);prec=mantissa.find(_H)
 			if m_sign:width-=1
-			e_width=len(exponent);e_sign=exponent[0]in _M;return ScalarFloat(sign*float(value_s),width=width,prec=prec,m_sign=m_sign,m_lead0=lead0,exp=exp,e_width=e_width,e_sign=e_sign,anchor=node.anchor)
+			e_width=len(exponent);e_sign=exponent[0]in _L;return ScalarFloat(sign*float(value_s),width=width,prec=prec,m_sign=m_sign,m_lead0=lead0,exp=exp,e_width=e_width,e_sign=e_sign,anchor=node.anchor)
 		width=len(value_so);prec=value_so.index(_H);lead0=leading_zeros(value_so);return ScalarFloat(sign*float(value_s),width=width,prec=prec,m_sign=m_sign,m_lead0=lead0,anchor=node.anchor)
 	def construct_yaml_str(self,node):
 		value=self.construct_scalar(node)
 		if isinstance(value,ScalarString):return value
 		if PY3:return value
-		try:return value.encode(_S)
+		try:return value.encode(_Q)
 		except AttributeError:return value
 		except UnicodeEncodeError:return value
 	def construct_rt_sequence(self,node,seqtyp,deep=_B):
-		if not isinstance(node,SequenceNode):raise ConstructorError(_A,_A,_h%node.id,node.start_mark)
+		if not isinstance(node,SequenceNode):raise ConstructorError(_A,_A,_e%node.id,node.start_mark)
 		ret_val=[]
 		if node.comment:
 			seqtyp._yaml_add_comment(node.comment[:2])
@@ -553,25 +544,25 @@ class RoundTripConstructor(SafeConstructor):
 		merge_map_list=[];index=0
 		while index<len(node.value):
 			key_node,value_node=node.value[index]
-			if key_node.tag==_k:
+			if key_node.tag==_h:
 				if merge_map_list:
 					if self.allow_duplicate_keys:del node.value[index];index+=1;continue
-					args=[_E,node.start_mark,_Y.format(key_node.value),key_node.start_mark,_l,_m]
-					if self.allow_duplicate_keys is _A:warnings.warn(DuplicateKeyFutureWarning(*args))
-					else:raise DuplicateKeyError(*args)
+					args=[_E,node.start_mark,_W.format(key_node.value),key_node.start_mark,_i,_j]
+					if self.allow_duplicate_keys is _A:warnings.warn(DuplicateKeyFutureWarning(*(args)))
+					else:raise DuplicateKeyError(*(args))
 				del node.value[index]
 				if isinstance(value_node,MappingNode):merge_map_list.append((index,constructed(value_node)))
 				elif isinstance(value_node,SequenceNode):
 					for subnode in value_node.value:
-						if not isinstance(subnode,MappingNode):raise ConstructorError(_E,node.start_mark,_n%subnode.id,subnode.start_mark)
+						if not isinstance(subnode,MappingNode):raise ConstructorError(_E,node.start_mark,_k%subnode.id,subnode.start_mark)
 						merge_map_list.append((index,constructed(subnode)))
-				else:raise ConstructorError(_E,node.start_mark,_o%value_node.id,value_node.start_mark)
-			elif key_node.tag==_Z:key_node.tag=_R;index+=1
+				else:raise ConstructorError(_E,node.start_mark,_l%value_node.id,value_node.start_mark)
+			elif key_node.tag==_X:key_node.tag=_P;index+=1
 			else:index+=1
 		return merge_map_list
 	def _sentinel(self):0
 	def construct_mapping(self,node,maptyp,deep=_B):
-		if not isinstance(node,MappingNode):raise ConstructorError(_A,_A,_P%node.id,node.start_mark)
+		if not isinstance(node,MappingNode):raise ConstructorError(_A,_A,_N%node.id,node.start_mark)
 		merge_map=self.flatten_mapping(node)
 		if node.comment:
 			maptyp._yaml_add_comment(node.comment[:2])
@@ -595,8 +586,8 @@ class RoundTripConstructor(SafeConstructor):
 					key=key_m
 			if PY2:
 				try:hash(key)
-				except TypeError as exc:raise ConstructorError(_E,node.start_mark,_W%exc,key_node.start_mark)
-			elif not isinstance(key,Hashable):raise ConstructorError(_E,node.start_mark,_X,key_node.start_mark)
+				except TypeError as exc:raise ConstructorError(_E,node.start_mark,_U%exc,key_node.start_mark)
+			elif not isinstance(key,Hashable):raise ConstructorError(_E,node.start_mark,_V,key_node.start_mark)
 			value=self.construct_object(value_node,deep=deep)
 			if self.check_mapping_key(node,key_node,maptyp,key,value):
 				if key_node.comment and len(key_node.comment)>4 and key_node.comment[4]:
@@ -608,7 +599,7 @@ class RoundTripConstructor(SafeConstructor):
 				maptyp._yaml_set_kv_line_col(key,[key_node.start_mark.line,key_node.start_mark.column,value_node.start_mark.line,value_node.start_mark.column]);maptyp[key]=value;last_key,last_value=key,value
 		if merge_map:maptyp.add_yaml_merge(merge_map)
 	def construct_setting(self,node,typ,deep=_B):
-		if not isinstance(node,MappingNode):raise ConstructorError(_A,_A,_P%node.id,node.start_mark)
+		if not isinstance(node,MappingNode):raise ConstructorError(_A,_A,_N%node.id,node.start_mark)
 		if node.comment:
 			typ._yaml_add_comment(node.comment[:2])
 			if len(node.comment)>2:typ.yaml_end_comment_extend(node.comment[2],clear=_C)
@@ -621,8 +612,8 @@ class RoundTripConstructor(SafeConstructor):
 				if isinstance(key,list):key=tuple(key)
 			if PY2:
 				try:hash(key)
-				except TypeError as exc:raise ConstructorError(_E,node.start_mark,_W%exc,key_node.start_mark)
-			elif not isinstance(key,Hashable):raise ConstructorError(_E,node.start_mark,_X,key_node.start_mark)
+				except TypeError as exc:raise ConstructorError(_E,node.start_mark,_U%exc,key_node.start_mark)
+			elif not isinstance(key,Hashable):raise ConstructorError(_E,node.start_mark,_V,key_node.start_mark)
 			value=self.construct_object(value_node,deep=deep);self.check_set_key(node,key_node,typ,key)
 			if key_node.comment:typ._yaml_add_comment(key_node.comment,key=key)
 			if value_node.comment:typ._yaml_add_comment(value_node.comment,value=key)
@@ -638,7 +629,7 @@ class RoundTripConstructor(SafeConstructor):
 		elif node.flow_style is _B:data.fa.set_block_style()
 	def construct_yaml_object(self,node,cls):
 		data=cls.__new__(cls);yield data
-		if hasattr(data,_V):state=SafeConstructor.construct_mapping(self,node,deep=_C);data.__setstate__(state)
+		if hasattr(data,_T):state=SafeConstructor.construct_mapping(self,node,deep=_C);data.__setstate__(state)
 		else:state=SafeConstructor.construct_mapping(self,node);data.__dict__.update(state)
 	def construct_yaml_omap(self,node):
 		omap=CommentedOrderedMap();omap._yaml_set_line_col(node.start_mark.line,node.start_mark.column)
@@ -648,10 +639,10 @@ class RoundTripConstructor(SafeConstructor):
 		if node.comment:
 			omap._yaml_add_comment(node.comment[:2])
 			if len(node.comment)>2:omap.yaml_end_comment_extend(node.comment[2],clear=_C)
-		if not isinstance(node,SequenceNode):raise ConstructorError(_L,node.start_mark,_b%node.id,node.start_mark)
+		if not isinstance(node,SequenceNode):raise ConstructorError(_K,node.start_mark,_Z%node.id,node.start_mark)
 		for subnode in node.value:
-			if not isinstance(subnode,MappingNode):raise ConstructorError(_L,node.start_mark,_c%subnode.id,subnode.start_mark)
-			if len(subnode.value)!=1:raise ConstructorError(_L,node.start_mark,_d%len(subnode.value),subnode.start_mark)
+			if not isinstance(subnode,MappingNode):raise ConstructorError(_K,node.start_mark,_a%subnode.id,subnode.start_mark)
+			if len(subnode.value)!=1:raise ConstructorError(_K,node.start_mark,_b%len(subnode.value),subnode.start_mark)
 			key_node,value_node=subnode.value[0];key=self.construct_object(key_node);assert key not in omap;value=self.construct_object(value_node)
 			if key_node.comment:omap._yaml_add_comment(key_node.comment,key=key)
 			if subnode.comment:omap._yaml_add_comment(subnode.comment,key=key)
@@ -679,30 +670,30 @@ class RoundTripConstructor(SafeConstructor):
 				if node.anchor:data3.yaml_set_anchor(node.anchor)
 				data3.extend(self.construct_sequence(node));return
 		except:pass
-		raise ConstructorError(_A,_A,_z%utf8(node.tag),node.start_mark)
+		raise ConstructorError(_A,_A,_r%utf8(node.tag),node.start_mark)
 	def construct_yaml_timestamp(self,node,values=_A):
 		B='t';A='tz'
 		try:match=self.timestamp_regexp.match(node.value)
 		except TypeError:match=_A
-		if match is _A:raise ConstructorError(_A,_A,_t.format(node.value),node.start_mark)
+		if match is _A:raise ConstructorError(_A,_A,_o.format(node.value),node.start_mark)
 		values=match.groupdict()
-		if not values[_T]:return SafeConstructor.construct_yaml_timestamp(self,node,values)
-		for part in [B,_K,_U,_O]:
+		if not values[_R]:return SafeConstructor.construct_yaml_timestamp(self,node,values)
+		for part in [B,_J,_S,_M]:
 			if values[part]:break
 		else:return SafeConstructor.construct_yaml_timestamp(self,node,values)
-		year=int(values[_u]);month=int(values[_v]);day=int(values[_w]);hour=int(values[_T]);minute=int(values[_x]);second=int(values[_y]);fraction=0
+		year=int(values['year']);month=int(values['month']);day=int(values['day']);hour=int(values[_R]);minute=int(values[_p]);second=int(values[_q]);fraction=0
 		if values[_I]:
 			fraction_s=values[_I][:6]
 			while len(fraction_s)<6:fraction_s+=_F
 			fraction=int(fraction_s)
 			if len(values[_I])>6 and int(values[_I][6])>4:fraction+=1
 		delta=_A
-		if values[_K]:
-			tz_hour=int(values[_U]);minutes=values[_O];tz_minute=int(minutes)if minutes else 0;delta=datetime.timedelta(hours=tz_hour,minutes=tz_minute)
-			if values[_K]==_J:delta=-delta
+		if values[_J]:
+			tz_hour=int(values[_S]);minutes=values[_M];tz_minute=int(minutes)if minutes else 0;delta=datetime.timedelta(hours=tz_hour,minutes=tz_minute)
+			if values[_J]=='-':delta=-delta
 		if delta:
-			dt=datetime.datetime(year,month,day,hour,minute);dt-=delta;data=TimeStamp(dt.year,dt.month,dt.day,dt.hour,dt.minute,second,fraction);data._yaml['delta']=delta;tz=values[_K]+values[_U]
-			if values[_O]:tz+=_G+values[_O]
+			dt=datetime.datetime(year,month,day,hour,minute);dt-=delta;data=TimeStamp(dt.year,dt.month,dt.day,dt.hour,dt.minute,second,fraction);data._yaml['delta']=delta;tz=values[_J]+values[_S]
+			if values[_M]:tz+=_G+values[_M]
 			data._yaml[A]=tz
 		else:
 			data=TimeStamp(year,month,day,hour,minute,second,fraction)
@@ -713,16 +704,16 @@ class RoundTripConstructor(SafeConstructor):
 		b=SafeConstructor.construct_yaml_bool(self,node)
 		if node.anchor:return ScalarBoolean(b,anchor=node.anchor)
 		return b
-RoundTripConstructor.add_constructor(_A0,RoundTripConstructor.construct_yaml_null)
-RoundTripConstructor.add_constructor(_A1,RoundTripConstructor.construct_yaml_bool)
-RoundTripConstructor.add_constructor(_A2,RoundTripConstructor.construct_yaml_int)
-RoundTripConstructor.add_constructor(_A3,RoundTripConstructor.construct_yaml_float)
-RoundTripConstructor.add_constructor(_A4,RoundTripConstructor.construct_yaml_binary)
-RoundTripConstructor.add_constructor(_A5,RoundTripConstructor.construct_yaml_timestamp)
-RoundTripConstructor.add_constructor(_A6,RoundTripConstructor.construct_yaml_omap)
-RoundTripConstructor.add_constructor(_A7,RoundTripConstructor.construct_yaml_pairs)
-RoundTripConstructor.add_constructor(_A8,RoundTripConstructor.construct_yaml_set)
-RoundTripConstructor.add_constructor(_R,RoundTripConstructor.construct_yaml_str)
-RoundTripConstructor.add_constructor(_A9,RoundTripConstructor.construct_yaml_seq)
-RoundTripConstructor.add_constructor(_AA,RoundTripConstructor.construct_yaml_map)
+RoundTripConstructor.add_constructor(_s,RoundTripConstructor.construct_yaml_null)
+RoundTripConstructor.add_constructor(_t,RoundTripConstructor.construct_yaml_bool)
+RoundTripConstructor.add_constructor(_u,RoundTripConstructor.construct_yaml_int)
+RoundTripConstructor.add_constructor(_v,RoundTripConstructor.construct_yaml_float)
+RoundTripConstructor.add_constructor(_w,RoundTripConstructor.construct_yaml_binary)
+RoundTripConstructor.add_constructor(_x,RoundTripConstructor.construct_yaml_timestamp)
+RoundTripConstructor.add_constructor(_y,RoundTripConstructor.construct_yaml_omap)
+RoundTripConstructor.add_constructor(_z,RoundTripConstructor.construct_yaml_pairs)
+RoundTripConstructor.add_constructor(_A0,RoundTripConstructor.construct_yaml_set)
+RoundTripConstructor.add_constructor(_P,RoundTripConstructor.construct_yaml_str)
+RoundTripConstructor.add_constructor(_A1,RoundTripConstructor.construct_yaml_seq)
+RoundTripConstructor.add_constructor(_A2,RoundTripConstructor.construct_yaml_map)
 RoundTripConstructor.add_constructor(_A,RoundTripConstructor.construct_undefined)
\ No newline at end of file
diff --git a/dynaconf/vendor/ruamel/yaml/emitter.py b/dynaconf/vendor/ruamel/yaml/emitter.py
index 036530a..c411fcf 100644
--- a/dynaconf/vendor/ruamel/yaml/emitter.py
+++ b/dynaconf/vendor/ruamel/yaml/emitter.py
@@ -1,21 +1,14 @@
 from __future__ import absolute_import,print_function
-_a='\x07'
-_Z='\ufeff'
-_Y='\ue000'
-_X='\ud7ff'
-_W='\x85'
-_V='%%%02X'
-_U='version'
-_T="-;/?:@&=+$,_.~*'()[]"
-_S='---'
-_R=' \n\x85\u2028\u2029'
-_Q='\xa0'
-_P='a'
-_O='0'
-_N=','
-_M='...'
-_L='\\'
-_K='['
+_T='\ufeff'
+_S='\ue000'
+_R='\ud7ff'
+_Q='%%%02X'
+_P='version'
+_O="-;/?:@&=+$,_.~*'()[]"
+_N=' \n\x85\u2028\u2029'
+_M='\xa0'
+_L='...'
+_K='\\'
 _J="'"
 _I='?'
 _H='"'
@@ -113,7 +106,7 @@ class Emitter:
 	def expect_first_document_start(self):return self.expect_document_start(first=_A)
 	def expect_document_start(self,first=_C):
 		if isinstance(self.event,DocumentStartEvent):
-			if(self.event.version or self.event.tags)and self.open_ended:self.write_indicator(_M,_A);self.write_indent()
+			if(self.event.version or self.event.tags)and self.open_ended:self.write_indicator(_L,_A);self.write_indent()
 			if self.event.version:version_text=self.prepare_version(self.event.version);self.write_version_directive(version_text)
 			self.tag_prefixes=self.DEFAULT_TAG_PREFIXES.copy()
 			if self.event.tags:
@@ -121,17 +114,17 @@ class Emitter:
 				for handle in handles:prefix=self.event.tags[handle];self.tag_prefixes[prefix]=handle;handle_text=self.prepare_tag_handle(handle);prefix_text=self.prepare_tag_prefix(prefix);self.write_tag_directive(handle_text,prefix_text)
 			implicit=first and not self.event.explicit and not self.canonical and not self.event.version and not self.event.tags and not self.check_empty_document()
 			if not implicit:
-				self.write_indent();self.write_indicator(_S,_A)
+				self.write_indent();self.write_indicator('---',_A)
 				if self.canonical:self.write_indent()
 			self.state=self.expect_document_root
 		elif isinstance(self.event,StreamEndEvent):
-			if self.open_ended:self.write_indicator(_M,_A);self.write_indent()
+			if self.open_ended:self.write_indicator(_L,_A);self.write_indent()
 			self.write_stream_end();self.state=self.expect_nothing
 		else:raise EmitterError('expected DocumentStartEvent, but got %s'%(self.event,))
 	def expect_document_end(self):
 		if isinstance(self.event,DocumentEndEvent):
 			self.write_indent()
-			if self.event.explicit:self.write_indicator(_M,_A);self.write_indent()
+			if self.event.explicit:self.write_indicator(_L,_A);self.write_indent()
 			self.flush_stream();self.state=self.expect_document_start
 		else:raise EmitterError('expected DocumentEndEvent, but got %s'%(self.event,))
 	def expect_document_root(self):self.states.append(self.expect_document_end);self.expect_node(root=_A)
@@ -161,10 +154,10 @@ class Emitter:
 		if self.event.anchor is _B:raise EmitterError('anchor is not specified for alias')
 		self.process_anchor('*');self.state=self.states.pop()
 	def expect_scalar(self):self.increase_indent(flow=_A);self.process_scalar();self.indent=self.indents.pop();self.state=self.states.pop()
-	def expect_flow_sequence(self):ind=self.indents.seq_flow_align(self.best_sequence_indent,self.column);self.write_indicator(_D*ind+_K,_A,whitespace=_A);self.increase_indent(flow=_A,sequence=_A);self.flow_context.append(_K);self.state=self.expect_first_flow_sequence_item
+	def expect_flow_sequence(self):ind=self.indents.seq_flow_align(self.best_sequence_indent,self.column);self.write_indicator(_D*ind+'[',_A,whitespace=_A);self.increase_indent(flow=_A,sequence=_A);self.flow_context.append('[');self.state=self.expect_first_flow_sequence_item
 	def expect_first_flow_sequence_item(self):
 		if isinstance(self.event,SequenceEndEvent):
-			self.indent=self.indents.pop();popped=self.flow_context.pop();assert popped==_K;self.write_indicator(']',_C)
+			self.indent=self.indents.pop();popped=self.flow_context.pop();assert popped=='[';self.write_indicator(']',_C)
 			if self.event.comment and self.event.comment[0]:self.write_post_comment(self.event)
 			elif self.flow_level==0:self.write_line_break()
 			self.state=self.states.pop()
@@ -173,19 +166,19 @@ class Emitter:
 			self.states.append(self.expect_flow_sequence_item);self.expect_node(sequence=_A)
 	def expect_flow_sequence_item(self):
 		if isinstance(self.event,SequenceEndEvent):
-			self.indent=self.indents.pop();popped=self.flow_context.pop();assert popped==_K
-			if self.canonical:self.write_indicator(_N,_C);self.write_indent()
+			self.indent=self.indents.pop();popped=self.flow_context.pop();assert popped=='['
+			if self.canonical:self.write_indicator(',',_C);self.write_indent()
 			self.write_indicator(']',_C)
 			if self.event.comment and self.event.comment[0]:self.write_post_comment(self.event)
 			else:self.no_newline=_C
 			self.state=self.states.pop()
 		else:
-			self.write_indicator(_N,_C)
+			self.write_indicator(',',_C)
 			if self.canonical or self.column>self.best_width:self.write_indent()
 			self.states.append(self.expect_flow_sequence_item);self.expect_node(sequence=_A)
 	def expect_flow_mapping(self,single=_C):
 		ind=self.indents.seq_flow_align(self.best_sequence_indent,self.column);map_init='{'
-		if single and self.flow_level and self.flow_context[-1]==_K and not self.canonical and not self.brace_single_entry_mapping_in_flow_sequence:map_init=''
+		if single and self.flow_level and self.flow_context[-1]=='['and not self.canonical and not self.brace_single_entry_mapping_in_flow_sequence:map_init=''
 		self.write_indicator(_D*ind+map_init,_A,whitespace=_A);self.flow_context.append(map_init);self.increase_indent(flow=_A,sequence=_C);self.state=self.expect_first_flow_mapping_key
 	def expect_first_flow_mapping_key(self):
 		if isinstance(self.event,MappingEndEvent):
@@ -200,13 +193,13 @@ class Emitter:
 	def expect_flow_mapping_key(self):
 		if isinstance(self.event,MappingEndEvent):
 			self.indent=self.indents.pop();popped=self.flow_context.pop();assert popped in['{','']
-			if self.canonical:self.write_indicator(_N,_C);self.write_indent()
+			if self.canonical:self.write_indicator(',',_C);self.write_indent()
 			if popped!='':self.write_indicator('}',_C)
 			if self.event.comment and self.event.comment[0]:self.write_post_comment(self.event)
 			else:self.no_newline=_C
 			self.state=self.states.pop()
 		else:
-			self.write_indicator(_N,_C)
+			self.write_indicator(',',_C)
 			if self.canonical or self.column>self.best_width:self.write_indent()
 			if not self.canonical and self.check_simple_key():self.states.append(self.expect_flow_mapping_simple_value);self.expect_node(mapping=_A,simple_key=_A)
 			else:self.write_indicator(_I,_A);self.states.append(self.expect_flow_mapping_value);self.expect_node(mapping=_A)
@@ -324,23 +317,23 @@ class Emitter:
 		if not handle:raise EmitterError('tag handle must not be empty')
 		if handle[0]!=_G or handle[-1]!=_G:raise EmitterError("tag handle must start and end with '!': %r"%utf8(handle))
 		for ch in handle[1:-1]:
-			if not(_O<=ch<='9'or'A'<=ch<='Z'or _P<=ch<='z'or ch in'-_'):raise EmitterError('invalid character %r in the tag handle: %r'%(utf8(ch),utf8(handle)))
+			if not('0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z'or ch in'-_'):raise EmitterError('invalid character %r in the tag handle: %r'%(utf8(ch),utf8(handle)))
 		return handle
 	def prepare_tag_prefix(self,prefix):
 		if not prefix:raise EmitterError('tag prefix must not be empty')
 		chunks=[];start=end=0
 		if prefix[0]==_G:end=1
-		ch_set=_T
+		ch_set=_O
 		if self.dumper:
-			version=getattr(self.dumper,_U,(1,2))
+			version=getattr(self.dumper,_P,(1,2))
 			if version is _B or version>=(1,2):ch_set+='#'
 		while end<len(prefix):
 			ch=prefix[end]
-			if _O<=ch<='9'or'A'<=ch<='Z'or _P<=ch<='z'or ch in ch_set:end+=1
+			if'0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z'or ch in ch_set:end+=1
 			else:
 				if start<end:chunks.append(prefix[start:end])
 				start=end=end+1;data=utf8(ch)
-				for ch in data:chunks.append(_V%ord(ch))
+				for ch in data:chunks.append(_Q%ord(ch))
 		if start<end:chunks.append(prefix[start:end])
 		return ''.join(chunks)
 	def prepare_tag(self,tag):
@@ -349,17 +342,17 @@ class Emitter:
 		handle=_B;suffix=tag;prefixes=sorted(self.tag_prefixes.keys())
 		for prefix in prefixes:
 			if tag.startswith(prefix)and(prefix==_G or len(prefix)<len(tag)):handle=self.tag_prefixes[prefix];suffix=tag[len(prefix):]
-		chunks=[];start=end=0;ch_set=_T
+		chunks=[];start=end=0;ch_set=_O
 		if self.dumper:
-			version=getattr(self.dumper,_U,(1,2))
+			version=getattr(self.dumper,_P,(1,2))
 			if version is _B or version>=(1,2):ch_set+='#'
 		while end<len(suffix):
 			ch=suffix[end]
-			if _O<=ch<='9'or'A'<=ch<='Z'or _P<=ch<='z'or ch in ch_set or ch==_G and handle!=_G:end+=1
+			if'0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z'or ch in ch_set or ch==_G and handle!=_G:end+=1
 			else:
 				if start<end:chunks.append(suffix[start:end])
 				start=end=end+1;data=utf8(ch)
-				for ch in data:chunks.append(_V%ord(ch))
+				for ch in data:chunks.append(_Q%ord(ch))
 		if start<end:chunks.append(suffix[start:end])
 		suffix_text=''.join(chunks)
 		if handle:return'%s%s'%(handle,suffix_text)
@@ -373,7 +366,7 @@ class Emitter:
 		A='\x00 \t\r\n\x85\u2028\u2029'
 		if not scalar:return ScalarAnalysis(scalar=scalar,empty=_A,multiline=_C,allow_flow_plain=_C,allow_block_plain=_A,allow_single_quoted=_A,allow_double_quoted=_A,allow_block=_C)
 		block_indicators=_C;flow_indicators=_C;line_breaks=_C;special_characters=_C;leading_space=_C;leading_break=_C;trailing_space=_C;trailing_break=_C;break_space=_C;space_break=_C
-		if scalar.startswith(_S)or scalar.startswith(_M):block_indicators=_A;flow_indicators=_A
+		if scalar.startswith('---')or scalar.startswith(_L):block_indicators=_A;flow_indicators=_A
 		preceeded_by_whitespace=_A;followed_by_whitespace=len(scalar)==1 or scalar[1]in A;previous_space=_C;previous_break=_C;index=0
 		while index<len(scalar):
 			ch=scalar[index]
@@ -392,7 +385,7 @@ class Emitter:
 				if ch=='#'and preceeded_by_whitespace:flow_indicators=_A;block_indicators=_A
 			if ch in _F:line_breaks=_A
 			if not(ch==_E or _D<=ch<='~'):
-				if(ch==_W or _Q<=ch<=_X or _Y<=ch<='�'or self.unicode_supplementary and'𐀀'<=ch<='\U0010ffff')and ch!=_Z:
+				if(ch=='\x85'or _M<=ch<=_R or _S<=ch<='�'or self.unicode_supplementary and'𐀀'<=ch<='\U0010ffff')and ch!=_T:
 					if not self.allow_unicode:special_characters=_A
 				else:special_characters=_A
 			if ch==_D:
@@ -422,7 +415,7 @@ class Emitter:
 	def flush_stream(self):
 		if hasattr(self.stream,'flush'):self.stream.flush()
 	def write_stream_start(self):
-		if self.encoding and self.encoding.startswith('utf-16'):self.stream.write(_Z.encode(self.encoding))
+		if self.encoding and self.encoding.startswith('utf-16'):self.stream.write(_T.encode(self.encoding))
 	def write_stream_end(self):self.flush_stream()
 	def write_indicator(self,indicator,need_whitespace,whitespace=_C,indention=_C):
 		if self.whitespace or not need_whitespace:data=indicator
@@ -476,7 +469,7 @@ class Emitter:
 						if br==_E:self.write_line_break()
 						else:self.write_line_break(br)
 					self.write_indent();start=end
-			elif ch is _B or ch in _R or ch==_J:
+			elif ch is _B or ch in _N or ch==_J:
 				if start<end:
 					data=text[start:end];self.column+=len(data)
 					if bool(self.encoding):data=data.encode(self.encoding)
@@ -488,7 +481,7 @@ class Emitter:
 			if ch is not _B:spaces=ch==_D;breaks=ch in _F
 			end+=1
 		self.write_indicator(_J,_C)
-	ESCAPE_REPLACEMENTS={'\x00':_O,_a:_P,'\x08':'b','\t':'t',_E:'n','\x0b':'v','\x0c':'f','\r':'r','\x1b':'e',_H:_H,_L:_L,_W:'N',_Q:'_','\u2028':'L','\u2029':'P'}
+	ESCAPE_REPLACEMENTS={'\x00':'0','\x07':'a','\x08':'b','\t':'t',_E:'n','\x0b':'v','\x0c':'f','\r':'r','\x1b':'e',_H:_H,_K:_K,'\x85':'N',_M:'_','\u2028':'L','\u2029':'P'}
 	def write_double_quoted(self,text,split=_A):
 		if self.root_context:
 			if self.requested_indent is not _B:
@@ -498,13 +491,13 @@ class Emitter:
 		while end<=len(text):
 			ch=_B
 			if end<len(text):ch=text[end]
-			if ch is _B or ch in'"\\\x85\u2028\u2029\ufeff'or not(_D<=ch<='~'or self.allow_unicode and(_Q<=ch<=_X or _Y<=ch<='�')):
+			if ch is _B or ch in'"\\\x85\u2028\u2029\ufeff'or not(_D<=ch<='~'or self.allow_unicode and(_M<=ch<=_R or _S<=ch<='�')):
 				if start<end:
 					data=text[start:end];self.column+=len(data)
 					if bool(self.encoding):data=data.encode(self.encoding)
 					self.stream.write(data);start=end
 				if ch is not _B:
-					if ch in self.ESCAPE_REPLACEMENTS:data=_L+self.ESCAPE_REPLACEMENTS[ch]
+					if ch in self.ESCAPE_REPLACEMENTS:data=_K+self.ESCAPE_REPLACEMENTS[ch]
 					elif ch<='ÿ':data='\\x%02X'%ord(ch)
 					elif ch<='\uffff':data='\\u%04X'%ord(ch)
 					else:data='\\U%08X'%ord(ch)
@@ -512,13 +505,13 @@ class Emitter:
 					if bool(self.encoding):data=data.encode(self.encoding)
 					self.stream.write(data);start=end+1
 			if 0<end<len(text)-1 and(ch==_D or start>=end)and self.column+(end-start)>self.best_width and split:
-				data=text[start:end]+_L
+				data=text[start:end]+_K
 				if start<end:start=end
 				self.column+=len(data)
 				if bool(self.encoding):data=data.encode(self.encoding)
 				self.stream.write(data);self.write_indent();self.whitespace=_C;self.indention=_C
 				if text[start]==_D:
-					data=_L;self.column+=len(data)
+					data=_K;self.column+=len(data)
 					if bool(self.encoding):data=data.encode(self.encoding)
 					self.stream.write(data)
 			end+=1
@@ -526,7 +519,7 @@ class Emitter:
 	def determine_block_hints(self,text):
 		indent=0;indicator='';hints=''
 		if text:
-			if text[0]in _R:indent=self.best_sequence_indent;hints+=text_type(indent)
+			if text[0]in _N:indent=self.best_sequence_indent;hints+=text_type(indent)
 			elif self.root_context:
 				for end in ['\n---','\n...']:
 					pos=0
@@ -570,7 +563,7 @@ class Emitter:
 				data=text[start:end];self.column+=len(data)
 				if bool(self.encoding):data=data.encode(self.encoding)
 				self.stream.write(data)
-				if ch==_a:
+				if ch=='\x07':
 					if end<len(text)-1 and not text[end+2].isspace():self.write_line_break();self.write_indent();end+=2
 					else:raise EmitterError('unexcpected fold indicator \\a before space')
 				if ch is _B:self.write_line_break()
@@ -635,7 +628,7 @@ class Emitter:
 						if br==_E:self.write_line_break()
 						else:self.write_line_break(br)
 					self.write_indent();self.whitespace=_C;self.indention=_C;start=end
-			elif ch is _B or ch in _R:
+			elif ch is _B or ch in _N:
 				data=text[start:end];self.column+=len(data)
 				if self.encoding:data=data.encode(self.encoding)
 				try:self.stream.write(data)
diff --git a/dynaconf/vendor/ruamel/yaml/error.py b/dynaconf/vendor/ruamel/yaml/error.py
index 52652cc..cbcb115 100644
--- a/dynaconf/vendor/ruamel/yaml/error.py
+++ b/dynaconf/vendor/ruamel/yaml/error.py
@@ -1,9 +1,5 @@
 from __future__ import absolute_import
-_I='once'
-_H='  in "%s", line %d, column %d'
-_G='line'
-_F='index'
-_E='name'
+_E='  in "%s", line %d, column %d'
 _D='column'
 _C=False
 _B='\n'
@@ -13,9 +9,9 @@ from .compat import utf8
 if _C:from typing import Any,Dict,Optional,List,Text
 __all__=['FileMark','StringMark','CommentMark','YAMLError','MarkedYAMLError','ReusedAnchorWarning','UnsafeLoaderWarning','MarkedYAMLWarning','MarkedYAMLFutureWarning']
 class StreamMark:
-	__slots__=_E,_F,_G,_D
+	__slots__='name','index','line',_D
 	def __init__(A,name,index,line,column):A.name=name;A.index=index;A.line=line;A.column=column
-	def __str__(A):B=_H%(A.name,A.line+1,A.column+1);return B
+	def __str__(A):B=_E%(A.name,A.line+1,A.column+1);return B
 	def __eq__(A,other):
 		B=other
 		if A.line!=B.line or A.column!=B.column:return _C
@@ -24,22 +20,22 @@ class StreamMark:
 	def __ne__(A,other):return not A.__eq__(other)
 class FileMark(StreamMark):__slots__=()
 class StringMark(StreamMark):
-	__slots__=_E,_F,_G,_D,'buffer','pointer'
+	__slots__='name','index','line',_D,'buffer','pointer'
 	def __init__(A,name,index,line,column,buffer,pointer):StreamMark.__init__(A,name,index,line,column);A.buffer=buffer;A.pointer=pointer
 	def get_snippet(A,indent=4,max_length=75):
-		L=' ';K=' ... ';J='\x00\r\n\x85\u2028\u2029';F=max_length;E=indent
+		J=' ... ';I='\x00\r\n\x85\u2028\u2029';F=max_length;E=indent
 		if A.buffer is _A:return _A
 		D='';B=A.pointer
-		while B>0 and A.buffer[B-1]not in J:
+		while B>0 and A.buffer[B-1]not in I:
 			B-=1
-			if A.pointer-B>F/2-1:D=K;B+=5;break
+			if A.pointer-B>F/2-1:D=J;B+=5;break
 		G='';C=A.pointer
-		while C<len(A.buffer)and A.buffer[C]not in J:
+		while C<len(A.buffer)and A.buffer[C]not in I:
 			C+=1
-			if C-A.pointer>F/2-1:G=K;C-=5;break
-		I=utf8(A.buffer[B:C]);H='^';H='^ (line: {})'.format(A.line+1);return L*E+D+I+G+_B+L*(E+A.pointer-B+len(D))+H
+			if C-A.pointer>F/2-1:G=J;C-=5;break
+		K=utf8(A.buffer[B:C]);H='^';H='^ (line: {})'.format(A.line+1);return' '*E+D+K+G+_B+' '*(E+A.pointer-B+len(D))+H
 	def __str__(A):
-		B=A.get_snippet();C=_H%(A.name,A.line+1,A.column+1)
+		B=A.get_snippet();C=_E%(A.name,A.line+1,A.column+1)
 		if B is not _A:C+=':\n'+B
 		return C
 class CommentMark:
@@ -71,11 +67,11 @@ class MarkedYAMLWarning(YAMLWarning):
 		return _B.join(B)
 class ReusedAnchorWarning(YAMLWarning):0
 class UnsafeLoaderWarning(YAMLWarning):text="\nThe default 'Loader' for 'load(stream)' without further arguments can be unsafe.\nUse 'load(stream, Loader=ruamel.yaml.Loader)' explicitly if that is OK.\nAlternatively include the following in your code:\n\n  import warnings\n  warnings.simplefilter('ignore', ruamel.yaml.error.UnsafeLoaderWarning)\n\nIn most other cases you should consider using 'safe_load(stream)'"
-warnings.simplefilter(_I,UnsafeLoaderWarning)
+warnings.simplefilter('once',UnsafeLoaderWarning)
 class MantissaNoDotYAML1_1Warning(YAMLWarning):
 	def __init__(A,node,flt_str):A.node=node;A.flt=flt_str
 	def __str__(A):B=A.node.start_mark.line;C=A.node.start_mark.column;return '\nIn YAML 1.1 floating point values should have a dot (\'.\') in their mantissa.\nSee the Floating-Point Language-Independent Type for YAML™ Version 1.1 specification\n( http://yaml.org/type/float.html ). This dot is not required for JSON nor for YAML 1.2\n\nCorrect your float: "{}" on line: {}, column: {}\n\nor alternatively include the following in your code:\n\n  import warnings\n  warnings.simplefilter(\'ignore\', ruamel.yaml.error.MantissaNoDotYAML1_1Warning)\n\n'.format(A.flt,B,C)
-warnings.simplefilter(_I,MantissaNoDotYAML1_1Warning)
+warnings.simplefilter('once',MantissaNoDotYAML1_1Warning)
 class YAMLFutureWarning(Warning):0
 class MarkedYAMLFutureWarning(YAMLFutureWarning):
 	def __init__(A,context=_A,context_mark=_A,problem=_A,problem_mark=_A,note=_A,warn=_A):A.context=context;A.context_mark=context_mark;A.problem=problem;A.problem_mark=problem_mark;A.note=note;A.warn=warn
diff --git a/dynaconf/vendor/ruamel/yaml/events.py b/dynaconf/vendor/ruamel/yaml/events.py
index 8c1356e..545eae2 100644
--- a/dynaconf/vendor/ruamel/yaml/events.py
+++ b/dynaconf/vendor/ruamel/yaml/events.py
@@ -1,7 +1,5 @@
-_H='explicit'
-_G='style'
-_F='flow_style'
-_E='value'
+_F='explicit'
+_E='flow_style'
 _D='anchor'
 _C='implicit'
 _B='tag'
@@ -15,14 +13,14 @@ class Event:
 		if B is CommentCheck:B=_A
 		A.comment=B
 	def __repr__(A):
-		C=[B for B in[_D,_B,_C,_E,_F,_G]if hasattr(A,B)];B=', '.join(['%s=%r'%(B,getattr(A,B))for B in C])
+		C=[B for B in[_D,_B,_C,'value',_E,'style']if hasattr(A,B)];B=', '.join(['%s=%r'%(B,getattr(A,B))for B in C])
 		if A.comment not in[_A,CommentCheck]:B+=', comment={!r}'.format(A.comment)
 		return'%s(%s)'%(A.__class__.__name__,B)
 class NodeEvent(Event):
 	__slots__=_D,
 	def __init__(A,anchor,start_mark=_A,end_mark=_A,comment=_A):Event.__init__(A,start_mark,end_mark,comment);A.anchor=anchor
 class CollectionStartEvent(NodeEvent):
-	__slots__=_B,_C,_F,'nr_items'
+	__slots__=_B,_C,_E,'nr_items'
 	def __init__(A,anchor,tag,implicit,start_mark=_A,end_mark=_A,flow_style=_A,comment=_A,nr_items=_A):NodeEvent.__init__(A,anchor,start_mark,end_mark,comment);A.tag=tag;A.implicit=implicit;A.flow_style=flow_style;A.nr_items=nr_items
 class CollectionEndEvent(Event):__slots__=()
 class StreamStartEvent(Event):
@@ -30,14 +28,14 @@ class StreamStartEvent(Event):
 	def __init__(A,start_mark=_A,end_mark=_A,encoding=_A,comment=_A):Event.__init__(A,start_mark,end_mark,comment);A.encoding=encoding
 class StreamEndEvent(Event):__slots__=()
 class DocumentStartEvent(Event):
-	__slots__=_H,'version','tags'
+	__slots__=_F,'version','tags'
 	def __init__(A,start_mark=_A,end_mark=_A,explicit=_A,version=_A,tags=_A,comment=_A):Event.__init__(A,start_mark,end_mark,comment);A.explicit=explicit;A.version=version;A.tags=tags
 class DocumentEndEvent(Event):
-	__slots__=_H,
+	__slots__=_F,
 	def __init__(A,start_mark=_A,end_mark=_A,explicit=_A,comment=_A):Event.__init__(A,start_mark,end_mark,comment);A.explicit=explicit
 class AliasEvent(NodeEvent):__slots__=()
 class ScalarEvent(NodeEvent):
-	__slots__=_B,_C,_E,_G
+	__slots__=_B,_C,'value','style'
 	def __init__(A,anchor,tag,implicit,value,start_mark=_A,end_mark=_A,style=_A,comment=_A):NodeEvent.__init__(A,anchor,start_mark,end_mark,comment);A.tag=tag;A.implicit=implicit;A.value=value;A.style=style
 class SequenceStartEvent(CollectionStartEvent):__slots__=()
 class SequenceEndEvent(CollectionEndEvent):__slots__=()
diff --git a/dynaconf/vendor/ruamel/yaml/main.py b/dynaconf/vendor/ruamel/yaml/main.py
index acd2e93..bab6902 100644
--- a/dynaconf/vendor/ruamel/yaml/main.py
+++ b/dynaconf/vendor/ruamel/yaml/main.py
@@ -1,13 +1,8 @@
 from __future__ import absolute_import,unicode_literals,print_function
-_Q='_emitter'
-_P='_serializer'
-_O='write'
-_N='{}.dump(_all) takes two positional argument but at least three were given ({!r})'
-_M='read'
-_L='_stream'
-_K='typ'
-_J='utf-8'
-_I='base'
+_L='_emitter'
+_K='_serializer'
+_J='{}.dump(_all) takes two positional argument but at least three were given ({!r})'
+_I='_stream'
 _H='{}.__init__() takes no positional argument but at least one was given ({!r})'
 _G='yaml_tag'
 _F='open'
@@ -45,13 +40,13 @@ class YAML:
 		self.Resolver=ruamel.yaml.resolver.VersionedResolver;self.allow_unicode=_C;self.Reader=_A;self.Representer=_A;self.Constructor=_A;self.Scanner=_A;self.Serializer=_A;self.default_flow_style=_A;typ_found=1;setup_rt=_B
 		if _E in self.typ:setup_rt=_C
 		elif'safe'in self.typ:self.Emitter=ruamel.yaml.emitter.Emitter if pure or CEmitter is _A else CEmitter;self.Representer=ruamel.yaml.representer.SafeRepresenter;self.Parser=ruamel.yaml.parser.Parser if pure or CParser is _A else CParser;self.Composer=ruamel.yaml.composer.Composer;self.Constructor=ruamel.yaml.constructor.SafeConstructor
-		elif _I in self.typ:self.Emitter=ruamel.yaml.emitter.Emitter;self.Representer=ruamel.yaml.representer.BaseRepresenter;self.Parser=ruamel.yaml.parser.Parser if pure or CParser is _A else CParser;self.Composer=ruamel.yaml.composer.Composer;self.Constructor=ruamel.yaml.constructor.BaseConstructor
+		elif'base'in self.typ:self.Emitter=ruamel.yaml.emitter.Emitter;self.Representer=ruamel.yaml.representer.BaseRepresenter;self.Parser=ruamel.yaml.parser.Parser if pure or CParser is _A else CParser;self.Composer=ruamel.yaml.composer.Composer;self.Constructor=ruamel.yaml.constructor.BaseConstructor
 		elif'unsafe'in self.typ:self.Emitter=ruamel.yaml.emitter.Emitter if pure or CEmitter is _A else CEmitter;self.Representer=ruamel.yaml.representer.Representer;self.Parser=ruamel.yaml.parser.Parser if pure or CParser is _A else CParser;self.Composer=ruamel.yaml.composer.Composer;self.Constructor=ruamel.yaml.constructor.Constructor
 		else:setup_rt=_C;typ_found=0
 		if setup_rt:self.default_flow_style=_B;self.Emitter=ruamel.yaml.emitter.Emitter;self.Serializer=ruamel.yaml.serializer.Serializer;self.Representer=ruamel.yaml.representer.RoundTripRepresenter;self.Scanner=ruamel.yaml.scanner.RoundTripScanner;self.Parser=ruamel.yaml.parser.RoundTripParser;self.Composer=ruamel.yaml.composer.Composer;self.Constructor=ruamel.yaml.constructor.RoundTripConstructor
-		del setup_rt;self.stream=_A;self.canonical=_A;self.old_indent=_A;self.width=_A;self.line_break=_A;self.map_indent=_A;self.sequence_indent=_A;self.sequence_dash_offset=0;self.compact_seq_seq=_A;self.compact_seq_map=_A;self.sort_base_mapping_type_on_output=_A;self.top_level_colon_align=_A;self.prefix_colon=_A;self.version=_A;self.preserve_quotes=_A;self.allow_duplicate_keys=_B;self.encoding=_J;self.explicit_start=_A;self.explicit_end=_A;self.tags=_A;self.default_style=_A;self.top_level_block_style_scalar_no_indent_error_1_1=_B;self.scalar_after_indicator=_A;self.brace_single_entry_mapping_in_flow_sequence=_B
+		del setup_rt;self.stream=_A;self.canonical=_A;self.old_indent=_A;self.width=_A;self.line_break=_A;self.map_indent=_A;self.sequence_indent=_A;self.sequence_dash_offset=0;self.compact_seq_seq=_A;self.compact_seq_map=_A;self.sort_base_mapping_type_on_output=_A;self.top_level_colon_align=_A;self.prefix_colon=_A;self.version=_A;self.preserve_quotes=_A;self.allow_duplicate_keys=_B;self.encoding='utf-8';self.explicit_start=_A;self.explicit_end=_A;self.tags=_A;self.default_style=_A;self.top_level_block_style_scalar_no_indent_error_1_1=_B;self.scalar_after_indicator=_A;self.brace_single_entry_mapping_in_flow_sequence=_B
 		for module in self.plug_ins:
-			if getattr(module,_K,_A)in self.typ:typ_found+=1;module.init_typ(self);break
+			if getattr(module,'typ',_A)in self.typ:typ_found+=1;module.init_typ(self);break
 		if typ_found==0:raise NotImplementedError('typ "{}"not recognised (need to install plug-in?)'.format(self.typ))
 	@property
 	def reader(self):
@@ -66,7 +61,7 @@ class YAML:
 		attr=_D+sys._getframe().f_code.co_name
 		if not hasattr(self,attr):
 			if self.Parser is not CParser:setattr(self,attr,self.Parser(loader=self))
-			elif getattr(self,_L,_A)is _A:return _A
+			elif getattr(self,_I,_A)is _A:return _A
 			else:setattr(self,attr,CParser(self._stream))
 		return getattr(self,attr)
 	@property
@@ -96,7 +91,7 @@ class YAML:
 				if self.compact_seq_seq is not _A:_emitter.compact_seq_seq=self.compact_seq_seq
 				if self.compact_seq_map is not _A:_emitter.compact_seq_map=self.compact_seq_map
 			else:
-				if getattr(self,_L,_A)is _A:return _A
+				if getattr(self,_I,_A)is _A:return _A
 				return _A
 		return getattr(self,attr)
 	@property
@@ -113,7 +108,7 @@ class YAML:
 			setattr(self,attr,repres)
 		return getattr(self,attr)
 	def load(self,stream):
-		if not hasattr(stream,_M)and hasattr(stream,_F):
+		if not hasattr(stream,'read')and hasattr(stream,_F):
 			with stream.open('rb')as fp:return self.load(fp)
 		constructor,parser=self.get_constructor_parser(stream)
 		try:return constructor.get_single_data()
@@ -125,7 +120,7 @@ class YAML:
 			except AttributeError:pass
 	def load_all(self,stream,_kw=enforce):
 		if _kw is not enforce:raise TypeError(_H.format(self.__class__.__name__,_kw))
-		if not hasattr(stream,_M)and hasattr(stream,_F):
+		if not hasattr(stream,'read')and hasattr(stream,_F):
 			with stream.open('r')as fp:
 				for d in self.load_all(fp,_kw=enforce):yield d
 				return
@@ -166,14 +161,14 @@ class YAML:
 			return self.dump_all([data],stream,_kw,transform=transform)
 	def dump_all(self,documents,stream,_kw=enforce,transform=_A):
 		if self._context_manager:raise NotImplementedError
-		if _kw is not enforce:raise TypeError(_N.format(self.__class__.__name__,_kw))
+		if _kw is not enforce:raise TypeError(_J.format(self.__class__.__name__,_kw))
 		self._output=stream;self._context_manager=YAMLContextManager(self,transform=transform)
 		for data in documents:self._context_manager.dump(data)
 		self._context_manager.teardown_output();self._output=_A;self._context_manager=_A
 	def Xdump_all(self,documents,stream,_kw=enforce,transform=_A):
-		if not hasattr(stream,_O)and hasattr(stream,_F):
+		if not hasattr(stream,'write')and hasattr(stream,_F):
 			with stream.open('w')as fp:return self.dump_all(documents,fp,_kw,transform=transform)
-		if _kw is not enforce:raise TypeError(_N.format(self.__class__.__name__,_kw))
+		if _kw is not enforce:raise TypeError(_J.format(self.__class__.__name__,_kw))
 		if self.top_level_colon_align is _C:tlca=max([len(str(x))for x in documents[0]])
 		else:tlca=self.top_level_colon_align
 		if transform is not _A:
@@ -190,7 +185,7 @@ class YAML:
 		finally:
 			try:self.emitter.dispose()
 			except AttributeError:raise
-			delattr(self,_P);delattr(self,_Q)
+			delattr(self,_K);delattr(self,_L)
 		if transform:
 			val=stream.getvalue()
 			if self.encoding:val=val.decode(self.encoding)
@@ -207,7 +202,7 @@ class YAML:
 			self.Emitter=ruamel.yaml.emitter.Emitter;self.emitter.stream=stream;self.emitter.top_level_colon_align=tlca
 			if self.scalar_after_indicator is not _A:self.emitter.scalar_after_indicator=self.scalar_after_indicator
 			return self.serializer,self.representer,self.emitter
-		rslvr=ruamel.yaml.resolver.BaseResolver if _I in self.typ else ruamel.yaml.resolver.Resolver
+		rslvr=ruamel.yaml.resolver.BaseResolver if'base'in self.typ else ruamel.yaml.resolver.Resolver
 		class XDumper(CEmitter,self.Representer,rslvr):
 			def __init__(selfx,stream,default_style=_A,default_flow_style=_A,canonical=_A,indent=_A,width=_A,allow_unicode=_A,line_break=_A,encoding=_A,explicit_start=_A,explicit_end=_A,version=_A,tags=_A,block_seq_indent=_A,top_level_colon_align=_A,prefix_colon=_A):CEmitter.__init__(selfx,stream,canonical=canonical,indent=indent,width=width,encoding=encoding,allow_unicode=allow_unicode,line_break=line_break,explicit_start=explicit_start,explicit_end=explicit_end,version=version,tags=tags);selfx._emitter=selfx._serializer=selfx._representer=selfx;self.Representer.__init__(selfx,default_style=default_style,default_flow_style=default_flow_style);rslvr.__init__(selfx)
 		self._stream=stream;dumper=XDumper(stream,default_style=self.default_style,default_flow_style=self.default_flow_style,canonical=self.canonical,indent=self.old_indent,width=self.width,allow_unicode=self.allow_unicode,line_break=self.line_break,explicit_start=self.explicit_start,explicit_end=self.explicit_end,version=self.version,tags=self.tags);self._emitter=self._serializer=dumper;return dumper,dumper,dumper
@@ -215,8 +210,8 @@ class YAML:
 		if _E in self.typ:from dynaconf.vendor.ruamel.yaml.comments import CommentedMap;return CommentedMap(**kw)
 		else:return dict(**kw)
 	def seq(self,*args):
-		if _E in self.typ:from dynaconf.vendor.ruamel.yaml.comments import CommentedSeq;return CommentedSeq(*args)
-		else:return list(*args)
+		if _E in self.typ:from dynaconf.vendor.ruamel.yaml.comments import CommentedSeq;return CommentedSeq(*(args))
+		else:return list(*(args))
 	def official_plug_ins(self):bd=os.path.dirname(__file__);gpbd=os.path.dirname(os.path.dirname(bd));res=[x.replace(gpbd,'')[1:-3]for x in glob.glob(bd+'/*/__plug_in__.py')];return res
 	def register_class(self,cls):
 		tag=getattr(cls,_G,'!'+cls.__name__)
@@ -241,7 +236,7 @@ class YAML:
 			except AttributeError:pass
 	def __enter__(self):self._context_manager=YAMLContextManager(self);return self
 	def __exit__(self,typ,value,traceback):
-		if typ:nprint(_K,typ)
+		if typ:nprint('typ',typ)
 		self._context_manager.teardown_output();self._context_manager=_A
 	def _indent(self,mapping=_A,sequence=_A,offset=_A):
 		if mapping is not _A:self.map_indent=mapping
@@ -259,7 +254,7 @@ class YAML:
 class YAMLContextManager:
 	def __init__(self,yaml,transform=_A):
 		self._yaml=yaml;self._output_inited=_B;self._output_path=_A;self._output=self._yaml._output;self._transform=transform
-		if not hasattr(self._output,_O)and hasattr(self._output,_F):self._output_path=self._output;self._output=self._output_path.open('w')
+		if not hasattr(self._output,'write')and hasattr(self._output,_F):self._output_path=self._output;self._output=self._output_path.open('w')
 		if self._transform is not _A:
 			self._fstream=self._output
 			if self._yaml.encoding is _A:self._output=StringIO()
@@ -269,7 +264,7 @@ class YAMLContextManager:
 		else:return
 		try:self._yaml.emitter.dispose()
 		except AttributeError:raise
-		try:delattr(self._yaml,_P);delattr(self._yaml,_Q)
+		try:delattr(self._yaml,_K);delattr(self._yaml,_L)
 		except AttributeError:raise
 		if self._transform:
 			val=self._output.getvalue()
@@ -352,7 +347,7 @@ def emit(events,stream=_A,Dumper=Dumper,canonical=_A,indent=_A,width=_A,allow_un
 		try:dumper._emitter.dispose()
 		except AttributeError:raise;dumper.dispose()
 	if getvalue is not _A:return getvalue()
-enc=_A if PY3 else _J
+enc=_A if PY3 else'utf-8'
 def serialize_all(nodes,stream=_A,Dumper=Dumper,canonical=_A,indent=_A,width=_A,allow_unicode=_A,line_break=_A,encoding=enc,explicit_start=_A,explicit_end=_A,version=_A,tags=_A):
 	getvalue=_A
 	if stream is _A:
diff --git a/dynaconf/vendor/ruamel/yaml/nodes.py b/dynaconf/vendor/ruamel/yaml/nodes.py
index ffbd8cb..886be14 100644
--- a/dynaconf/vendor/ruamel/yaml/nodes.py
+++ b/dynaconf/vendor/ruamel/yaml/nodes.py
@@ -8,16 +8,16 @@ class Node:
 	def __init__(A,tag,value,start_mark,end_mark,comment=_A,anchor=_A):A.tag=tag;A.value=value;A.start_mark=start_mark;A.end_mark=end_mark;A.comment=comment;A.anchor=anchor
 	def __repr__(A):B=A.value;B=repr(B);return'%s(tag=%r, value=%s)'%(A.__class__.__name__,A.tag,B)
 	def dump(A,indent=0):
-		F='    {}comment: {})\n';D='  ';B=indent
+		E='    {}comment: {})\n';D='  ';B=indent
 		if isinstance(A.value,string_types):
 			sys.stdout.write('{}{}(tag={!r}, value={!r})\n'.format(D*B,A.__class__.__name__,A.tag,A.value))
-			if A.comment:sys.stdout.write(F.format(D*B,A.comment))
+			if A.comment:sys.stdout.write(E.format(D*B,A.comment))
 			return
 		sys.stdout.write('{}{}(tag={!r})\n'.format(D*B,A.__class__.__name__,A.tag))
-		if A.comment:sys.stdout.write(F.format(D*B,A.comment))
+		if A.comment:sys.stdout.write(E.format(D*B,A.comment))
 		for C in A.value:
 			if isinstance(C,tuple):
-				for E in C:E.dump(B+1)
+				for F in C:F.dump(B+1)
 			elif isinstance(C,Node):C.dump(B+1)
 			else:sys.stdout.write('Node value type? {}\n'.format(type(C)))
 class ScalarNode(Node):
diff --git a/dynaconf/vendor/ruamel/yaml/parser.py b/dynaconf/vendor/ruamel/yaml/parser.py
index 2fc791c..173b1e9 100644
--- a/dynaconf/vendor/ruamel/yaml/parser.py
+++ b/dynaconf/vendor/ruamel/yaml/parser.py
@@ -1,7 +1,5 @@
 from __future__ import absolute_import
-_F='expected <block end>, but found %r'
-_E='typ'
-_D='!'
+_D='expected <block end>, but found %r'
 _C=True
 _B=False
 _A=None
@@ -14,7 +12,7 @@ if _B:from typing import Any,Dict,Optional,List
 __all__=['Parser','RoundTripParser','ParserError']
 class ParserError(MarkedYAMLError):0
 class Parser:
-	DEFAULT_TAGS={_D:_D,'!!':'tag:yaml.org,2002:'}
+	DEFAULT_TAGS={'!':'!','!!':'tag:yaml.org,2002:'}
 	def __init__(self,loader):
 		self.loader=loader
 		if self.loader is not _A and getattr(self.loader,'_parser',_A)is _A:self.loader._parser=self
@@ -23,11 +21,11 @@ class Parser:
 	def dispose(self):self.reset_parser()
 	@property
 	def scanner(self):
-		if hasattr(self.loader,_E):return self.loader.scanner
+		if hasattr(self.loader,'typ'):return self.loader.scanner
 		return self.loader._scanner
 	@property
 	def resolver(self):
-		if hasattr(self.loader,_E):return self.loader.resolver
+		if hasattr(self.loader,'typ'):return self.loader.resolver
 		return self.loader._resolver
 	def check_event(self,*choices):
 		if self.current_event is _A:
@@ -109,14 +107,14 @@ class Parser:
 				tag=self.transform_tag(handle,suffix)
 			else:tag=suffix
 		if start_mark is _A:start_mark=end_mark=self.scanner.peek_token().start_mark
-		event=_A;implicit=tag is _A or tag==_D
+		event=_A;implicit=tag is _A or tag=='!'
 		if indentless_sequence and self.scanner.check_token(BlockEntryToken):
 			comment=_A;pt=self.scanner.peek_token()
 			if pt.comment and pt.comment[0]:comment=[pt.comment[0],[]];pt.comment[0]=_A
 			end_mark=self.scanner.peek_token().end_mark;event=SequenceStartEvent(anchor,tag,implicit,start_mark,end_mark,flow_style=_B,comment=comment);self.state=self.parse_indentless_sequence_entry;return event
 		if self.scanner.check_token(ScalarToken):
 			token=self.scanner.get_token();end_mark=token.end_mark
-			if token.plain and tag is _A or tag==_D:implicit=_C,_B
+			if token.plain and tag is _A or tag=='!':implicit=_C,_B
 			elif tag is _A:implicit=_B,_C
 			else:implicit=_B,_B
 			event=ScalarEvent(anchor,tag,implicit,token.value,start_mark,end_mark,style=token.style,comment=token.comment);self.state=self.states.pop()
@@ -139,7 +137,7 @@ class Parser:
 			token=self.scanner.get_token();token.move_comment(self.scanner.peek_token())
 			if not self.scanner.check_token(BlockEntryToken,BlockEndToken):self.states.append(self.parse_block_sequence_entry);return self.parse_block_node()
 			else:self.state=self.parse_block_sequence_entry;return self.process_empty_scalar(token.end_mark)
-		if not self.scanner.check_token(BlockEndToken):token=self.scanner.peek_token();raise ParserError('while parsing a block collection',self.marks[-1],_F%token.id,token.start_mark)
+		if not self.scanner.check_token(BlockEndToken):token=self.scanner.peek_token();raise ParserError('while parsing a block collection',self.marks[-1],_D%token.id,token.start_mark)
 		token=self.scanner.get_token();event=SequenceEndEvent(token.start_mark,token.end_mark,comment=token.comment);self.state=self.states.pop();self.marks.pop();return event
 	def parse_indentless_sequence_entry(self):
 		if self.scanner.check_token(BlockEntryToken):
@@ -154,7 +152,7 @@ class Parser:
 			if not self.scanner.check_token(KeyToken,ValueToken,BlockEndToken):self.states.append(self.parse_block_mapping_value);return self.parse_block_node_or_indentless_sequence()
 			else:self.state=self.parse_block_mapping_value;return self.process_empty_scalar(token.end_mark)
 		if self.resolver.processing_version>(1,1)and self.scanner.check_token(ValueToken):self.state=self.parse_block_mapping_value;return self.process_empty_scalar(self.scanner.peek_token().start_mark)
-		if not self.scanner.check_token(BlockEndToken):token=self.scanner.peek_token();raise ParserError('while parsing a block mapping',self.marks[-1],_F%token.id,token.start_mark)
+		if not self.scanner.check_token(BlockEndToken):token=self.scanner.peek_token();raise ParserError('while parsing a block mapping',self.marks[-1],_D%token.id,token.start_mark)
 		token=self.scanner.get_token();token.move_comment(self.scanner.peek_token());event=MappingEndEvent(token.start_mark,token.end_mark,comment=token.comment);self.state=self.states.pop();self.marks.pop();return event
 	def parse_block_mapping_value(self):
 		if self.scanner.check_token(ValueToken):
diff --git a/dynaconf/vendor/ruamel/yaml/reader.py b/dynaconf/vendor/ruamel/yaml/reader.py
index 06bd083..5f87e47 100644
--- a/dynaconf/vendor/ruamel/yaml/reader.py
+++ b/dynaconf/vendor/ruamel/yaml/reader.py
@@ -1,15 +1,12 @@
 from __future__ import absolute_import
-_F='\ufeff'
-_E='\x00'
-_D=False
-_C='ascii'
-_B='\n'
+_C='\ufeff'
+_B='ascii'
 _A=None
 import codecs
 from .error import YAMLError,FileMark,StringMark,YAMLStreamError
 from .compat import text_type,binary_type,PY3,UNICODE_SIZE
 from .util import RegExp
-if _D:from typing import Any,Dict,Optional,List,Union,Text,Tuple,Optional
+if False:from typing import Any,Dict,Optional,List,Union,Text,Tuple,Optional
 __all__=['Reader','ReaderError']
 class ReaderError(YAMLError):
 	def __init__(A,name,position,character,encoding,reason):A.name=name;A.character=character;A.position=position;A.encoding=encoding;A.reason=reason
@@ -31,11 +28,11 @@ class Reader:
 		B=val;A=self
 		if B is _A:return
 		A._stream=_A
-		if isinstance(B,text_type):A.name='<unicode string>';A.check_printable(B);A.buffer=B+_E
+		if isinstance(B,text_type):A.name='<unicode string>';A.check_printable(B);A.buffer=B+'\x00'
 		elif isinstance(B,binary_type):A.name='<byte string>';A.raw_buffer=B;A.determine_encoding()
 		else:
 			if not hasattr(B,'read'):raise YAMLStreamError('stream argument needs to have a read() method')
-			A._stream=B;A.name=getattr(A.stream,'name','<file>');A.eof=_D;A.raw_buffer=_A;A.determine_encoding()
+			A._stream=B;A.name=getattr(A.stream,'name','<file>');A.eof=False;A.raw_buffer=_A;A.determine_encoding()
 	def peek(A,index=0):
 		B=index
 		try:return A.buffer[A.pointer+B]
@@ -49,16 +46,16 @@ class Reader:
 		if A.pointer+B+1>=len(A.buffer):A.update(B+1)
 		while B!=0:
 			C=A.buffer[A.pointer];A.pointer+=1;A.index+=1
-			if C in'\n\x85\u2028\u2029'or C=='\r'and A.buffer[A.pointer]!=_B:A.line+=1;A.column=0
-			elif C!=_F:A.column+=1
+			if C in'\n\x85\u2028\u2029'or C=='\r'and A.buffer[A.pointer]!='\n':A.line+=1;A.column=0
+			elif C!=_C:A.column+=1
 			B-=1
 	def forward(A,length=1):
 		B=length
 		if A.pointer+B+1>=len(A.buffer):A.update(B+1)
 		while B!=0:
 			C=A.buffer[A.pointer];A.pointer+=1;A.index+=1
-			if C==_B or C=='\r'and A.buffer[A.pointer]!=_B:A.line+=1;A.column=0
-			elif C!=_F:A.column+=1
+			if C=='\n'or C=='\r'and A.buffer[A.pointer]!='\n':A.line+=1;A.column=0
+			elif C!=_C:A.column+=1
 			B-=1
 	def get_mark(A):
 		if A.stream is _A:return StringMark(A.name,A.index,A.line,A.column,A.buffer,A.pointer)
@@ -72,12 +69,12 @@ class Reader:
 		A.update(1)
 	if UNICODE_SIZE==2:NON_PRINTABLE=RegExp('[^\t\n\r -~\x85\xa0-\ud7ff\ue000-�]')
 	else:NON_PRINTABLE=RegExp('[^\t\n\r -~\x85\xa0-\ud7ff\ue000-�𐀀-\U0010ffff]')
-	_printable_ascii=('\t\n\r'+''.join(map(chr,range(32,127)))).encode(_C)
+	_printable_ascii=('\t\n\r'+''.join(map(chr,range(32,127)))).encode(_B)
 	@classmethod
 	def _get_non_printable_ascii(D,data):
-		A=data.encode(_C);B=A.translate(_A,D._printable_ascii)
+		A=data.encode(_B);B=A.translate(_A,D._printable_ascii)
 		if not B:return _A
-		C=B[:1];return A.index(C),C.decode(_C)
+		C=B[:1];return A.index(C),C.decode(_B)
 	@classmethod
 	def _get_non_printable_regex(B,data):
 		A=B.NON_PRINTABLE.search(data)
@@ -106,7 +103,7 @@ class Reader:
 					raise ReaderError(A.name,D,F,B.encoding,B.reason)
 			else:C=A.raw_buffer;E=len(C)
 			A.check_printable(C);A.buffer+=C;A.raw_buffer=A.raw_buffer[E:]
-			if A.eof:A.buffer+=_E;A.raw_buffer=_A;break
+			if A.eof:A.buffer+='\x00';A.raw_buffer=_A;break
 	def update_raw(A,size=_A):
 		C=size
 		if C is _A:C=4096 if PY3 else 1024
diff --git a/dynaconf/vendor/ruamel/yaml/representer.py b/dynaconf/vendor/ruamel/yaml/representer.py
index dc6bc3d..861bb50 100644
--- a/dynaconf/vendor/ruamel/yaml/representer.py
+++ b/dynaconf/vendor/ruamel/yaml/representer.py
@@ -1,28 +1,17 @@
 from __future__ import print_function,absolute_import,division
-_e='tag:yaml.org,2002:'
-_d='state'
-_c='args'
-_b='tag:yaml.org,2002:python/object:'
-_a='__getstate__'
-_Z='tag:yaml.org,2002:set'
-_Y='-.inf'
-_X='.inf'
-_W='.nan'
-_V='base64'
-_U='utf-8'
-_T='null'
-_S='typ'
-_R='tag:yaml.org,2002:python/object/new:'
-_Q='tag:yaml.org,2002:timestamp'
-_P='tag:yaml.org,2002:map'
-_O='tag:yaml.org,2002:seq'
-_N='tag:yaml.org,2002:float'
-_M='tag:yaml.org,2002:binary'
-_L='tag:yaml.org,2002:null'
-_K=0.0
-_J='|'
-_I='%s.%s'
-_H='.'
+_T='tag:yaml.org,2002:'
+_S='tag:yaml.org,2002:python/object:'
+_R='__getstate__'
+_Q='tag:yaml.org,2002:set'
+_P='base64'
+_O='tag:yaml.org,2002:python/object/new:'
+_N='tag:yaml.org,2002:timestamp'
+_M='tag:yaml.org,2002:map'
+_L='tag:yaml.org,2002:seq'
+_K='tag:yaml.org,2002:float'
+_J='tag:yaml.org,2002:binary'
+_I='tag:yaml.org,2002:null'
+_H='%s.%s'
 _G='tag:yaml.org,2002:int'
 _F='comment'
 _E='ascii'
@@ -60,7 +49,7 @@ class BaseRepresenter:
 	@property
 	def serializer(self):
 		try:
-			if hasattr(self.dumper,_S):return self.dumper.serializer
+			if hasattr(self.dumper,'typ'):return self.dumper.serializer
 			return self.dumper._serializer
 		except AttributeError:return self
 	def represent(self,data):node=self.represent_data(data);self.serializer.serialize(node);self.represented_objects={};self.object_keeper=[];self.alias_key=_A
@@ -145,20 +134,20 @@ class SafeRepresenter(BaseRepresenter):
 		if data is _A or isinstance(data,tuple)and data==():return _B
 		if isinstance(data,(binary_type,text_type,bool,int,float)):return _B
 		return _C
-	def represent_none(self,data):return self.represent_scalar(_L,_T)
+	def represent_none(self,data):return self.represent_scalar(_I,'null')
 	if PY3:
 		def represent_str(self,data):return self.represent_scalar(_D,data)
 		def represent_binary(self,data):
 			if hasattr(base64,'encodebytes'):data=base64.encodebytes(data).decode(_E)
 			else:data=base64.encodestring(data).decode(_E)
-			return self.represent_scalar(_M,data,style=_J)
+			return self.represent_scalar(_J,data,style='|')
 	else:
 		def represent_str(self,data):
 			tag=_A;style=_A
 			try:data=unicode(data,_E);tag=_D
 			except UnicodeDecodeError:
-				try:data=unicode(data,_U);tag=_D
-				except UnicodeDecodeError:data=data.encode(_V);tag=_M;style=_J
+				try:data=unicode(data,'utf-8');tag=_D
+				except UnicodeDecodeError:data=data.encode(_P);tag=_J;style='|'
 			return self.represent_scalar(tag,data,style=style)
 		def represent_unicode(self,data):return self.represent_scalar(_D,data)
 	def represent_bool(self,data,anchor=_A):
@@ -173,25 +162,25 @@ class SafeRepresenter(BaseRepresenter):
 	inf_value=1e+300
 	while repr(inf_value)!=repr(inf_value*inf_value):inf_value*=inf_value
 	def represent_float(self,data):
-		if data!=data or data==_K and data==1.0:value=_W
-		elif data==self.inf_value:value=_X
-		elif data==-self.inf_value:value=_Y
+		if data!=data or data==0.0 and data==1.0:value='.nan'
+		elif data==self.inf_value:value='.inf'
+		elif data==-self.inf_value:value='-.inf'
 		else:
 			value=to_unicode(repr(data)).lower()
 			if getattr(self.serializer,'use_version',_A)==(1,1):
-				if _H not in value and'e'in value:value=value.replace('e','.0e',1)
-		return self.represent_scalar(_N,value)
-	def represent_list(self,data):return self.represent_sequence(_O,data)
-	def represent_dict(self,data):return self.represent_mapping(_P,data)
+				if'.'not in value and'e'in value:value=value.replace('e','.0e',1)
+		return self.represent_scalar(_K,value)
+	def represent_list(self,data):return self.represent_sequence(_L,data)
+	def represent_dict(self,data):return self.represent_mapping(_M,data)
 	def represent_ordereddict(self,data):return self.represent_omap('tag:yaml.org,2002:omap',data)
 	def represent_set(self,data):
 		value={}
 		for key in data:value[key]=_A
-		return self.represent_mapping(_Z,value)
-	def represent_date(self,data):value=to_unicode(data.isoformat());return self.represent_scalar(_Q,value)
-	def represent_datetime(self,data):value=to_unicode(data.isoformat(' '));return self.represent_scalar(_Q,value)
+		return self.represent_mapping(_Q,value)
+	def represent_date(self,data):value=to_unicode(data.isoformat());return self.represent_scalar(_N,value)
+	def represent_datetime(self,data):value=to_unicode(data.isoformat(' '));return self.represent_scalar(_N,value)
 	def represent_yaml_object(self,tag,data,cls,flow_style=_A):
-		if hasattr(data,_a):state=data.__getstate__()
+		if hasattr(data,_R):state=data.__getstate__()
 		else:state=data.__dict__.copy()
 		return self.represent_mapping(tag,state,flow_style=flow_style)
 	def represent_undefined(self,data):raise RepresenterError('cannot represent an object: %s'%(data,))
@@ -218,8 +207,8 @@ class Representer(SafeRepresenter):
 			tag=_A;style=_A
 			try:data=unicode(data,_E);tag=_D
 			except UnicodeDecodeError:
-				try:data=unicode(data,_U);tag='tag:yaml.org,2002:python/str'
-				except UnicodeDecodeError:data=data.encode(_V);tag=_M;style=_J
+				try:data=unicode(data,'utf-8');tag='tag:yaml.org,2002:python/str'
+				except UnicodeDecodeError:data=data.encode(_P);tag=_J;style='|'
 			return self.represent_scalar(tag,data,style=style)
 		def represent_unicode(self,data):
 			tag=_A
@@ -231,28 +220,28 @@ class Representer(SafeRepresenter):
 			if int(data)is not data:tag='tag:yaml.org,2002:python/long'
 			return self.represent_scalar(tag,to_unicode(data))
 	def represent_complex(self,data):
-		if data.imag==_K:data='%r'%data.real
-		elif data.real==_K:data='%rj'%data.imag
+		if data.imag==0.0:data='%r'%data.real
+		elif data.real==0.0:data='%rj'%data.imag
 		elif data.imag>0:data='%r+%rj'%(data.real,data.imag)
 		else:data='%r%rj'%(data.real,data.imag)
 		return self.represent_scalar('tag:yaml.org,2002:python/complex',data)
 	def represent_tuple(self,data):return self.represent_sequence('tag:yaml.org,2002:python/tuple',data)
 	def represent_name(self,data):
-		try:name=_I%(data.__module__,data.__qualname__)
-		except AttributeError:name=_I%(data.__module__,data.__name__)
+		try:name=_H%(data.__module__,data.__qualname__)
+		except AttributeError:name=_H%(data.__module__,data.__name__)
 		return self.represent_scalar('tag:yaml.org,2002:python/name:'+name,'')
 	def represent_module(self,data):return self.represent_scalar('tag:yaml.org,2002:python/module:'+data.__name__,'')
 	if PY2:
 		def represent_instance(self,data):
-			cls=data.__class__;class_name=_I%(cls.__module__,cls.__name__);args=_A;state=_A
+			cls=data.__class__;class_name=_H%(cls.__module__,cls.__name__);args=_A;state=_A
 			if hasattr(data,'__getinitargs__'):args=list(data.__getinitargs__())
-			if hasattr(data,_a):state=data.__getstate__()
+			if hasattr(data,_R):state=data.__getstate__()
 			else:state=data.__dict__
-			if args is _A and isinstance(state,dict):return self.represent_mapping(_b+class_name,state)
-			if isinstance(state,dict)and not state:return self.represent_sequence(_R+class_name,args)
+			if args is _A and isinstance(state,dict):return self.represent_mapping(_S+class_name,state)
+			if isinstance(state,dict)and not state:return self.represent_sequence(_O+class_name,args)
 			value={}
-			if bool(args):value[_c]=args
-			value[_d]=state;return self.represent_mapping(_R+class_name,value)
+			if bool(args):value['args']=args
+			value['state']=state;return self.represent_mapping(_O+class_name,value)
 	def represent_object(self,data):
 		cls=type(data)
 		if cls in copyreg.dispatch_table:reduce=copyreg.dispatch_table[cls](data)
@@ -263,15 +252,15 @@ class Representer(SafeRepresenter):
 		if state is _A:state={}
 		if listitems is not _A:listitems=list(listitems)
 		if dictitems is not _A:dictitems=dict(dictitems)
-		if function.__name__=='__newobj__':function=args[0];args=args[1:];tag=_R;newobj=_B
+		if function.__name__=='__newobj__':function=args[0];args=args[1:];tag=_O;newobj=_B
 		else:tag='tag:yaml.org,2002:python/object/apply:';newobj=_C
-		try:function_name=_I%(function.__module__,function.__qualname__)
-		except AttributeError:function_name=_I%(function.__module__,function.__name__)
-		if not args and not listitems and not dictitems and isinstance(state,dict)and newobj:return self.represent_mapping(_b+function_name,state)
+		try:function_name=_H%(function.__module__,function.__qualname__)
+		except AttributeError:function_name=_H%(function.__module__,function.__name__)
+		if not args and not listitems and not dictitems and isinstance(state,dict)and newobj:return self.represent_mapping(_S+function_name,state)
 		if not listitems and not dictitems and isinstance(state,dict)and not state:return self.represent_sequence(tag+function_name,args)
 		value={}
-		if args:value[_c]=args
-		if state or not isinstance(state,dict):value[_d]=state
+		if args:value['args']=args
+		if state or not isinstance(state,dict):value['state']=state
 		if listitems:value['listitems']=listitems
 		if dictitems:value['dictitems']=dictitems
 		return self.represent_mapping(tag+function_name,value)
@@ -289,7 +278,7 @@ Representer.add_multi_representer(type,Representer.represent_name)
 from .comments import CommentedMap,CommentedOrderedMap,CommentedSeq,CommentedKeySeq,CommentedKeyMap,CommentedSet,comment_attrib,merge_attrib,TaggedScalar
 class RoundTripRepresenter(SafeRepresenter):
 	def __init__(self,default_style=_A,default_flow_style=_A,dumper=_A):
-		if not hasattr(dumper,_S)and default_flow_style is _A:default_flow_style=_C
+		if not hasattr(dumper,'typ')and default_flow_style is _A:default_flow_style=_C
 		SafeRepresenter.__init__(self,default_style=default_style,default_flow_style=default_flow_style,dumper=dumper)
 	def ignore_aliases(self,data):
 		try:
@@ -297,10 +286,10 @@ class RoundTripRepresenter(SafeRepresenter):
 		except AttributeError:pass
 		return SafeRepresenter.ignore_aliases(self,data)
 	def represent_none(self,data):
-		if len(self.represented_objects)==0 and not self.serializer.use_explicit_start:return self.represent_scalar(_L,_T)
-		return self.represent_scalar(_L,'')
+		if len(self.represented_objects)==0 and not self.serializer.use_explicit_start:return self.represent_scalar(_I,'null')
+		return self.represent_scalar(_I,'')
 	def represent_literal_scalarstring(self,data):
-		tag=_A;style=_J;anchor=data.yaml_anchor(any=_B)
+		tag=_A;style='|';anchor=data.yaml_anchor(any=_B)
 		if PY2 and not isinstance(data,unicode):data=unicode(data,_E)
 		tag=_D;return self.represent_scalar(tag,data,style=style,anchor=anchor)
 	represent_preserved_scalarstring=represent_literal_scalarstring
@@ -353,35 +342,35 @@ class RoundTripRepresenter(SafeRepresenter):
 		else:s=format(data,'X')
 		anchor=data.yaml_anchor(any=_B);return self.insert_underscore('0x',s,data._underscore,anchor=anchor)
 	def represent_scalar_float(self,data):
-		C='+';B='{:{}0{}d}';A='0';value=_A;anchor=data.yaml_anchor(any=_B)
-		if data!=data or data==_K and data==1.0:value=_W
-		elif data==self.inf_value:value=_X
-		elif data==-self.inf_value:value=_Y
-		if value:return self.represent_scalar(_N,value,anchor=anchor)
+		B='{:{}0{}d}';A='0';value=_A;anchor=data.yaml_anchor(any=_B)
+		if data!=data or data==0.0 and data==1.0:value='.nan'
+		elif data==self.inf_value:value='.inf'
+		elif data==-self.inf_value:value='-.inf'
+		if value:return self.represent_scalar(_K,value,anchor=anchor)
 		if data._exp is _A and data._prec>0 and data._prec==data._width-1:value='{}{:d}.'.format(data._m_sign if data._m_sign else'',abs(int(data)))
 		elif data._exp is _A:
 			prec=data._prec;ms=data._m_sign if data._m_sign else'';value='{}{:0{}.{}f}'.format(ms,abs(data),data._width-len(ms),data._width-prec-1)
-			if prec==0 or prec==1 and ms!='':value=value.replace('0.',_H)
+			if prec==0 or prec==1 and ms!='':value=value.replace('0.','.')
 			while len(value)<data._width:value+=A
 		else:
 			m,es='{:{}.{}e}'.format(data,data._width,data._width+(1 if data._m_sign else 0)).split('e');w=data._width if data._prec>0 else data._width+1
 			if data<0:w+=1
-			m=m[:w];e=int(es);m1,m2=m.split(_H)
+			m=m[:w];e=int(es);m1,m2=m.split('.')
 			while len(m1)+len(m2)<data._width-(1 if data._prec>=0 else 0):m2+=A
-			if data._m_sign and data>0:m1=C+m1
-			esgn=C if data._e_sign else''
+			if data._m_sign and data>0:m1='+'+m1
+			esgn='+'if data._e_sign else''
 			if data._prec<0:
 				if m2!=A:e-=len(m2)
 				else:m2=''
 				while len(m1)+len(m2)-(1 if data._m_sign else 0)<data._width:m2+=A;e-=1
 				value=m1+m2+data._exp+B.format(e,esgn,data._e_width)
-			elif data._prec==0:e-=len(m2);value=m1+m2+_H+data._exp+B.format(e,esgn,data._e_width)
+			elif data._prec==0:e-=len(m2);value=m1+m2+'.'+data._exp+B.format(e,esgn,data._e_width)
 			else:
 				if data._m_lead0>0:m2=A*(data._m_lead0-1)+m1+m2;m1=A;m2=m2[:-data._m_lead0];e+=data._m_lead0
 				while len(m1)<data._prec:m1+=m2[0];m2=m2[1:];e-=1
-				value=m1+_H+m2+data._exp+B.format(e,esgn,data._e_width)
+				value=m1+'.'+m2+data._exp+B.format(e,esgn,data._e_width)
 		if value is _A:value=to_unicode(repr(data)).lower()
-		return self.represent_scalar(_N,value,anchor=anchor)
+		return self.represent_scalar(_K,value,anchor=anchor)
 	def represent_sequence(self,tag,sequence,flow_style=_A):
 		value=[]
 		try:flow_style=sequence.fa.flow_style(flow_style)
@@ -420,8 +409,8 @@ class RoundTripRepresenter(SafeRepresenter):
 				if nc is not _A:assert val is _A or val==nc;comments[idx]=nc
 		node.comment=comments;return node
 	def represent_key(self,data):
-		if isinstance(data,CommentedKeySeq):self.alias_key=_A;return self.represent_sequence(_O,data,flow_style=_B)
-		if isinstance(data,CommentedKeyMap):self.alias_key=_A;return self.represent_mapping(_P,data,flow_style=_B)
+		if isinstance(data,CommentedKeySeq):self.alias_key=_A;return self.represent_sequence(_L,data,flow_style=_B)
+		if isinstance(data,CommentedKeyMap):self.alias_key=_A;return self.represent_mapping(_M,data,flow_style=_B)
 		return SafeRepresenter.represent_key(self,data)
 	def represent_mapping(self,tag,mapping,flow_style=_A):
 		value=[]
@@ -499,7 +488,7 @@ class RoundTripRepresenter(SafeRepresenter):
 			else:node.flow_style=best_style
 		return node
 	def represent_set(self,setting):
-		flow_style=_C;tag=_Z;value=[];flow_style=setting.fa.flow_style(flow_style)
+		flow_style=_C;tag=_Q;value=[];flow_style=setting.fa.flow_style(flow_style)
 		try:anchor=setting.yaml_anchor()
 		except AttributeError:anchor=_A
 		node=MappingNode(tag,value,flow_style=flow_style,anchor=anchor)
@@ -528,24 +517,24 @@ class RoundTripRepresenter(SafeRepresenter):
 		try:t=data.tag.value
 		except AttributeError:t=_A
 		if t:
-			if t.startswith('!!'):tag=_e+t[2:]
+			if t.startswith('!!'):tag=_T+t[2:]
 			else:tag=t
-		else:tag=_P
+		else:tag=_M
 		return self.represent_mapping(tag,data)
 	def represent_list(self,data):
 		try:t=data.tag.value
 		except AttributeError:t=_A
 		if t:
-			if t.startswith('!!'):tag=_e+t[2:]
+			if t.startswith('!!'):tag=_T+t[2:]
 			else:tag=t
-		else:tag=_O
+		else:tag=_L
 		return self.represent_sequence(tag,data)
 	def represent_datetime(self,data):
-		B='tz';A='delta';inter='T'if data._yaml['t']else' ';_yaml=data._yaml
+		A='delta';inter='T'if data._yaml['t']else' ';_yaml=data._yaml
 		if _yaml[A]:data+=_yaml[A];value=data.isoformat(inter)
 		else:value=data.isoformat(inter)
-		if _yaml[B]:value+=_yaml[B]
-		return self.represent_scalar(_Q,to_unicode(value))
+		if _yaml['tz']:value+=_yaml['tz']
+		return self.represent_scalar(_N,to_unicode(value))
 	def represent_tagged_scalar(self,data):
 		try:tag=data.tag.value
 		except AttributeError:tag=_A
diff --git a/dynaconf/vendor/ruamel/yaml/resolver.py b/dynaconf/vendor/ruamel/yaml/resolver.py
index 7377ca5..9bef98b 100644
--- a/dynaconf/vendor/ruamel/yaml/resolver.py
+++ b/dynaconf/vendor/ruamel/yaml/resolver.py
@@ -1,12 +1,10 @@
 from __future__ import absolute_import
-_J='yaml_implicit_resolvers'
-_I='typ'
-_H='-+0123456789'
-_G='tag:yaml.org,2002:int'
-_F='-+0123456789.'
-_E='tag:yaml.org,2002:float'
-_D='tag:yaml.org,2002:bool'
-_C=True
+_H='yaml_implicit_resolvers'
+_G='-+0123456789'
+_F='tag:yaml.org,2002:int'
+_E='-+0123456789.'
+_D='tag:yaml.org,2002:float'
+_C='tag:yaml.org,2002:bool'
 _B=False
 _A=None
 import re
@@ -16,7 +14,7 @@ from .error import *
 from .nodes import MappingNode,ScalarNode,SequenceNode
 from .util import RegExp
 __all__=['BaseResolver','Resolver','VersionedResolver']
-implicit_resolvers=[([(1,2)],_D,RegExp('^(?:true|True|TRUE|false|False|FALSE)$',re.X),list('tTfF')),([(1,1)],_D,RegExp('^(?:y|Y|yes|Yes|YES|n|N|no|No|NO\n        |true|True|TRUE|false|False|FALSE\n        |on|On|ON|off|Off|OFF)$',re.X),list('yYnNtTfFoO')),([(1,2)],_E,RegExp('^(?:\n         [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?\n        |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)\n        |[-+]?\\.[0-9_]+(?:[eE][-+][0-9]+)?\n        |[-+]?\\.(?:inf|Inf|INF)\n        |\\.(?:nan|NaN|NAN))$',re.X),list(_F)),([(1,1)],_E,RegExp('^(?:\n         [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?\n        |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)\n        |\\.[0-9_]+(?:[eE][-+][0-9]+)?\n        |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*  # sexagesimal float\n        |[-+]?\\.(?:inf|Inf|INF)\n        |\\.(?:nan|NaN|NAN))$',re.X),list(_F)),([(1,2)],_G,RegExp('^(?:[-+]?0b[0-1_]+\n        |[-+]?0o?[0-7_]+\n        |[-+]?[0-9_]+\n        |[-+]?0x[0-9a-fA-F_]+)$',re.X),list(_H)),([(1,1)],_G,RegExp('^(?:[-+]?0b[0-1_]+\n        |[-+]?0?[0-7_]+\n        |[-+]?(?:0|[1-9][0-9_]*)\n        |[-+]?0x[0-9a-fA-F_]+\n        |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$',re.X),list(_H)),([(1,2),(1,1)],'tag:yaml.org,2002:merge',RegExp('^(?:<<)$'),['<']),([(1,2),(1,1)],'tag:yaml.org,2002:null',RegExp('^(?: ~\n        |null|Null|NULL\n        | )$',re.X),['~','n','N','']),([(1,2),(1,1)],'tag:yaml.org,2002:timestamp',RegExp('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n        |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n        (?:[Tt]|[ \\t]+)[0-9][0-9]?\n        :[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)?\n        (?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$',re.X),list('0123456789')),([(1,2),(1,1)],'tag:yaml.org,2002:value',RegExp('^(?:=)$'),['=']),([(1,2),(1,1)],'tag:yaml.org,2002:yaml',RegExp('^(?:!|&|\\*)$'),list('!&*'))]
+implicit_resolvers=[([(1,2)],_C,RegExp('^(?:true|True|TRUE|false|False|FALSE)$',re.X),list('tTfF')),([(1,1)],_C,RegExp('^(?:y|Y|yes|Yes|YES|n|N|no|No|NO\n        |true|True|TRUE|false|False|FALSE\n        |on|On|ON|off|Off|OFF)$',re.X),list('yYnNtTfFoO')),([(1,2)],_D,RegExp('^(?:\n         [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?\n        |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)\n        |[-+]?\\.[0-9_]+(?:[eE][-+][0-9]+)?\n        |[-+]?\\.(?:inf|Inf|INF)\n        |\\.(?:nan|NaN|NAN))$',re.X),list(_E)),([(1,1)],_D,RegExp('^(?:\n         [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?\n        |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)\n        |\\.[0-9_]+(?:[eE][-+][0-9]+)?\n        |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*  # sexagesimal float\n        |[-+]?\\.(?:inf|Inf|INF)\n        |\\.(?:nan|NaN|NAN))$',re.X),list(_E)),([(1,2)],_F,RegExp('^(?:[-+]?0b[0-1_]+\n        |[-+]?0o?[0-7_]+\n        |[-+]?[0-9_]+\n        |[-+]?0x[0-9a-fA-F_]+)$',re.X),list(_G)),([(1,1)],_F,RegExp('^(?:[-+]?0b[0-1_]+\n        |[-+]?0?[0-7_]+\n        |[-+]?(?:0|[1-9][0-9_]*)\n        |[-+]?0x[0-9a-fA-F_]+\n        |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$',re.X),list(_G)),([(1,2),(1,1)],'tag:yaml.org,2002:merge',RegExp('^(?:<<)$'),['<']),([(1,2),(1,1)],'tag:yaml.org,2002:null',RegExp('^(?: ~\n        |null|Null|NULL\n        | )$',re.X),['~','n','N','']),([(1,2),(1,1)],'tag:yaml.org,2002:timestamp',RegExp('^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\n        |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?\n        (?:[Tt]|[ \\t]+)[0-9][0-9]?\n        :[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)?\n        (?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$',re.X),list('0123456789')),([(1,2),(1,1)],'tag:yaml.org,2002:value',RegExp('^(?:=)$'),['=']),([(1,2),(1,1)],'tag:yaml.org,2002:yaml',RegExp('^(?:!|&|\\*)$'),list('!&*'))]
 class ResolverError(YAMLError):0
 class BaseResolver:
 	DEFAULT_SCALAR_TAG='tag:yaml.org,2002:str';DEFAULT_SEQUENCE_TAG='tag:yaml.org,2002:seq';DEFAULT_MAPPING_TAG='tag:yaml.org,2002:map';yaml_implicit_resolvers={};yaml_path_resolvers={}
@@ -27,17 +25,17 @@ class BaseResolver:
 	@property
 	def parser(self):
 		if self.loadumper is not _A:
-			if hasattr(self.loadumper,_I):return self.loadumper.parser
+			if hasattr(self.loadumper,'typ'):return self.loadumper.parser
 			return self.loadumper._parser
 		return _A
 	@classmethod
 	def add_implicit_resolver_base(cls,tag,regexp,first):
-		if _J not in cls.__dict__:cls.yaml_implicit_resolvers=dict(((k,cls.yaml_implicit_resolvers[k][:])for k in cls.yaml_implicit_resolvers))
+		if _H not in cls.__dict__:cls.yaml_implicit_resolvers=dict(((k,cls.yaml_implicit_resolvers[k][:])for k in cls.yaml_implicit_resolvers))
 		if first is _A:first=[_A]
 		for ch in first:cls.yaml_implicit_resolvers.setdefault(ch,[]).append((tag,regexp))
 	@classmethod
 	def add_implicit_resolver(cls,tag,regexp,first):
-		if _J not in cls.__dict__:cls.yaml_implicit_resolvers=dict(((k,cls.yaml_implicit_resolvers[k][:])for k in cls.yaml_implicit_resolvers))
+		if _H not in cls.__dict__:cls.yaml_implicit_resolvers=dict(((k,cls.yaml_implicit_resolvers[k][:])for k in cls.yaml_implicit_resolvers))
 		if first is _A:first=[_A]
 		for ch in first:cls.yaml_implicit_resolvers.setdefault(ch,[]).append((tag,regexp))
 		implicit_resolvers.append(([(1,2),(1,1)],tag,regexp,first))
@@ -48,7 +46,7 @@ class BaseResolver:
 		for element in path:
 			if isinstance(element,(list,tuple)):
 				if len(element)==2:node_check,index_check=element
-				elif len(element)==1:node_check=element[0];index_check=_C
+				elif len(element)==1:node_check=element[0];index_check=True
 				else:raise ResolverError('Invalid path element: %s'%(element,))
 			else:node_check=_A;index_check=element
 			if node_check is str:node_check=ScalarNode
@@ -85,13 +83,13 @@ class BaseResolver:
 			if current_node.tag!=node_check:return _B
 		elif node_check is not _A:
 			if not isinstance(current_node,node_check):return _B
-		if index_check is _C and current_index is not _A:return _B
+		if index_check is True and current_index is not _A:return _B
 		if(index_check is _B or index_check is _A)and current_index is _A:return _B
 		if isinstance(index_check,string_types):
 			if not(isinstance(current_index,ScalarNode)and index_check==current_index.value):return _B
 		elif isinstance(index_check,int)and not isinstance(index_check,bool):
 			if index_check!=current_index:return _B
-		return _C
+		return True
 	def resolve(self,kind,value,implicit):
 		if kind is ScalarNode and implicit[0]:
 			if value=='':resolvers=self.yaml_implicit_resolvers.get('',[])
@@ -151,7 +149,7 @@ class VersionedResolver(BaseResolver):
 		try:version=self.loadumper._scanner.yaml_version
 		except AttributeError:
 			try:
-				if hasattr(self.loadumper,_I):version=self.loadumper.version
+				if hasattr(self.loadumper,'typ'):version=self.loadumper.version
 				else:version=self.loadumper._serializer.use_version
 			except AttributeError:version=_A
 		if version is _A:
diff --git a/dynaconf/vendor/ruamel/yaml/scalarbool.py b/dynaconf/vendor/ruamel/yaml/scalarbool.py
index 84c7cc2..fb951c4 100644
--- a/dynaconf/vendor/ruamel/yaml/scalarbool.py
+++ b/dynaconf/vendor/ruamel/yaml/scalarbool.py
@@ -6,7 +6,7 @@ if _B:from typing import Text,Any,Dict,List
 __all__=['ScalarBoolean']
 class ScalarBoolean(int):
 	def __new__(D,*E,**A):
-		B=A.pop('anchor',_A);C=int.__new__(D,*E,**A)
+		B=A.pop('anchor',_A);C=int.__new__(D,*(E),**A)
 		if B is not _A:C.yaml_set_anchor(B,always_dump=True)
 		return C
 	@property
diff --git a/dynaconf/vendor/ruamel/yaml/scalarfloat.py b/dynaconf/vendor/ruamel/yaml/scalarfloat.py
index fab3a1b..443b9d7 100644
--- a/dynaconf/vendor/ruamel/yaml/scalarfloat.py
+++ b/dynaconf/vendor/ruamel/yaml/scalarfloat.py
@@ -8,7 +8,7 @@ if _B:from typing import Text,Any,Dict,List
 __all__=['ScalarFloat','ExponentialFloat','ExponentialCapsFloat']
 class ScalarFloat(float):
 	def __new__(D,*E,**A):
-		F=A.pop('width',_A);G=A.pop('prec',_A);H=A.pop('m_sign',_A);I=A.pop('m_lead0',0);J=A.pop('exp',_A);K=A.pop('e_width',_A);L=A.pop('e_sign',_A);M=A.pop('underscore',_A);C=A.pop('anchor',_A);B=float.__new__(D,*E,**A);B._width=F;B._prec=G;B._m_sign=H;B._m_lead0=I;B._exp=J;B._e_width=K;B._e_sign=L;B._underscore=M
+		F=A.pop('width',_A);G=A.pop('prec',_A);H=A.pop('m_sign',_A);I=A.pop('m_lead0',0);J=A.pop('exp',_A);K=A.pop('e_width',_A);L=A.pop('e_sign',_A);M=A.pop('underscore',_A);C=A.pop('anchor',_A);B=float.__new__(D,*(E),**A);B._width=F;B._prec=G;B._m_sign=H;B._m_lead0=I;B._exp=J;B._e_width=K;B._e_sign=L;B._underscore=M
 		if C is not _A:B.yaml_set_anchor(C,always_dump=True)
 		return B
 	def __iadd__(A,a):return float(A)+a;B=type(A)(A+a);B._width=A._width;B._underscore=A._underscore[:]if A._underscore is not _A else _A;return B
diff --git a/dynaconf/vendor/ruamel/yaml/scalarint.py b/dynaconf/vendor/ruamel/yaml/scalarint.py
index e61b7eb..925ac41 100644
--- a/dynaconf/vendor/ruamel/yaml/scalarint.py
+++ b/dynaconf/vendor/ruamel/yaml/scalarint.py
@@ -7,7 +7,7 @@ if _B:from typing import Text,Any,Dict,List
 __all__=['ScalarInt','BinaryInt','OctalInt','HexInt','HexCapsInt','DecimalInt']
 class ScalarInt(no_limit_int):
 	def __new__(D,*E,**A):
-		F=A.pop('width',_A);G=A.pop('underscore',_A);C=A.pop('anchor',_A);B=no_limit_int.__new__(D,*E,**A);B._width=F;B._underscore=G
+		F=A.pop('width',_A);G=A.pop('underscore',_A);C=A.pop('anchor',_A);B=no_limit_int.__new__(D,*(E),**A);B._width=F;B._underscore=G
 		if C is not _A:B.yaml_set_anchor(C,always_dump=True)
 		return B
 	def __iadd__(A,a):B=type(A)(A+a);B._width=A._width;B._underscore=A._underscore[:]if A._underscore is not _A else _A;return B
diff --git a/dynaconf/vendor/ruamel/yaml/scalarstring.py b/dynaconf/vendor/ruamel/yaml/scalarstring.py
index 53b9c39..bc7f1f8 100644
--- a/dynaconf/vendor/ruamel/yaml/scalarstring.py
+++ b/dynaconf/vendor/ruamel/yaml/scalarstring.py
@@ -1,6 +1,5 @@
 from __future__ import print_function,absolute_import,division,unicode_literals
-_D='comment'
-_C='\n'
+_C='comment'
 _B=False
 _A=None
 from .compat import text_type
@@ -10,7 +9,7 @@ __all__=['ScalarString','LiteralScalarString','FoldedScalarString','SingleQuoted
 class ScalarString(text_type):
 	__slots__=Anchor.attrib
 	def __new__(D,*E,**A):
-		B=A.pop('anchor',_A);C=text_type.__new__(D,*E,**A)
+		B=A.pop('anchor',_A);C=text_type.__new__(D,*(E),**A)
 		if B is not _A:C.yaml_set_anchor(B,always_dump=True)
 		return C
 	def replace(A,old,new,maxreplace=-1):return type(A)(text_type.replace(A,old,new,maxreplace))
@@ -25,11 +24,11 @@ class ScalarString(text_type):
 		return _A
 	def yaml_set_anchor(A,value,always_dump=_B):A.anchor.value=value;A.anchor.always_dump=always_dump
 class LiteralScalarString(ScalarString):
-	__slots__=_D;style='|'
+	__slots__=_C;style='|'
 	def __new__(A,value,anchor=_A):return ScalarString.__new__(A,value,anchor=anchor)
 PreservedScalarString=LiteralScalarString
 class FoldedScalarString(ScalarString):
-	__slots__='fold_pos',_D;style='>'
+	__slots__='fold_pos',_C;style='>'
 	def __new__(A,value,anchor=_A):return ScalarString.__new__(A,value,anchor=anchor)
 class SingleQuotedScalarString(ScalarString):
 	__slots__=();style="'"
@@ -40,10 +39,10 @@ class DoubleQuotedScalarString(ScalarString):
 class PlainScalarString(ScalarString):
 	__slots__=();style=''
 	def __new__(A,value,anchor=_A):return ScalarString.__new__(A,value,anchor=anchor)
-def preserve_literal(s):return LiteralScalarString(s.replace('\r\n',_C).replace('\r',_C))
+def preserve_literal(s):return LiteralScalarString(s.replace('\r\n','\n').replace('\r','\n'))
 def walk_tree(base,map=_A):
 	A=base;from dynaconf.vendor.ruamel.yaml.compat import string_types as E,MutableMapping as G,MutableSequence as H
-	if map is _A:map={_C:preserve_literal}
+	if map is _A:map={'\n':preserve_literal}
 	if isinstance(A,G):
 		for F in A:
 			C=A[F]
diff --git a/dynaconf/vendor/ruamel/yaml/scanner.py b/dynaconf/vendor/ruamel/yaml/scanner.py
index dfbd1b4..6b344e6 100644
--- a/dynaconf/vendor/ruamel/yaml/scanner.py
+++ b/dynaconf/vendor/ruamel/yaml/scanner.py
@@ -1,36 +1,23 @@
 from __future__ import print_function,absolute_import,division,unicode_literals
-_o='\u2028\u2029'
-_n='\r\n'
-_m='\r\n\x85'
-_l='while scanning a quoted scalar'
-_k='0123456789ABCDEFabcdef'
-_j=' \r\n\x85\u2028\u2029'
-_i='\x07'
-_h='expected a comment or a line break, but found %r'
-_g='directive'
-_f='\ufeff'
-_e="could not find expected ':'"
-_d='while scanning a simple key'
-_c='typ'
-_b='\\'
-_a='\t'
-_Z="expected ' ', but found %r"
-_Y='while scanning a %s'
-_X='\r\n\x85\u2028\u2029'
-_W='while scanning a block scalar'
-_V='expected alphabetic or numeric character, but found %r'
-_U='a'
-_T='...'
-_S='---'
-_R='>'
-_Q='9'
-_P='"'
-_O=':'
-_N='-'
-_M=' \t'
-_L='\x00 \r\n\x85\u2028\u2029'
-_K='0'
-_J="'"
+_b='\u2028\u2029'
+_a='\r\n\x85'
+_Z='while scanning a quoted scalar'
+_Y='0123456789ABCDEFabcdef'
+_X=' \r\n\x85\u2028\u2029'
+_W='expected a comment or a line break, but found %r'
+_V='directive'
+_U='\ufeff'
+_T="could not find expected ':'"
+_S='while scanning a simple key'
+_R="expected ' ', but found %r"
+_Q='while scanning a %s'
+_P='\r\n\x85\u2028\u2029'
+_O='while scanning a block scalar'
+_N='expected alphabetic or numeric character, but found %r'
+_M='...'
+_L='---'
+_K=' \t'
+_J='\x00 \r\n\x85\u2028\u2029'
 _I='\x00'
 _H='!'
 _G='while scanning a directive'
@@ -47,7 +34,7 @@ if _B:from typing import Any,Dict,Optional,List,Union,Text;from .compat import V
 __all__=['Scanner','RoundTripScanner','ScannerError']
 _THE_END='\n\x00\r\x85\u2028\u2029'
 _THE_END_SPACE_TAB=' \n\x00\t\r\x85\u2028\u2029'
-_SPACE_TAB=_M
+_SPACE_TAB=_K
 class ScannerError(MarkedYAMLError):0
 class SimpleKey:
 	def __init__(self,token_number,required,index,line,column,mark):self.token_number=token_number;self.required=required;self.index=index;self.line=line;self.column=column;self.mark=mark
@@ -63,12 +50,12 @@ class Scanner:
 	def reader(self):
 		try:return self._scanner_reader
 		except AttributeError:
-			if hasattr(self.loader,_c):self._scanner_reader=self.loader.reader
+			if hasattr(self.loader,'typ'):self._scanner_reader=self.loader.reader
 			else:self._scanner_reader=self.loader._reader
 			return self._scanner_reader
 	@property
 	def scanner_processing_version(self):
-		if hasattr(self.loader,_c):return self.loader.resolver.processing_version
+		if hasattr(self.loader,'typ'):return self.loader.resolver.processing_version
 		return self.loader.processing_version
 	def check_token(self,*choices):
 		while self.need_more_tokens():self.fetch_more_tokens()
@@ -96,23 +83,23 @@ class Scanner:
 		self.stale_possible_simple_keys();self.unwind_indent(self.reader.column);ch=self.reader.peek()
 		if ch==_I:return self.fetch_stream_end()
 		if ch=='%'and self.check_directive():return self.fetch_directive()
-		if ch==_N and self.check_document_start():return self.fetch_document_start()
+		if ch=='-'and self.check_document_start():return self.fetch_document_start()
 		if ch=='.'and self.check_document_end():return self.fetch_document_end()
 		if ch=='[':return self.fetch_flow_sequence_start()
 		if ch=='{':return self.fetch_flow_mapping_start()
 		if ch==']':return self.fetch_flow_sequence_end()
 		if ch=='}':return self.fetch_flow_mapping_end()
 		if ch==',':return self.fetch_flow_entry()
-		if ch==_N and self.check_block_entry():return self.fetch_block_entry()
+		if ch=='-'and self.check_block_entry():return self.fetch_block_entry()
 		if ch=='?'and self.check_key():return self.fetch_key()
-		if ch==_O and self.check_value():return self.fetch_value()
+		if ch==':'and self.check_value():return self.fetch_value()
 		if ch=='*':return self.fetch_alias()
 		if ch=='&':return self.fetch_anchor()
 		if ch==_H:return self.fetch_tag()
 		if ch=='|'and not self.flow_level:return self.fetch_literal()
-		if ch==_R and not self.flow_level:return self.fetch_folded()
-		if ch==_J:return self.fetch_single()
-		if ch==_P:return self.fetch_double()
+		if ch=='>'and not self.flow_level:return self.fetch_folded()
+		if ch=="'":return self.fetch_single()
+		if ch=='"':return self.fetch_double()
 		if self.check_plain():return self.fetch_plain()
 		raise ScannerError('while scanning for the next token',_C,'found character %r that cannot start any token'%utf8(ch),self.reader.get_mark())
 	def next_possible_simple_key(self):
@@ -125,7 +112,7 @@ class Scanner:
 		for level in list(self.possible_simple_keys):
 			key=self.possible_simple_keys[level]
 			if key.line!=self.reader.line or self.reader.index-key.index>1024:
-				if key.required:raise ScannerError(_d,key.mark,_e,self.reader.get_mark())
+				if key.required:raise ScannerError(_S,key.mark,_T,self.reader.get_mark())
 				del self.possible_simple_keys[level]
 	def save_possible_simple_key(self):
 		required=not self.flow_level and self.indent==self.reader.column
@@ -133,7 +120,7 @@ class Scanner:
 	def remove_possible_simple_key(self):
 		if self.flow_level in self.possible_simple_keys:
 			key=self.possible_simple_keys[self.flow_level]
-			if key.required:raise ScannerError(_d,key.mark,_e,self.reader.get_mark())
+			if key.required:raise ScannerError(_S,key.mark,_T,self.reader.get_mark())
 			del self.possible_simple_keys[self.flow_level]
 	def unwind_indent(self,column):
 		if bool(self.flow_level):return
@@ -186,10 +173,10 @@ class Scanner:
 	def fetch_anchor(self):self.save_possible_simple_key();self.allow_simple_key=_B;self.tokens.append(self.scan_anchor(AnchorToken))
 	def fetch_tag(self):self.save_possible_simple_key();self.allow_simple_key=_B;self.tokens.append(self.scan_tag())
 	def fetch_literal(self):self.fetch_block_scalar(style='|')
-	def fetch_folded(self):self.fetch_block_scalar(style=_R)
+	def fetch_folded(self):self.fetch_block_scalar(style='>')
 	def fetch_block_scalar(self,style):self.allow_simple_key=_A;self.remove_possible_simple_key();self.tokens.append(self.scan_block_scalar(style))
-	def fetch_single(self):self.fetch_flow_scalar(style=_J)
-	def fetch_double(self):self.fetch_flow_scalar(style=_P)
+	def fetch_single(self):self.fetch_flow_scalar(style="'")
+	def fetch_double(self):self.fetch_flow_scalar(style='"')
 	def fetch_flow_scalar(self,style):self.save_possible_simple_key();self.allow_simple_key=_B;self.tokens.append(self.scan_flow_scalar(style))
 	def fetch_plain(self):self.save_possible_simple_key();self.allow_simple_key=_B;self.tokens.append(self.scan_plain())
 	def check_directive(self):
@@ -197,11 +184,11 @@ class Scanner:
 		return _C
 	def check_document_start(self):
 		if self.reader.column==0:
-			if self.reader.prefix(3)==_S and self.reader.peek(3)in _THE_END_SPACE_TAB:return _A
+			if self.reader.prefix(3)==_L and self.reader.peek(3)in _THE_END_SPACE_TAB:return _A
 		return _C
 	def check_document_end(self):
 		if self.reader.column==0:
-			if self.reader.prefix(3)==_T and self.reader.peek(3)in _THE_END_SPACE_TAB:return _A
+			if self.reader.prefix(3)==_M and self.reader.peek(3)in _THE_END_SPACE_TAB:return _A
 		return _C
 	def check_block_entry(self):return self.reader.peek(1)in _THE_END_SPACE_TAB
 	def check_key(self):
@@ -218,16 +205,16 @@ class Scanner:
 			return _A
 		return self.reader.peek(1)in _THE_END_SPACE_TAB
 	def check_plain(self):
-		B='?:';A='\x00 \t\r\n\x85\u2028\u2029-?:,[]{}#&*!|>\'"%@`';srp=self.reader.peek;ch=srp()
-		if self.scanner_processing_version==(1,1):return ch not in A or srp(1)not in _THE_END_SPACE_TAB and(ch==_N or not self.flow_level and ch in B)
+		A='\x00 \t\r\n\x85\u2028\u2029-?:,[]{}#&*!|>\'"%@`';srp=self.reader.peek;ch=srp()
+		if self.scanner_processing_version==(1,1):return ch not in A or srp(1)not in _THE_END_SPACE_TAB and(ch=='-'or not self.flow_level and ch in'?:')
 		if ch not in A:return _A
 		ch1=srp(1)
-		if ch==_N and ch1 not in _THE_END_SPACE_TAB:return _A
-		if ch==_O and bool(self.flow_level)and ch1 not in _SPACE_TAB:return _A
-		return srp(1)not in _THE_END_SPACE_TAB and(ch==_N or not self.flow_level and ch in B)
+		if ch=='-'and ch1 not in _THE_END_SPACE_TAB:return _A
+		if ch==':'and bool(self.flow_level)and ch1 not in _SPACE_TAB:return _A
+		return srp(1)not in _THE_END_SPACE_TAB and(ch=='-'or not self.flow_level and ch in'?:')
 	def scan_to_next_token(self):
 		srp=self.reader.peek;srf=self.reader.forward
-		if self.reader.index==0 and srp()==_f:srf()
+		if self.reader.index==0 and srp()==_U:srf()
 		found=_B;_the_end=_THE_END
 		while not found:
 			while srp()==_D:srf()
@@ -247,10 +234,10 @@ class Scanner:
 		self.scan_directive_ignored_line(start_mark);return DirectiveToken(name,value,start_mark,end_mark)
 	def scan_directive_name(self,start_mark):
 		length=0;srp=self.reader.peek;ch=srp(length)
-		while _K<=ch<=_Q or'A'<=ch<='Z'or _U<=ch<='z'or ch in'-_:.':length+=1;ch=srp(length)
-		if not length:raise ScannerError(_G,start_mark,_V%utf8(ch),self.reader.get_mark())
+		while '0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z'or ch in'-_:.':length+=1;ch=srp(length)
+		if not length:raise ScannerError(_G,start_mark,_N%utf8(ch),self.reader.get_mark())
 		value=self.reader.prefix(length);self.reader.forward(length);ch=srp()
-		if ch not in _L:raise ScannerError(_G,start_mark,_V%utf8(ch),self.reader.get_mark())
+		if ch not in _J:raise ScannerError(_G,start_mark,_N%utf8(ch),self.reader.get_mark())
 		return value
 	def scan_yaml_directive_value(self,start_mark):
 		srp=self.reader.peek;srf=self.reader.forward
@@ -258,13 +245,13 @@ class Scanner:
 		major=self.scan_yaml_directive_number(start_mark)
 		if srp()!='.':raise ScannerError(_G,start_mark,"expected a digit or '.', but found %r"%utf8(srp()),self.reader.get_mark())
 		srf();minor=self.scan_yaml_directive_number(start_mark)
-		if srp()not in _L:raise ScannerError(_G,start_mark,"expected a digit or ' ', but found %r"%utf8(srp()),self.reader.get_mark())
+		if srp()not in _J:raise ScannerError(_G,start_mark,"expected a digit or ' ', but found %r"%utf8(srp()),self.reader.get_mark())
 		self.yaml_version=major,minor;return self.yaml_version
 	def scan_yaml_directive_number(self,start_mark):
 		srp=self.reader.peek;srf=self.reader.forward;ch=srp()
-		if not _K<=ch<=_Q:raise ScannerError(_G,start_mark,'expected a digit, but found %r'%utf8(ch),self.reader.get_mark())
+		if not'0'<=ch<='9':raise ScannerError(_G,start_mark,'expected a digit, but found %r'%utf8(ch),self.reader.get_mark())
 		length=0
-		while _K<=srp(length)<=_Q:length+=1
+		while '0'<=srp(length)<='9':length+=1
 		value=int(self.reader.prefix(length));srf(length);return value
 	def scan_tag_directive_value(self,start_mark):
 		srp=self.reader.peek;srf=self.reader.forward
@@ -273,12 +260,12 @@ class Scanner:
 		while srp()==_D:srf()
 		prefix=self.scan_tag_directive_prefix(start_mark);return handle,prefix
 	def scan_tag_directive_handle(self,start_mark):
-		value=self.scan_tag_handle(_g,start_mark);ch=self.reader.peek()
-		if ch!=_D:raise ScannerError(_G,start_mark,_Z%utf8(ch),self.reader.get_mark())
+		value=self.scan_tag_handle(_V,start_mark);ch=self.reader.peek()
+		if ch!=_D:raise ScannerError(_G,start_mark,_R%utf8(ch),self.reader.get_mark())
 		return value
 	def scan_tag_directive_prefix(self,start_mark):
-		value=self.scan_tag_uri(_g,start_mark);ch=self.reader.peek()
-		if ch not in _L:raise ScannerError(_G,start_mark,_Z%utf8(ch),self.reader.get_mark())
+		value=self.scan_tag_uri(_V,start_mark);ch=self.reader.peek()
+		if ch not in _J:raise ScannerError(_G,start_mark,_R%utf8(ch),self.reader.get_mark())
 		return value
 	def scan_directive_ignored_line(self,start_mark):
 		srp=self.reader.peek;srf=self.reader.forward
@@ -286,7 +273,7 @@ class Scanner:
 		if srp()==_F:
 			while srp()not in _THE_END:srf()
 		ch=srp()
-		if ch not in _THE_END:raise ScannerError(_G,start_mark,_h%utf8(ch),self.reader.get_mark())
+		if ch not in _THE_END:raise ScannerError(_G,start_mark,_W%utf8(ch),self.reader.get_mark())
 		self.scan_line_break()
 	def scan_anchor(self,TokenClass):
 		A='while scanning an %s';srp=self.reader.peek;start_mark=self.reader.get_mark();indicator=srp()
@@ -294,20 +281,20 @@ class Scanner:
 		else:name='anchor'
 		self.reader.forward();length=0;ch=srp(length)
 		while check_anchorname_char(ch):length+=1;ch=srp(length)
-		if not length:raise ScannerError(A%(name,),start_mark,_V%utf8(ch),self.reader.get_mark())
+		if not length:raise ScannerError(A%(name,),start_mark,_N%utf8(ch),self.reader.get_mark())
 		value=self.reader.prefix(length);self.reader.forward(length)
-		if ch not in'\x00 \t\r\n\x85\u2028\u2029?:,[]{}%@`':raise ScannerError(A%(name,),start_mark,_V%utf8(ch),self.reader.get_mark())
+		if ch not in'\x00 \t\r\n\x85\u2028\u2029?:,[]{}%@`':raise ScannerError(A%(name,),start_mark,_N%utf8(ch),self.reader.get_mark())
 		end_mark=self.reader.get_mark();return TokenClass(value,start_mark,end_mark)
 	def scan_tag(self):
 		A='tag';srp=self.reader.peek;start_mark=self.reader.get_mark();ch=srp(1)
 		if ch=='<':
 			handle=_C;self.reader.forward(2);suffix=self.scan_tag_uri(A,start_mark)
-			if srp()!=_R:raise ScannerError('while parsing a tag',start_mark,"expected '>', but found %r"%utf8(srp()),self.reader.get_mark())
+			if srp()!='>':raise ScannerError('while parsing a tag',start_mark,"expected '>', but found %r"%utf8(srp()),self.reader.get_mark())
 			self.reader.forward()
 		elif ch in _THE_END_SPACE_TAB:handle=_C;suffix=_H;self.reader.forward()
 		else:
 			length=1;use_handle=_B
-			while ch not in _L:
+			while ch not in _J:
 				if ch==_H:use_handle=_A;break
 				length+=1;ch=srp(length)
 			handle=_H
@@ -315,29 +302,29 @@ class Scanner:
 			else:handle=_H;self.reader.forward()
 			suffix=self.scan_tag_uri(A,start_mark)
 		ch=srp()
-		if ch not in _L:raise ScannerError('while scanning a tag',start_mark,_Z%utf8(ch),self.reader.get_mark())
+		if ch not in _J:raise ScannerError('while scanning a tag',start_mark,_R%utf8(ch),self.reader.get_mark())
 		value=handle,suffix;end_mark=self.reader.get_mark();return TagToken(value,start_mark,end_mark)
 	def scan_block_scalar(self,style,rt=_B):
-		A='|>';srp=self.reader.peek
-		if style==_R:folded=_A
+		srp=self.reader.peek
+		if style=='>':folded=_A
 		else:folded=_B
 		chunks=[];start_mark=self.reader.get_mark();self.reader.forward();chomping,increment=self.scan_block_scalar_indicators(start_mark);block_scalar_comment=self.scan_block_scalar_ignored_line(start_mark);min_indent=self.indent+1
 		if increment is _C:
-			if min_indent<1 and(style not in A or self.scanner_processing_version==(1,1)and getattr(self.loader,'top_level_block_style_scalar_no_indent_error_1_1',_B)):min_indent=1
+			if min_indent<1 and(style not in'|>'or self.scanner_processing_version==(1,1)and getattr(self.loader,'top_level_block_style_scalar_no_indent_error_1_1',_B)):min_indent=1
 			breaks,max_indent,end_mark=self.scan_block_scalar_indentation();indent=max(min_indent,max_indent)
 		else:
 			if min_indent<1:min_indent=1
 			indent=min_indent+increment-1;breaks,end_mark=self.scan_block_scalar_breaks(indent)
 		line_break=''
 		while self.reader.column==indent and srp()!=_I:
-			chunks.extend(breaks);leading_non_space=srp()not in _M;length=0
+			chunks.extend(breaks);leading_non_space=srp()not in _K;length=0
 			while srp(length)not in _THE_END:length+=1
 			chunks.append(self.reader.prefix(length));self.reader.forward(length);line_break=self.scan_line_break();breaks,end_mark=self.scan_block_scalar_breaks(indent)
-			if style in A and min_indent==0:
+			if style in'|>'and min_indent==0:
 				if self.check_document_start()or self.check_document_end():break
 			if self.reader.column==indent and srp()!=_I:
-				if rt and folded and line_break==_E:chunks.append(_i)
-				if folded and line_break==_E and leading_non_space and srp()not in _M:
+				if rt and folded and line_break==_E:chunks.append('\x07')
+				if folded and line_break==_E and leading_non_space and srp()not in _K:
 					if not breaks:chunks.append(_D)
 				else:chunks.append(line_break)
 			else:break
@@ -353,25 +340,25 @@ class Scanner:
 			comment_end_mark=self.reader.get_mark();comment=CommentToken(''.join(trailing),end_mark,comment_end_mark);token.add_post_comment(comment)
 		return token
 	def scan_block_scalar_indicators(self,start_mark):
-		D='expected indentation indicator in the range 1-9, but found 0';C='0123456789';B='+';A='+-';srp=self.reader.peek;chomping=_C;increment=_C;ch=srp()
-		if ch in A:
-			if ch==B:chomping=_A
+		B='expected indentation indicator in the range 1-9, but found 0';A='0123456789';srp=self.reader.peek;chomping=_C;increment=_C;ch=srp()
+		if ch in'+-':
+			if ch=='+':chomping=_A
 			else:chomping=_B
 			self.reader.forward();ch=srp()
-			if ch in C:
+			if ch in A:
 				increment=int(ch)
-				if increment==0:raise ScannerError(_W,start_mark,D,self.reader.get_mark())
+				if increment==0:raise ScannerError(_O,start_mark,B,self.reader.get_mark())
 				self.reader.forward()
-		elif ch in C:
+		elif ch in A:
 			increment=int(ch)
-			if increment==0:raise ScannerError(_W,start_mark,D,self.reader.get_mark())
+			if increment==0:raise ScannerError(_O,start_mark,B,self.reader.get_mark())
 			self.reader.forward();ch=srp()
-			if ch in A:
-				if ch==B:chomping=_A
+			if ch in'+-':
+				if ch=='+':chomping=_A
 				else:chomping=_B
 				self.reader.forward()
 		ch=srp()
-		if ch not in _L:raise ScannerError(_W,start_mark,'expected chomping or indentation indicators, but found %r'%utf8(ch),self.reader.get_mark())
+		if ch not in _J:raise ScannerError(_O,start_mark,'expected chomping or indentation indicators, but found %r'%utf8(ch),self.reader.get_mark())
 		return chomping,increment
 	def scan_block_scalar_ignored_line(self,start_mark):
 		srp=self.reader.peek;srf=self.reader.forward;prefix='';comment=_C
@@ -380,11 +367,11 @@ class Scanner:
 			comment=prefix
 			while srp()not in _THE_END:comment+=srp();srf()
 		ch=srp()
-		if ch not in _THE_END:raise ScannerError(_W,start_mark,_h%utf8(ch),self.reader.get_mark())
+		if ch not in _THE_END:raise ScannerError(_O,start_mark,_W%utf8(ch),self.reader.get_mark())
 		self.scan_line_break();return comment
 	def scan_block_scalar_indentation(self):
 		srp=self.reader.peek;srf=self.reader.forward;chunks=[];max_indent=0;end_mark=self.reader.get_mark()
-		while srp()in _j:
+		while srp()in _X:
 			if srp()!=_D:chunks.append(self.scan_line_break());end_mark=self.reader.get_mark()
 			else:
 				srf()
@@ -393,17 +380,17 @@ class Scanner:
 	def scan_block_scalar_breaks(self,indent):
 		chunks=[];srp=self.reader.peek;srf=self.reader.forward;end_mark=self.reader.get_mark()
 		while self.reader.column<indent and srp()==_D:srf()
-		while srp()in _X:
+		while srp()in _P:
 			chunks.append(self.scan_line_break());end_mark=self.reader.get_mark()
 			while self.reader.column<indent and srp()==_D:srf()
 		return chunks,end_mark
 	def scan_flow_scalar(self,style):
-		if style==_P:double=_A
+		if style=='"':double=_A
 		else:double=_B
 		srp=self.reader.peek;chunks=[];start_mark=self.reader.get_mark();quote=srp();self.reader.forward();chunks.extend(self.scan_flow_scalar_non_spaces(double,start_mark))
 		while srp()!=quote:chunks.extend(self.scan_flow_scalar_spaces(double,start_mark));chunks.extend(self.scan_flow_scalar_non_spaces(double,start_mark))
 		self.reader.forward();end_mark=self.reader.get_mark();return ScalarToken(''.join(chunks),_B,start_mark,end_mark,style)
-	ESCAPE_REPLACEMENTS={_K:_I,_U:_i,'b':'\x08','t':_a,_a:_a,'n':_E,'v':'\x0b','f':'\x0c','r':'\r','e':'\x1b',_D:_D,_P:_P,'/':'/',_b:_b,'N':'\x85','_':'\xa0','L':'\u2028','P':'\u2029'};ESCAPE_CODES={'x':2,'u':4,'U':8}
+	ESCAPE_REPLACEMENTS={'0':_I,'a':'\x07','b':'\x08','t':'\t','\t':'\t','n':_E,'v':'\x0b','f':'\x0c','r':'\r','e':'\x1b',_D:_D,'"':'"','/':'/','\\':'\\','N':'\x85','_':'\xa0','L':'\u2028','P':'\u2029'};ESCAPE_CODES={'x':2,'u':4,'U':8}
 	def scan_flow_scalar_non_spaces(self,double,start_mark):
 		A='while scanning a double-quoted scalar';chunks=[];srp=self.reader.peek;srf=self.reader.forward
 		while _A:
@@ -411,25 +398,25 @@ class Scanner:
 			while srp(length)not in' \n\'"\\\x00\t\r\x85\u2028\u2029':length+=1
 			if length!=0:chunks.append(self.reader.prefix(length));srf(length)
 			ch=srp()
-			if not double and ch==_J and srp(1)==_J:chunks.append(_J);srf(2)
-			elif double and ch==_J or not double and ch in'"\\':chunks.append(ch);srf()
-			elif double and ch==_b:
+			if not double and ch=="'"and srp(1)=="'":chunks.append("'");srf(2)
+			elif double and ch=="'"or not double and ch in'"\\':chunks.append(ch);srf()
+			elif double and ch=='\\':
 				srf();ch=srp()
 				if ch in self.ESCAPE_REPLACEMENTS:chunks.append(self.ESCAPE_REPLACEMENTS[ch]);srf()
 				elif ch in self.ESCAPE_CODES:
 					length=self.ESCAPE_CODES[ch];srf()
 					for k in range(length):
-						if srp(k)not in _k:raise ScannerError(A,start_mark,'expected escape sequence of %d hexdecimal numbers, but found %r'%(length,utf8(srp(k))),self.reader.get_mark())
+						if srp(k)not in _Y:raise ScannerError(A,start_mark,'expected escape sequence of %d hexdecimal numbers, but found %r'%(length,utf8(srp(k))),self.reader.get_mark())
 					code=int(self.reader.prefix(length),16);chunks.append(unichr(code));srf(length)
 				elif ch in'\n\r\x85\u2028\u2029':self.scan_line_break();chunks.extend(self.scan_flow_scalar_breaks(double,start_mark))
 				else:raise ScannerError(A,start_mark,'found unknown escape character %r'%utf8(ch),self.reader.get_mark())
 			else:return chunks
 	def scan_flow_scalar_spaces(self,double,start_mark):
 		srp=self.reader.peek;chunks=[];length=0
-		while srp(length)in _M:length+=1
+		while srp(length)in _K:length+=1
 		whitespaces=self.reader.prefix(length);self.reader.forward(length);ch=srp()
-		if ch==_I:raise ScannerError(_l,start_mark,'found unexpected end of stream',self.reader.get_mark())
-		elif ch in _X:
+		if ch==_I:raise ScannerError(_Z,start_mark,'found unexpected end of stream',self.reader.get_mark())
+		elif ch in _P:
 			line_break=self.scan_line_break();breaks=self.scan_flow_scalar_breaks(double,start_mark)
 			if line_break!=_E:chunks.append(line_break)
 			elif not breaks:chunks.append(_D)
@@ -440,9 +427,9 @@ class Scanner:
 		chunks=[];srp=self.reader.peek;srf=self.reader.forward
 		while _A:
 			prefix=self.reader.prefix(3)
-			if(prefix==_S or prefix==_T)and srp(3)in _THE_END_SPACE_TAB:raise ScannerError(_l,start_mark,'found unexpected document separator',self.reader.get_mark())
-			while srp()in _M:srf()
-			if srp()in _X:chunks.append(self.scan_line_break())
+			if(prefix==_L or prefix==_M)and srp(3)in _THE_END_SPACE_TAB:raise ScannerError(_Z,start_mark,'found unexpected document separator',self.reader.get_mark())
+			while srp()in _K:srf()
+			if srp()in _P:chunks.append(self.scan_line_break())
 			else:return chunks
 	def scan_plain(self):
 		srp=self.reader.peek;srf=self.reader.forward;chunks=[];start_mark=self.reader.get_mark();end_mark=start_mark;indent=self.indent+1;spaces=[]
@@ -451,11 +438,11 @@ class Scanner:
 			if srp()==_F:break
 			while _A:
 				ch=srp(length)
-				if ch==_O and srp(length+1)not in _THE_END_SPACE_TAB:0
+				if ch==':'and srp(length+1)not in _THE_END_SPACE_TAB:0
 				elif ch=='?'and self.scanner_processing_version!=(1,1):0
-				elif ch in _THE_END_SPACE_TAB or not self.flow_level and ch==_O and srp(length+1)in _THE_END_SPACE_TAB or self.flow_level and ch in',:?[]{}':break
+				elif ch in _THE_END_SPACE_TAB or not self.flow_level and ch==':'and srp(length+1)in _THE_END_SPACE_TAB or self.flow_level and ch in',:?[]{}':break
 				length+=1
-			if self.flow_level and ch==_O and srp(length+1)not in'\x00 \t\r\n\x85\u2028\u2029,[]{}':srf(length);raise ScannerError('while scanning a plain scalar',start_mark,"found unexpected ':'",self.reader.get_mark(),'Please check http://pyyaml.org/wiki/YAMLColonInFlowContext for details.')
+			if self.flow_level and ch==':'and srp(length+1)not in'\x00 \t\r\n\x85\u2028\u2029,[]{}':srf(length);raise ScannerError('while scanning a plain scalar',start_mark,"found unexpected ':'",self.reader.get_mark(),'Please check http://pyyaml.org/wiki/YAMLColonInFlowContext for details.')
 			if length==0:break
 			self.allow_simple_key=_B;chunks.extend(spaces);chunks.append(self.reader.prefix(length));srf(length);end_mark=self.reader.get_mark();spaces=self.scan_plain_spaces(indent,start_mark)
 			if not spaces or srp()==_F or not self.flow_level and self.reader.column<indent:break
@@ -466,15 +453,15 @@ class Scanner:
 		srp=self.reader.peek;srf=self.reader.forward;chunks=[];length=0
 		while srp(length)in _D:length+=1
 		whitespaces=self.reader.prefix(length);self.reader.forward(length);ch=srp()
-		if ch in _X:
+		if ch in _P:
 			line_break=self.scan_line_break();self.allow_simple_key=_A;prefix=self.reader.prefix(3)
-			if(prefix==_S or prefix==_T)and srp(3)in _THE_END_SPACE_TAB:return
+			if(prefix==_L or prefix==_M)and srp(3)in _THE_END_SPACE_TAB:return
 			breaks=[]
-			while srp()in _j:
+			while srp()in _X:
 				if srp()==_D:srf()
 				else:
 					breaks.append(self.scan_line_break());prefix=self.reader.prefix(3)
-					if(prefix==_S or prefix==_T)and srp(3)in _THE_END_SPACE_TAB:return
+					if(prefix==_L or prefix==_M)and srp(3)in _THE_END_SPACE_TAB:return
 			if line_break!=_E:chunks.append(line_break)
 			elif not breaks:chunks.append(_D)
 			chunks.extend(breaks)
@@ -482,16 +469,16 @@ class Scanner:
 		return chunks
 	def scan_tag_handle(self,name,start_mark):
 		A="expected '!', but found %r";srp=self.reader.peek;ch=srp()
-		if ch!=_H:raise ScannerError(_Y%(name,),start_mark,A%utf8(ch),self.reader.get_mark())
+		if ch!=_H:raise ScannerError(_Q%(name,),start_mark,A%utf8(ch),self.reader.get_mark())
 		length=1;ch=srp(length)
 		if ch!=_D:
-			while _K<=ch<=_Q or'A'<=ch<='Z'or _U<=ch<='z'or ch in'-_':length+=1;ch=srp(length)
-			if ch!=_H:self.reader.forward(length);raise ScannerError(_Y%(name,),start_mark,A%utf8(ch),self.reader.get_mark())
+			while '0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z'or ch in'-_':length+=1;ch=srp(length)
+			if ch!=_H:self.reader.forward(length);raise ScannerError(_Q%(name,),start_mark,A%utf8(ch),self.reader.get_mark())
 			length+=1
 		value=self.reader.prefix(length);self.reader.forward(length);return value
 	def scan_tag_uri(self,name,start_mark):
 		srp=self.reader.peek;chunks=[];length=0;ch=srp(length)
-		while _K<=ch<=_Q or'A'<=ch<='Z'or _U<=ch<='z'or ch in"-;/?:@&=+$,_.!~*'()[]%"or self.scanner_processing_version>(1,1)and ch==_F:
+		while '0'<=ch<='9'or'A'<=ch<='Z'or'a'<=ch<='z'or ch in"-;/?:@&=+$,_.!~*'()[]%"or self.scanner_processing_version>(1,1)and ch==_F:
 			if ch=='%':chunks.append(self.reader.prefix(length));self.reader.forward(length);length=0;chunks.append(self.scan_uri_escapes(name,start_mark))
 			else:length+=1
 			ch=srp(length)
@@ -503,22 +490,22 @@ class Scanner:
 		while srp()=='%':
 			srf()
 			for k in range(2):
-				if srp(k)not in _k:raise ScannerError(_Y%(name,),start_mark,'expected URI escape sequence of 2 hexdecimal numbers, but found %r'%utf8(srp(k)),self.reader.get_mark())
+				if srp(k)not in _Y:raise ScannerError(_Q%(name,),start_mark,'expected URI escape sequence of 2 hexdecimal numbers, but found %r'%utf8(srp(k)),self.reader.get_mark())
 			if PY3:code_bytes.append(int(self.reader.prefix(2),16))
 			else:code_bytes.append(chr(int(self.reader.prefix(2),16)))
 			srf(2)
 		try:
 			if PY3:value=bytes(code_bytes).decode(A)
 			else:value=unicode(b''.join(code_bytes),A)
-		except UnicodeDecodeError as exc:raise ScannerError(_Y%(name,),start_mark,str(exc),mark)
+		except UnicodeDecodeError as exc:raise ScannerError(_Q%(name,),start_mark,str(exc),mark)
 		return value
 	def scan_line_break(self):
 		ch=self.reader.peek()
-		if ch in _m:
-			if self.reader.prefix(2)==_n:self.reader.forward(2)
+		if ch in _a:
+			if self.reader.prefix(2)=='\r\n':self.reader.forward(2)
 			else:self.reader.forward()
 			return _E
-		elif ch in _o:self.reader.forward();return ch
+		elif ch in _b:self.reader.forward();return ch
 		return''
 class RoundTripScanner(Scanner):
 	def check_token(self,*choices):
@@ -563,7 +550,7 @@ class RoundTripScanner(Scanner):
 		self.tokens.append(CommentToken(value,start_mark,end_mark))
 	def scan_to_next_token(self):
 		srp=self.reader.peek;srf=self.reader.forward
-		if self.reader.index==0 and srp()==_f:srf()
+		if self.reader.index==0 and srp()==_U:srf()
 		found=_B
 		while not found:
 			while srp()==_D:srf()
@@ -592,11 +579,11 @@ class RoundTripScanner(Scanner):
 		return _C
 	def scan_line_break(self,empty_line=_B):
 		ch=self.reader.peek()
-		if ch in _m:
-			if self.reader.prefix(2)==_n:self.reader.forward(2)
+		if ch in _a:
+			if self.reader.prefix(2)=='\r\n':self.reader.forward(2)
 			else:self.reader.forward()
 			return _E
-		elif ch in _o:self.reader.forward();return ch
+		elif ch in _b:self.reader.forward();return ch
 		elif empty_line and ch in'\t ':self.reader.forward();return ch
 		return''
 	def scan_block_scalar(self,style,rt=_A):return Scanner.scan_block_scalar(self,style,rt=rt)
\ No newline at end of file
diff --git a/dynaconf/vendor/ruamel/yaml/serializer.py b/dynaconf/vendor/ruamel/yaml/serializer.py
index 158ca05..ffb90a6 100644
--- a/dynaconf/vendor/ruamel/yaml/serializer.py
+++ b/dynaconf/vendor/ruamel/yaml/serializer.py
@@ -1,7 +1,6 @@
 from __future__ import absolute_import
-_F='serializer is not opened'
-_E='serializer is closed'
-_D='typ'
+_E='serializer is not opened'
+_D='serializer is closed'
 _C=False
 _B=True
 _A=None
@@ -25,25 +24,25 @@ class Serializer:
 	@property
 	def emitter(self):
 		A=self
-		if hasattr(A.dumper,_D):return A.dumper.emitter
+		if hasattr(A.dumper,'typ'):return A.dumper.emitter
 		return A.dumper._emitter
 	@property
 	def resolver(self):
 		A=self
-		if hasattr(A.dumper,_D):A.dumper.resolver
+		if hasattr(A.dumper,'typ'):A.dumper.resolver
 		return A.dumper._resolver
 	def open(A):
 		if A.closed is _A:A.emitter.emit(StreamStartEvent(encoding=A.use_encoding));A.closed=_C
-		elif A.closed:raise SerializerError(_E)
+		elif A.closed:raise SerializerError(_D)
 		else:raise SerializerError('serializer is already opened')
 	def close(A):
-		if A.closed is _A:raise SerializerError(_F)
+		if A.closed is _A:raise SerializerError(_E)
 		elif not A.closed:A.emitter.emit(StreamEndEvent());A.closed=_B
 	def serialize(A,node):
 		B=node
 		if dbg(DBG_NODE):nprint('Serializing nodes');B.dump()
-		if A.closed is _A:raise SerializerError(_F)
-		elif A.closed:raise SerializerError(_E)
+		if A.closed is _A:raise SerializerError(_E)
+		elif A.closed:raise SerializerError(_D)
 		A.emitter.emit(DocumentStartEvent(explicit=A.use_explicit_start,version=A.use_version,tags=A.use_tags));A.anchor_node(B);A.serialize_node(B,_A,_A);A.emitter.emit(DocumentEndEvent(explicit=A.use_explicit_end));A.serialized_nodes={};A.anchors={};A.last_anchor_id=0
 	def anchor_node(B,node):
 		A=node
diff --git a/dynaconf/vendor/ruamel/yaml/setup.py b/dynaconf/vendor/ruamel/yaml/setup.py
index 690e172..b46b2d1 100644
--- a/dynaconf/vendor/ruamel/yaml/setup.py
+++ b/dynaconf/vendor/ruamel/yaml/setup.py
@@ -1,13 +1,11 @@
 from __future__ import print_function,absolute_import,division,unicode_literals
-_V='bdist_wheel'
-_U='--version'
-_T='extra_packages'
-_S='universal'
-_R='nested'
-_Q='setting  distdir {}/{}'
-_P='nsp'
-_O='PYDISTBASE'
-_N='True'
+_T='bdist_wheel'
+_S='--version'
+_R='extra_packages'
+_Q='universal'
+_P='nested'
+_O='setting  distdir {}/{}'
+_N='PYDISTBASE'
 _M='DVDEBUG'
 _L='LICENSE'
 _K='Jython'
@@ -47,9 +45,9 @@ if os.environ.get(_M,'')=='':
 	def debug(*args,**kw):0
 else:
 	def debug(*args,**kw):
-		with open(os.environ[_M],'a')as fp:kw1=kw.copy();kw1['file']=fp;print('{:%Y-%d-%mT%H:%M:%S}'.format(datetime.datetime.now()),file=fp,end=' ');print(*args,**kw1)
+		with open(os.environ[_M],'a')as fp:kw1=kw.copy();kw1['file']=fp;print('{:%Y-%d-%mT%H:%M:%S}'.format(datetime.datetime.now()),file=fp,end=' ');print(*(args),**kw1)
 def literal_eval(node_or_string):
-	_safe_names={'None':_A,_N:_D,'False':_C}
+	_safe_names={'None':_A,'True':_D,'False':_C}
 	if isinstance(node_or_string,string_type):node_or_string=parse(node_or_string,mode='eval')
 	if isinstance(node_or_string,Expression):node_or_string=node_or_string.body
 	else:raise TypeError('only string or AST nodes supported')
@@ -78,8 +76,8 @@ def literal_eval(node_or_string):
 			func_id=getattr(node.func,'id',_A)
 			if func_id=='dict':return dict(((k.arg,_convert(k.value))for k in node.keywords))
 			elif func_id=='set':return set(_convert(node.args[0]))
-			elif func_id=='date':return datetime.date(*[_convert(k)for k in node.args])
-			elif func_id=='datetime':return datetime.datetime(*[_convert(k)for k in node.args])
+			elif func_id=='date':return datetime.date(*([_convert(k)for k in node.args]))
+			elif func_id=='datetime':return datetime.datetime(*([_convert(k)for k in node.args]))
 		err=SyntaxError('malformed node or string: '+repr(node));err.filename='<string>';err.lineno=node.lineno;err.offset=node.col_offset;err.text=repr(node);err.node=node;raise err
 	return _convert(node_or_string)
 def _package_data(fn):
@@ -138,25 +136,25 @@ class MyInstallLib(install_lib.install_lib):
 		return alt_files
 class MySdist(_sdist):
 	def initialize_options(self):
-		_sdist.initialize_options(self);dist_base=os.environ.get(_O);fpn=getattr(getattr(self,_P,self),_I,_A)
-		if fpn and dist_base:print(_Q.format(dist_base,fpn));self.dist_dir=os.path.join(dist_base,fpn)
+		_sdist.initialize_options(self);dist_base=os.environ.get(_N);fpn=getattr(getattr(self,'nsp',self),_I,_A)
+		if fpn and dist_base:print(_O.format(dist_base,fpn));self.dist_dir=os.path.join(dist_base,fpn)
 try:
 	from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
 	class MyBdistWheel(_bdist_wheel):
 		def initialize_options(self):
-			_bdist_wheel.initialize_options(self);dist_base=os.environ.get(_O);fpn=getattr(getattr(self,_P,self),_I,_A)
-			if fpn and dist_base:print(_Q.format(dist_base,fpn));self.dist_dir=os.path.join(dist_base,fpn)
+			_bdist_wheel.initialize_options(self);dist_base=os.environ.get(_N);fpn=getattr(getattr(self,'nsp',self),_I,_A)
+			if fpn and dist_base:print(_O.format(dist_base,fpn));self.dist_dir=os.path.join(dist_base,fpn)
 	_bdist_wheel_available=_D
 except ImportError:_bdist_wheel_available=_C
 class NameSpacePackager:
 	def __init__(self,pkg_data):
-		assert isinstance(pkg_data,dict);self._pkg_data=pkg_data;self.full_package_name=self.pn(self._pkg_data[_I]);self._split=_A;self.depth=self.full_package_name.count(_B);self.nested=self._pkg_data.get(_R,_C)
+		assert isinstance(pkg_data,dict);self._pkg_data=pkg_data;self.full_package_name=self.pn(self._pkg_data[_I]);self._split=_A;self.depth=self.full_package_name.count(_B);self.nested=self._pkg_data.get(_P,_C)
 		if self.nested:NameSpaceInstaller.install_namespaces=lambda x:_A
 		self.command=_A;self.python_version();self._pkg=[_A,_A]
 		if sys.argv[0]==_F and sys.argv[1]==_J and'--single-version-externally-managed'not in sys.argv:
-			if os.environ.get('READTHEDOCS',_A)==_N:os.system('pip install .');sys.exit(0)
+			if os.environ.get('READTHEDOCS',_A)=='True':os.system('pip install .');sys.exit(0)
 			if not os.environ.get('RUAMEL_NO_PIP_INSTALL_CHECK',_C):print('error: you have to install with "pip install ."');sys.exit(1)
-		if self._pkg_data.get(_S):Distribution.is_pure=lambda *args:_D
+		if self._pkg_data.get(_Q):Distribution.is_pure=lambda *args:_D
 		else:Distribution.is_pure=lambda *args:_C
 		for x in sys.argv:
 			if x[0]=='-'or x==_F:continue
@@ -175,7 +173,7 @@ class NameSpacePackager:
 				x=os.path.join(d,_H)
 				if os.path.exists(x):
 					pd=_package_data(x)
-					if pd.get(_R,_C):skip.append(d);continue
+					if pd.get(_P,_C):skip.append(d);continue
 					self._split.append(self.full_package_name+_B+d)
 			if sys.version_info<(3,):self._split=[y.encode(_E)if isinstance(y,unicode)else y for y in self._split]
 		if skip:0
@@ -191,7 +189,7 @@ class NameSpacePackager:
 	@property
 	def package_dir(self):
 		d={self.full_package_name:_B}
-		if _T in self._pkg_data:return d
+		if _R in self._pkg_data:return d
 		if len(self.split)>1:d[self.split[0]]=self.namespace_directories(1)[0]
 		return d
 	def create_dirs(self):
@@ -266,9 +264,9 @@ class NameSpacePackager:
 	def description(self):return self._pkg_data['description']
 	@property
 	def status(self):
-		A='β';status=self._pkg_data.get('status',A).lower()
+		status=self._pkg_data.get('status','β').lower()
 		if status in['α','alpha']:return 3,'Alpha'
-		elif status in[A,'beta']:return 4,'Beta'
+		elif status in['β','beta']:return 4,'Beta'
 		elif'stable'in status.lower():return 5,'Production/Stable'
 		raise NotImplementedError
 	@property
@@ -319,14 +317,14 @@ class NameSpacePackager:
 				if isinstance(k,unicode):pd[str(k)]=pd.pop(k)
 		return pd
 	@property
-	def packages(self):s=self.split;return s+self._pkg_data.get(_T,[])
+	def packages(self):s=self.split;return s+self._pkg_data.get(_R,[])
 	@property
 	def python_requires(self):return self._pkg_data.get('python_requires',_A)
 	@property
 	def ext_modules(self):
 		I='Exception:';H='link error';G='compile error:';F='Windows';E='lib';D='src';C='ext_modules';B='test';A='name'
 		if hasattr(self,'_ext_modules'):return self._ext_modules
-		if _U in sys.argv:return _A
+		if _S in sys.argv:return _A
 		if platform.python_implementation()==_K:return _A
 		try:
 			plat=sys.argv.index('--plat-name')
@@ -363,13 +361,13 @@ class NameSpacePackager:
 	@property
 	def test_suite(self):return self._pkg_data.get('test_suite')
 	def wheel(self,kw,setup):
-		if _V not in sys.argv:return _C
+		if _T not in sys.argv:return _C
 		file_name='setup.cfg'
 		if os.path.exists(file_name):return _C
 		with open(file_name,'w')as fp:
 			if os.path.exists(_L):fp.write('[metadata]\nlicense-file = LICENSE\n')
 			else:print('\n\n>>>>>> LICENSE file not found <<<<<\n\n')
-			if self._pkg_data.get(_S):fp.write('[bdist_wheel]\nuniversal = 1\n')
+			if self._pkg_data.get(_Q):fp.write('[bdist_wheel]\nuniversal = 1\n')
 		try:setup(**kw)
 		except Exception:raise
 		finally:os.remove(file_name)
@@ -380,9 +378,9 @@ def main():
 	nsp=NameSpacePackager(pkg_data);nsp.check();nsp.create_dirs();MySdist.nsp=nsp
 	if pkg_data.get(A):MySdist.tarfmt=pkg_data.get(A)
 	cmdclass=dict(install_lib=MyInstallLib,sdist=MySdist)
-	if _bdist_wheel_available:MyBdistWheel.nsp=nsp;cmdclass[_V]=MyBdistWheel
+	if _bdist_wheel_available:MyBdistWheel.nsp=nsp;cmdclass[_T]=MyBdistWheel
 	kw=dict(name=nsp.full_package_name,namespace_packages=nsp.namespace_packages,version=version_str,packages=nsp.packages,python_requires=nsp.python_requires,url=nsp.url,author=nsp.author,author_email=nsp.author_email,cmdclass=cmdclass,package_dir=nsp.package_dir,entry_points=nsp.entry_points(),description=nsp.description,install_requires=nsp.install_requires,extras_require=nsp.extras_require,license=nsp.license,classifiers=nsp.classifiers,keywords=nsp.keywords,package_data=nsp.package_data,ext_modules=nsp.ext_modules,test_suite=nsp.test_suite)
-	if _U not in sys.argv and('--verbose'in sys.argv or dump_kw in sys.argv):
+	if _S not in sys.argv and('--verbose'in sys.argv or dump_kw in sys.argv):
 		for k in sorted(kw):v=kw[k];print('  "{0}": "{1}",'.format(k,v))
 	if dump_kw in sys.argv:sys.argv.remove(dump_kw)
 	try:
diff --git a/dynaconf/vendor/ruamel/yaml/timestamp.py b/dynaconf/vendor/ruamel/yaml/timestamp.py
index fafab94..cd1633b 100644
--- a/dynaconf/vendor/ruamel/yaml/timestamp.py
+++ b/dynaconf/vendor/ruamel/yaml/timestamp.py
@@ -1,8 +1,7 @@
 from __future__ import print_function,absolute_import,division,unicode_literals
-_A=False
 import datetime,copy
-if _A:from typing import Any,Dict,Optional,List
+if False:from typing import Any,Dict,Optional,List
 class TimeStamp(datetime.datetime):
-	def __init__(A,*B,**C):A._yaml=dict(t=_A,tz=None,delta=0)
-	def __new__(A,*B,**C):return datetime.datetime.__new__(A,*B,**C)
+	def __init__(A,*B,**C):A._yaml=dict(t=False,tz=None,delta=0)
+	def __new__(A,*B,**C):return datetime.datetime.__new__(A,*(B),**C)
 	def __deepcopy__(A,memo):B=TimeStamp(A.year,A.month,A.day,A.hour,A.minute,A.second);B._yaml=copy.deepcopy(A._yaml);return B
\ No newline at end of file
diff --git a/dynaconf/vendor/ruamel/yaml/util.py b/dynaconf/vendor/ruamel/yaml/util.py
index c8c1c6b..24f5cfc 100644
--- a/dynaconf/vendor/ruamel/yaml/util.py
+++ b/dynaconf/vendor/ruamel/yaml/util.py
@@ -1,17 +1,16 @@
 from __future__ import absolute_import,print_function
-_B='lazy_self'
-_A=' '
+_A='lazy_self'
 from functools import partial
 import re
 from .compat import text_type,binary_type
 if False:from typing import Any,Dict,Optional,List,Text;from .compat import StreamTextType
 class LazyEval:
 	def __init__(A,func,*C,**D):
-		def B():B=func(*C,**D);object.__setattr__(A,_B,lambda:B);return B
-		object.__setattr__(A,_B,B)
+		def B():B=func(*(C),**D);object.__setattr__(A,_A,lambda:B);return B
+		object.__setattr__(A,_A,B)
 	def __getattribute__(B,name):
-		A=object.__getattribute__(B,_B)
-		if name==_B:return A
+		A=object.__getattribute__(B,_A)
+		if name==_A:return A
 		return getattr(A(),name)
 	def __setattr__(A,name,value):setattr(A.lazy_self(),name,value)
 RegExp=partial(LazyEval,re.compile)
@@ -19,7 +18,7 @@ def load_yaml_guess_indent(stream,**N):
 	D=stream;B=None;from .main import round_trip_load as O
 	def K(l):
 		A=0
-		while A<len(l)and l[A]==_A:A+=1
+		while A<len(l)and l[A]==' ':A+=1
 		return A
 	if isinstance(D,text_type):F=D
 	elif isinstance(D,binary_type):F=D.decode('utf-8')
@@ -29,7 +28,7 @@ def load_yaml_guess_indent(stream,**N):
 		J=C.rstrip();P=J.lstrip()
 		if P.startswith('- '):
 			M=K(C);L=M-I;A=M+1
-			while C[A]==_A:A+=1
+			while C[A]==' ':A+=1
 			if C[A]=='#':continue
 			H=A-I;break
 		if G is B and E is not B and J:
@@ -38,7 +37,7 @@ def load_yaml_guess_indent(stream,**N):
 			if A>E:G=A-E
 		if J.endswith(':'):
 			I=K(C);A=0
-			while C[A]==_A:A+=1
+			while C[A]==' ':A+=1
 			E=A;continue
 		E=B
 	if H is B and G is not B:H=G
@@ -52,18 +51,18 @@ def configobj_walker(cfg):
 	for A in B.final_comment:
 		if A.strip():yield A
 def _walk_section(s,level=0):
-	L='  ';I="'";H='\n';F=level;from configobj import Section as J;assert isinstance(s,J);D=L*F
+	H=level;G="'";F='\n';from configobj import Section as J;assert isinstance(s,J);D='  '*H
 	for A in s.scalars:
 		for B in s.comments[A]:yield D+B.strip()
 		C=s[A]
-		if H in C:G=D+L;C='|\n'+G+C.strip().replace(H,H+G)
-		elif':'in C:C=I+C.replace(I,"''")+I
+		if F in C:I=D+'  ';C='|\n'+I+C.strip().replace(F,F+I)
+		elif':'in C:C=G+C.replace(G,"''")+G
 		E='{0}{1}: {2}'.format(D,A,C);B=s.inline_comments[A]
-		if B:E+=_A+B
+		if B:E+=' '+B
 		yield E
 	for A in s.sections:
 		for B in s.comments[A]:yield D+B.strip()
 		E='{0}{1}:'.format(D,A);B=s.inline_comments[A]
-		if B:E+=_A+B
+		if B:E+=' '+B
 		yield E
-		for K in _walk_section(s[A],level=F+1):yield K
\ No newline at end of file
+		for K in _walk_section(s[A],level=H+1):yield K
\ No newline at end of file
diff --git a/dynaconf/vendor/toml/decoder.py b/dynaconf/vendor/toml/decoder.py
index 315c36e..e003655 100644
--- a/dynaconf/vendor/toml/decoder.py
+++ b/dynaconf/vendor/toml/decoder.py
@@ -1,12 +1,6 @@
-_W='Reserved escape sequence used'
-_V='\\U'
-_U='false'
-_T='true'
-_S='\t'
-_R='}'
-_Q='+'
-_P='_'
-_O='-'
+_Q='Reserved escape sequence used'
+_P='false'
+_O='true'
 _N=','
 _M=']'
 _L=' '
@@ -56,12 +50,12 @@ class CommentValue:
 def _strictly_valid_num(n):
 	n=n.strip()
 	if not n:return _A
-	if n[0]==_P:return _A
-	if n[-1]==_P:return _A
+	if n[0]=='_':return _A
+	if n[-1]=='_':return _A
 	if'_.'in n or'._'in n:return _A
 	if len(n)==1:return _B
 	if n[0]=='0'and n[1]not in[_F,'o','b','x']:return _A
-	if n[0]==_Q or n[0]==_O:
+	if n[0]=='+'or n[0]=='-':
 		n=n[1:]
 		if len(n)>1 and n[0]=='0'and n[1]!=_F:return _A
 	if'__'in n:return _A
@@ -84,7 +78,7 @@ def load(f,_dict=dict,decoder=_E):
 		except AttributeError:raise TypeError('You can only load a file descriptor, filename or list')
 _groupname_re=re.compile('^[A-Za-z0-9_-]+$')
 def loads(s,_dict=dict,decoder=_E):
-	q="Invalid group name '";K=decoder;d=[]
+	o="Invalid group name '";K=decoder;d=[]
 	if K is _E:K=TomlDecoder(_dict)
 	e=K.get_empty_table();G=e
 	if not isinstance(s,basestring):raise TypeError('Expecting something like a string')
@@ -104,7 +98,7 @@ def loads(s,_dict=dict,decoder=_E):
 			elif O==1:
 				if E.isspace():O=2;continue
 				elif E==_F:W=_B;continue
-				elif E.isalnum()or E==_P or E==_O:continue
+				elif E.isalnum()or E=='_'or E=='-':continue
 				elif W and B[A-1]==_F and(E==_C or E==_D):J=_B;Q=E;continue
 			elif O==2:
 				if E.isspace():
@@ -168,7 +162,7 @@ def loads(s,_dict=dict,decoder=_E):
 			elif b:B[A]=_L
 			else:V=_B
 			k+=1
-		elif V and B[A]!=_L and B[A]!=_S:
+		elif V and B[A]!=_L and B[A]!='\t':
 			V=_A
 			if not U and not L:
 				if B[A]==_J:raise TomlDecodeError('Found empty keyname. ',I,A)
@@ -188,9 +182,9 @@ def loads(s,_dict=dict,decoder=_E):
 			if D[0]==_I:h=C[-1]==_M
 			elif len(C)>2:h=C[-1]==D[0]and C[-2]==D[0]and C[-3]==D[0]
 			if h:
-				try:o,r=K.load_value(D)
+				try:p,r=K.load_value(D)
 				except ValueError as Y:raise TomlDecodeError(str(Y),I,N)
-				G[T]=o;T=_E;D=''
+				G[T]=p;T=_E;D=''
 			else:
 				F=len(D)-1
 				while F>-1 and D[F]==_H:P=not P;F-=1
@@ -202,8 +196,8 @@ def loads(s,_dict=dict,decoder=_E):
 			if len(C)==1:raise TomlDecodeError('Opening key group bracket on line by itself.',I,N)
 			if C[1]==_I:L=_B;C=C[2:];Z=']]'
 			else:C=C[1:];Z=_M
-			A=1;p=K._get_split_on_quotes(C);i=_A
-			for m in p:
+			A=1;q=K._get_split_on_quotes(C);i=_A
+			for m in q:
 				if not i and Z in m:break
 				A+=m.count(Z);i=not i
 			C=C.split(Z,A)
@@ -215,10 +209,10 @@ def loads(s,_dict=dict,decoder=_E):
 					a=H[A];R=A+1
 					while not a[0]==a[-1]:
 						R+=1
-						if R>len(H)+2:raise TomlDecodeError(q+a+"' Something "+'went wrong.',I,N)
+						if R>len(H)+2:raise TomlDecodeError(o+a+"' Something "+'went wrong.',I,N)
 						a=_F.join(H[A:R]).strip()
 					H[A]=a[1:-1];H[A+1:R]=[]
-				elif not _groupname_re.match(H[A]):raise TomlDecodeError(q+H[A]+"'. Try quoting it.",I,N)
+				elif not _groupname_re.match(H[A]):raise TomlDecodeError(o+H[A]+"'. Try quoting it.",I,N)
 				A+=1
 			G=e
 			for A in _range(len(H)):
@@ -246,7 +240,7 @@ def loads(s,_dict=dict,decoder=_E):
 					try:G=G[-1]
 					except KeyError:pass
 		elif C[0]==_K:
-			if C[-1]!=_R:raise TomlDecodeError('Line breaks are not allowed in inlineobjects',I,N)
+			if C[-1]!='}':raise TomlDecodeError('Line breaks are not allowed in inlineobjects',I,N)
 			try:K.load_inline_object(C,G,T,P)
 			except ValueError as Y:raise TomlDecodeError(str(Y),I,N)
 		elif _J in C:
@@ -255,21 +249,21 @@ def loads(s,_dict=dict,decoder=_E):
 			if n is not _E:T,D,P=n
 	return e
 def _load_date(val):
-	I='Z';A=val;G=0;F=_E
+	A=val;G=0;F=_E
 	try:
 		if len(A)>19:
 			if A[19]==_F:
-				if A[-1].upper()==I:C=A[20:-1];D=I
+				if A[-1].upper()=='Z':C=A[20:-1];D='Z'
 				else:
 					B=A[20:]
-					if _Q in B:E=B.index(_Q);C=B[:E];D=B[E:]
-					elif _O in B:E=B.index(_O);C=B[:E];D=B[E:]
+					if'+'in B:E=B.index('+');C=B[:E];D=B[E:]
+					elif'-'in B:E=B.index('-');C=B[:E];D=B[E:]
 					else:D=_E;C=B
 				if D is not _E:F=TomlTz(D)
 				G=int(int(C)*10**(6-len(C)))
 			else:F=TomlTz(A[19:])
 	except ValueError:F=_E
-	if _O not in A[1:]:return _E
+	if'-'not in A[1:]:return _E
 	try:
 		if len(A)==10:H=datetime.date(int(A[:4]),int(A[5:7]),int(A[8:10]))
 		else:H=datetime.datetime(int(A[:4]),int(A[5:7]),int(A[8:10]),int(A[11:13]),int(A[14:16]),int(A[17:19]),G,F)
@@ -284,14 +278,14 @@ def _load_unicode_escapes(v,hexbytes,prefix):
 			while A>-1 and D[A]==_H:C=not C;A-=1
 			v+=E;v+=D;continue
 		B='';A=0;F=4
-		if E==_V:F=8
+		if E=='\\U':F=8
 		B=''.join(D[A:A+F]).lower()
 		if B.strip('0123456789abcdef'):raise ValueError(G+B)
 		if B[0]=='d'and B[1].strip('01234567'):raise ValueError(G+B+'. Only scalar unicode points are allowed.')
 		v+=unichr(int(B,16));v+=unicode(D[len(B):])
 	return v
 _escapes=['0','b','f','n','r','t',_C]
-_escapedchars=['\x00','\x08','\x0c',_G,'\r',_S,_C]
+_escapedchars=['\x00','\x08','\x0c',_G,'\r','\t',_C]
 _escape_to_escapedchars=dict(zip(_escapes,_escapedchars))
 def _unescape(v):
 	A=0;B=_A
@@ -301,7 +295,7 @@ def _unescape(v):
 			if v[A]in _escapes:v=v[:A-1]+_escape_to_escapedchars[v[A]]+v[A+1:]
 			elif v[A]==_H:v=v[:A-1]+v[A:]
 			elif v[A]=='u'or v[A]=='U':A+=1
-			else:raise ValueError(_W)
+			else:raise ValueError(_Q)
 			continue
 		elif v[A]==_H:B=_B
 		A+=1
@@ -321,7 +315,7 @@ class TomlDecoder:
 			try:H,A=C.split(_J,1)
 			except ValueError:raise ValueError('Invalid inline table encountered')
 			A=A.strip()
-			if A[0]==A[-1]and A[0]in(_C,_D)or(A[0]in'-0123456789'or A in(_T,_U)or A[0]==_I and A[-1]==_M or A[0]==_K and A[-1]==_R):D.append(C)
+			if A[0]==A[-1]and A[0]in(_C,_D)or(A[0]in'-0123456789'or A in(_O,_P)or A[0]==_I and A[-1]==_M or A[0]==_K and A[-1]=='}'):D.append(C)
 			elif len(B)>0:B[0]=C+_N+B[0]
 			else:raise ValueError('Invalid inline table value encountered')
 		for F in D:
@@ -340,19 +334,19 @@ class TomlDecoder:
 			else:C+=E.split(_D);D=not D
 		return C
 	def load_line(E,line,currentlevel,multikey,multibackslash):
-		S='Duplicate keys!';L=multikey;K=line;G=multibackslash;D=currentlevel;H=1;M=E._get_split_on_quotes(K);C=_A
+		P='Duplicate keys!';L=multikey;K=line;G=multibackslash;D=currentlevel;H=1;M=E._get_split_on_quotes(K);C=_A
 		for F in M:
 			if not C and _J in F:break
 			H+=F.count(_J);C=not C
 		A=K.split(_J,H);N=_strictly_valid_num(A[-1])
-		if _number_with_underscores.match(A[-1]):A[-1]=A[-1].replace(_P,'')
-		while len(A[-1])and(A[-1][0]!=_L and A[-1][0]!=_S and A[-1][0]!=_D and A[-1][0]!=_C and A[-1][0]!=_I and A[-1][0]!=_K and A[-1].strip()!=_T and A[-1].strip()!=_U):
+		if _number_with_underscores.match(A[-1]):A[-1]=A[-1].replace('_','')
+		while len(A[-1])and(A[-1][0]!=_L and A[-1][0]!='\t'and A[-1][0]!=_D and A[-1][0]!=_C and A[-1][0]!=_I and A[-1][0]!=_K and A[-1].strip()!=_O and A[-1].strip()!=_P):
 			try:float(A[-1]);break
 			except ValueError:pass
 			if _load_date(A[-1])is not _E:break
 			if TIME_RE.match(A[-1]):break
-			H+=1;P=A[-1];A=K.split(_J,H)
-			if P==A[-1]:raise ValueError('Invalid date or number')
+			H+=1;Q=A[-1];A=K.split(_J,H)
+			if Q==A[-1]:raise ValueError('Invalid date or number')
 			if N:N=_strictly_valid_num(A[-1])
 		A=[_J.join(A[:-1]).strip(),A[-1].strip()]
 		if _F in A[0]:
@@ -370,18 +364,18 @@ class TomlDecoder:
 				D=D[I]
 			A[0]=B[-1].strip()
 		elif(A[0][0]==_C or A[0][0]==_D)and A[0][-1]==A[0][0]:A[0]=_unescape(A[0][1:-1])
-		J,Q=E._load_line_multiline_str(A[1])
+		J,R=E._load_line_multiline_str(A[1])
 		if J>-1:
-			while J>-1 and A[1][J+Q]==_H:G=not G;J-=1
+			while J>-1 and A[1][J+R]==_H:G=not G;J-=1
 			if G:O=A[1][:-1]
 			else:O=A[1]+_G
 			L=A[0]
-		else:R,T=E.load_value(A[1],N)
-		try:D[A[0]];raise ValueError(S)
-		except TypeError:raise ValueError(S)
+		else:S,T=E.load_value(A[1],N)
+		try:D[A[0]];raise ValueError(P)
+		except TypeError:raise ValueError(P)
 		except KeyError:
 			if L:return L,O,G
-			else:D[A[0]]=R
+			else:D[A[0]]=S
 	def _load_line_multiline_str(C,p):
 		B=0
 		if len(p)<3:return-1,B
@@ -394,10 +388,10 @@ class TomlDecoder:
 		if len(p)>5 and p[-1]==p[0]and p[-2]==p[0]and p[-3]==p[0]:return-1,B
 		return len(p)-1,B
 	def load_value(E,v,strictly_valid=_B):
-		a='float';Z='int';Y='bool'
+		V='float';U='int';T='bool'
 		if not v:raise ValueError('Empty value is invalid')
-		if v==_T:return _B,Y
-		elif v==_U:return _A,Y
+		if v==_O:return _B,T
+		elif v==_P:return _A,T
 		elif v[0]==_C or v[0]==_D:
 			F=v[0];B=v[1:].split(F);G=_A;H=0
 			if len(B)>1 and B[0]==''and B[1]=='':B=B[2:];G=_B
@@ -417,34 +411,34 @@ class TomlDecoder:
 						elif not G or H>1:I=_B
 						else:H=0
 			if F==_C:
-				T=v.split(_H)[1:];C=_A
-				for A in T:
+				W=v.split(_H)[1:];C=_A
+				for A in W:
 					if A=='':C=not C
 					else:
-						if A[0]not in _escapes and(A[0]!='u'and A[0]!='U'and not C):raise ValueError(_W)
+						if A[0]not in _escapes and(A[0]!='u'and A[0]!='U'and not C):raise ValueError(_Q)
 						if C:C=_A
-				for L in ['\\u',_V]:
+				for L in ['\\u','\\U']:
 					if L in v:O=v.split(L);v=_load_unicode_escapes(O[0],O[1:],L)
 				v=_unescape(v)
 			if len(v)>1 and v[1]==F and(len(v)<3 or v[1]==v[2]):v=v[2:-2]
 			return v[1:-1],'str'
 		elif v[0]==_I:return E.load_array(v),'array'
 		elif v[0]==_K:P=E.get_empty_inline_table();E.load_inline_object(v,P);return P,'inline_object'
-		elif TIME_RE.match(v):U,V,W,b,Q=TIME_RE.match(v).groups();X=datetime.time(int(U),int(V),int(W),int(Q)if Q else 0);return X,'time'
+		elif TIME_RE.match(v):X,Y,Z,b,Q=TIME_RE.match(v).groups();a=datetime.time(int(X),int(Y),int(Z),int(Q)if Q else 0);return a,'time'
 		else:
 			R=_load_date(v)
 			if R is not _E:return R,'date'
 			if not strictly_valid:raise ValueError('Weirdness with leading zeroes or underscores in your number.')
-			D=Z;S=_A
-			if v[0]==_O:S=_B;v=v[1:]
-			elif v[0]==_Q:v=v[1:]
-			v=v.replace(_P,'');M=v.lower()
+			D=U;S=_A
+			if v[0]=='-':S=_B;v=v[1:]
+			elif v[0]=='+':v=v[1:]
+			v=v.replace('_','');M=v.lower()
 			if _F in v or'x'not in v and('e'in v or'E'in v):
 				if _F in v and v.split(_F,1)[1]=='':raise ValueError('This float is missing digits after the point')
 				if v[0]not in'0123456789':raise ValueError("This float doesn't have a leading digit")
-				v=float(v);D=a
-			elif len(M)==3 and(M=='inf'or M=='nan'):v=float(v);D=a
-			if D==Z:v=int(v,0)
+				v=float(v);D=V
+			elif len(M)==3 and(M=='inf'or M=='nan'):v=float(v);D=V
+			if D==U:v=int(v,0)
 			if S:return 0-v,D
 			return v,D
 	def bounded_string(C,s):
@@ -473,8 +467,8 @@ class TomlDecoder:
 							while K>-1 and a[K]==_H:F=not F;K-=1
 						F=not F
 					if not F and a[A]==_K:J+=1
-					if F or a[A]!=_R:A+=1;continue
-					elif a[A]==_R and J>1:J-=1;A+=1;continue
+					if F or a[A]!='}':A+=1;continue
+					elif a[A]=='}'and J>1:J-=1;A+=1;continue
 					A+=1;O.append(a[E:A]);E=A+1
 					while E<len(a[1:])and a[E]!=_K:E+=1
 					A=E+1
diff --git a/dynaconf/vendor/toml/encoder.py b/dynaconf/vendor/toml/encoder.py
index b77dc20..5cf8b06 100644
--- a/dynaconf/vendor/toml/encoder.py
+++ b/dynaconf/vendor/toml/encoder.py
@@ -1,9 +1,5 @@
-_G=']\n'
-_F=' = '
-_E='\n'
-_D=False
-_C='['
-_B='.'
+_C=' = '
+_B=False
 _A=None
 import datetime,re,sys
 from decimal import Decimal
@@ -24,47 +20,47 @@ def dumps(o,encoder=_A):
 		for E in D:
 			B,F=C.dump_sections(D[E],E)
 			if B or not B and not F:
-				if A and A[-2:]!='\n\n':A+=_E
-				A+=_C+E+_G
+				if A and A[-2:]!='\n\n':A+='\n'
+				A+='['+E+']\n'
 				if B:A+=B
-			for J in F:I[E+_B+J]=F[J]
+			for J in F:I[E+'.'+J]=F[J]
 		D=I
 	return A
 def _dump_str(v):
-	G="'";F='\\';C='"'
+	D='\\';B='"'
 	if sys.version_info<(3,)and hasattr(v,'decode')and isinstance(v,str):v=v.decode('utf-8')
 	v='%r'%v
 	if v[0]=='u':v=v[1:]
-	D=v.startswith(G)
-	if D or v.startswith(C):v=v[1:-1]
-	if D:v=v.replace("\\'",G);v=v.replace(C,'\\"')
+	E=v.startswith("'")
+	if E or v.startswith(B):v=v[1:-1]
+	if E:v=v.replace("\\'","'");v=v.replace(B,'\\"')
 	v=v.split('\\x')
 	while len(v)>1:
 		A=-1
 		if not v[0]:v=v[1:]
-		v[0]=v[0].replace('\\\\',F);B=v[0][A]!=F
-		while v[0][:A]and v[0][A]==F:B=not B;A-=1
-		if B:E='x'
-		else:E='u00'
-		v=[v[0]+E+v[1]]+v[2:]
-	return unicode(C+v[0]+C)
+		v[0]=v[0].replace('\\\\',D);C=v[0][A]!=D
+		while v[0][:A]and v[0][A]==D:C=not C;A-=1
+		if C:F='x'
+		else:F='u00'
+		v=[v[0]+F+v[1]]+v[2:]
+	return unicode(B+v[0]+B)
 def _dump_float(v):return '{}'.format(v).replace('e+0','e+').replace('e-0','e-')
 def _dump_time(v):
 	A=v.utcoffset()
 	if A is _A:return v.isoformat()
 	return v.isoformat()[:-6]
 class TomlEncoder:
-	def __init__(A,_dict=dict,preserve=_D):A._dict=_dict;A.preserve=preserve;A.dump_funcs={str:_dump_str,unicode:_dump_str,list:A.dump_list,bool:lambda v:unicode(v).lower(),int:lambda v:v,float:_dump_float,Decimal:_dump_float,datetime.datetime:lambda v:v.isoformat().replace('+00:00','Z'),datetime.time:_dump_time,datetime.date:lambda v:v.isoformat()}
+	def __init__(A,_dict=dict,preserve=_B):A._dict=_dict;A.preserve=preserve;A.dump_funcs={str:_dump_str,unicode:_dump_str,list:A.dump_list,bool:lambda v:unicode(v).lower(),int:lambda v:v,float:_dump_float,Decimal:_dump_float,datetime.datetime:lambda v:v.isoformat().replace('+00:00','Z'),datetime.time:_dump_time,datetime.date:lambda v:v.isoformat()}
 	def get_empty_table(A):return A._dict()
 	def dump_list(B,v):
-		A=_C
+		A='['
 		for C in v:A+=' '+unicode(B.dump_value(C))+','
 		A+=']';return A
 	def dump_inline_table(B,section):
 		A=section;C=''
 		if isinstance(A,dict):
 			D=[]
-			for (E,F) in A.items():G=B.dump_inline_table(F);D.append(E+_F+G)
+			for (E,F) in A.items():G=B.dump_inline_table(F);D.append(E+_C+G)
 			C+='{ '+', '.join(D)+' }\n';return C
 		else:return unicode(B.dump_value(A))
 	def dump_value(B,v):
@@ -73,44 +69,44 @@ class TomlEncoder:
 		return A(v)if A is not _A else B.dump_funcs[str](v)
 	def dump_sections(C,o,sup):
 		D=sup;F=''
-		if D!=''and D[-1]!=_B:D+=_B
+		if D!=''and D[-1]!='.':D+='.'
 		M=C._dict();G=''
 		for A in o:
 			A=unicode(A);B=A
 			if not re.match('^[A-Za-z0-9_-]+$',A):B=_dump_str(A)
 			if not isinstance(o[A],dict):
-				N=_D
+				N=_B
 				if isinstance(o[A],list):
 					for L in o[A]:
 						if isinstance(L,dict):N=True
 				if N:
 					for L in o[A]:
-						H=_E;G+='[['+D+B+']]\n';I,J=C.dump_sections(L,D+B)
+						H='\n';G+='[['+D+B+']]\n';I,J=C.dump_sections(L,D+B)
 						if I:
-							if I[0]==_C:H+=I
+							if I[0]=='[':H+=I
 							else:G+=I
 						while J:
 							O=C._dict()
 							for K in J:
-								E,P=C.dump_sections(J[K],D+B+_B+K)
-								if E:H+=_C+D+B+_B+K+_G;H+=E
-								for E in P:O[K+_B+E]=P[E]
+								E,P=C.dump_sections(J[K],D+B+'.'+K)
+								if E:H+='['+D+B+'.'+K+']\n';H+=E
+								for E in P:O[K+'.'+E]=P[E]
 							J=O
 						G+=H
-				elif o[A]is not _A:F+=B+_F+unicode(C.dump_value(o[A]))+_E
-			elif C.preserve and isinstance(o[A],InlineTableDict):F+=B+_F+C.dump_inline_table(o[A])
+				elif o[A]is not _A:F+=B+_C+unicode(C.dump_value(o[A]))+'\n'
+			elif C.preserve and isinstance(o[A],InlineTableDict):F+=B+_C+C.dump_inline_table(o[A])
 			else:M[B]=o[A]
 		F+=G;return F,M
 class TomlPreserveInlineDictEncoder(TomlEncoder):
 	def __init__(A,_dict=dict):super(TomlPreserveInlineDictEncoder,A).__init__(_dict,True)
 class TomlArraySeparatorEncoder(TomlEncoder):
-	def __init__(B,_dict=dict,preserve=_D,separator=','):
+	def __init__(B,_dict=dict,preserve=_B,separator=','):
 		A=separator;super(TomlArraySeparatorEncoder,B).__init__(_dict,preserve)
 		if A.strip()=='':A=','+A
 		elif A.strip(' \t\n\r,'):raise ValueError('Invalid separator for arrays')
 		B.separator=A
 	def dump_list(D,v):
-		B=[];C=_C
+		B=[];C='['
 		for A in v:B.append(D.dump_value(A))
 		while B!=[]:
 			E=[]
@@ -121,10 +117,10 @@ class TomlArraySeparatorEncoder(TomlEncoder):
 			B=E
 		C+=']';return C
 class TomlNumpyEncoder(TomlEncoder):
-	def __init__(A,_dict=dict,preserve=_D):import numpy as B;super(TomlNumpyEncoder,A).__init__(_dict,preserve);A.dump_funcs[B.float16]=_dump_float;A.dump_funcs[B.float32]=_dump_float;A.dump_funcs[B.float64]=_dump_float;A.dump_funcs[B.int16]=A._dump_int;A.dump_funcs[B.int32]=A._dump_int;A.dump_funcs[B.int64]=A._dump_int
+	def __init__(A,_dict=dict,preserve=_B):import numpy as B;super(TomlNumpyEncoder,A).__init__(_dict,preserve);A.dump_funcs[B.float16]=_dump_float;A.dump_funcs[B.float32]=_dump_float;A.dump_funcs[B.float64]=_dump_float;A.dump_funcs[B.int16]=A._dump_int;A.dump_funcs[B.int32]=A._dump_int;A.dump_funcs[B.int64]=A._dump_int
 	def _dump_int(A,v):return '{}'.format(int(v))
 class TomlPreserveCommentEncoder(TomlEncoder):
-	def __init__(A,_dict=dict,preserve=_D):from dynaconf.vendor.toml.decoder import CommentValue as B;super(TomlPreserveCommentEncoder,A).__init__(_dict,preserve);A.dump_funcs[B]=lambda v:v.dump(A.dump_value)
+	def __init__(A,_dict=dict,preserve=_B):from dynaconf.vendor.toml.decoder import CommentValue as B;super(TomlPreserveCommentEncoder,A).__init__(_dict,preserve);A.dump_funcs[B]=lambda v:v.dump(A.dump_value)
 class TomlPathlibEncoder(TomlEncoder):
 	def _dump_pathlib_path(A,v):return _dump_str(str(v))
 	def dump_value(A,v):
diff --git a/dynaconf/vendor/tomllib/__init__.py b/dynaconf/vendor/tomllib/__init__.py
new file mode 100644
index 0000000..663689e
--- /dev/null
+++ b/dynaconf/vendor/tomllib/__init__.py
@@ -0,0 +1,4 @@
+__all__='loads','load','TOMLDecodeError','dump','dumps'
+from ._parser import TOMLDecodeError,load,loads
+from ._writer import dump,dumps
+TOMLDecodeError.__module__=__name__
\ No newline at end of file
diff --git a/dynaconf/vendor/tomllib/_parser.py b/dynaconf/vendor/tomllib/_parser.py
new file mode 100644
index 0000000..b0c4912
--- /dev/null
+++ b/dynaconf/vendor/tomllib/_parser.py
@@ -0,0 +1,298 @@
+from __future__ import annotations
+_H='flags'
+_G='Cannot overwrite a value'
+_F='recursive_flags'
+_E='nested'
+_D='\n'
+_C=False
+_B=None
+_A=True
+from collections.abc import Iterable
+import string
+from types import MappingProxyType
+from typing import Any,BinaryIO,NamedTuple
+from ._re import RE_DATETIME,RE_LOCALTIME,RE_NUMBER,match_to_datetime,match_to_localtime,match_to_number
+from ._types import Key,ParseFloat,Pos
+ASCII_CTRL=frozenset((chr(A)for A in range(32)))|frozenset(chr(127))
+ILLEGAL_BASIC_STR_CHARS=ASCII_CTRL-frozenset('\t')
+ILLEGAL_MULTILINE_BASIC_STR_CHARS=ASCII_CTRL-frozenset('\t\n')
+ILLEGAL_LITERAL_STR_CHARS=ILLEGAL_BASIC_STR_CHARS
+ILLEGAL_MULTILINE_LITERAL_STR_CHARS=ILLEGAL_MULTILINE_BASIC_STR_CHARS
+ILLEGAL_COMMENT_CHARS=ILLEGAL_BASIC_STR_CHARS
+TOML_WS=frozenset(' \t')
+TOML_WS_AND_NEWLINE=TOML_WS|frozenset(_D)
+BARE_KEY_CHARS=frozenset(string.ascii_letters+string.digits+'-_')
+KEY_INITIAL_CHARS=BARE_KEY_CHARS|frozenset('"\'')
+HEXDIGIT_CHARS=frozenset(string.hexdigits)
+BASIC_STR_ESCAPE_REPLACEMENTS=MappingProxyType({'\\b':'\x08','\\t':'\t','\\n':_D,'\\f':'\x0c','\\r':'\r','\\"':'"','\\\\':'\\'})
+class TOMLDecodeError(ValueError):0
+def load(A,*,parse_float=float):
+	B=A.read()
+	try:C=B.decode()
+	except AttributeError:raise TypeError("File must be opened in binary mode, e.g. use `open('foo.toml', 'rb')`") from _B
+	return loads(C,parse_float=parse_float)
+def loads(H,*,parse_float=float):
+	E=parse_float;B=H.replace('\r\n',_D);A=0;D=Output(NestedDict(),Flags());F=();E=make_safe_parse_float(E)
+	while _A:
+		A=skip_chars(B,A,TOML_WS)
+		try:C=B[A]
+		except IndexError:break
+		if C==_D:A+=1;continue
+		if C in KEY_INITIAL_CHARS:A=key_value_rule(B,A,D,F,E);A=skip_chars(B,A,TOML_WS)
+		elif C=='[':
+			try:G=B[A+1]
+			except IndexError:G=_B
+			D.flags.finalize_pending()
+			if G=='[':A,F=create_list_rule(B,A,D)
+			else:A,F=create_dict_rule(B,A,D)
+			A=skip_chars(B,A,TOML_WS)
+		elif C!='#':raise suffixed_err(B,A,'Invalid statement')
+		A=skip_comment(B,A)
+		try:C=B[A]
+		except IndexError:break
+		if C!=_D:raise suffixed_err(B,A,'Expected newline or end of document after a statement')
+		A+=1
+	return D.data.dict
+class Flags:
+	FROZEN=0;EXPLICIT_NEST=1
+	def __init__(A):A._flags={};A._pending_flags=set()
+	def add_pending(A,key,flag):A._pending_flags.add((key,flag))
+	def finalize_pending(A):
+		for (B,C) in A._pending_flags:A.set(B,C,recursive=_C)
+		A._pending_flags.clear()
+	def unset_all(C,key):
+		A=C._flags
+		for B in key[:-1]:
+			if B not in A:return
+			A=A[B][_E]
+		A.pop(key[-1],_B)
+	def set(D,key,flag,*,recursive):
+		A=D._flags;E,B=key[:-1],key[-1]
+		for C in E:
+			if C not in A:A[C]={_H:set(),_F:set(),_E:{}}
+			A=A[C][_E]
+		if B not in A:A[B]={_H:set(),_F:set(),_E:{}}
+		A[B][_F if recursive else _H].add(flag)
+	def is_(G,key,flag):
+		C=flag;B=key
+		if not B:return _C
+		A=G._flags
+		for D in B[:-1]:
+			if D not in A:return _C
+			E=A[D]
+			if C in E[_F]:return _A
+			A=E[_E]
+		F=B[-1]
+		if F in A:A=A[F];return C in A[_H]or C in A[_F]
+		return _C
+class NestedDict:
+	def __init__(A):A.dict={}
+	def get_or_create_nest(C,key,*,access_lists=_A):
+		A=C.dict
+		for B in key:
+			if B not in A:A[B]={}
+			A=A[B]
+			if access_lists and isinstance(A,list):A=A[-1]
+			if not isinstance(A,dict):raise KeyError('There is no nest behind this key')
+		return A
+	def append_nest_to_list(D,key):
+		A=D.get_or_create_nest(key[:-1]);B=key[-1]
+		if B in A:
+			C=A[B]
+			if not isinstance(C,list):raise KeyError('An object other than list found behind this key')
+			C.append({})
+		else:A[B]=[{}]
+class Output(NamedTuple):data:NestedDict;flags:Flags
+def skip_chars(src,pos,chars):
+	A=pos
+	try:
+		while src[A]in chars:A+=1
+	except IndexError:pass
+	return A
+def skip_until(src,pos,expect,*,error_on,error_on_eof):
+	E=error_on;D=expect;B=pos;A=src
+	try:C=A.index(D,B)
+	except ValueError:
+		C=len(A)
+		if error_on_eof:raise suffixed_err(A,C,f"Expected {D!r}") from _B
+	if not E.isdisjoint(A[B:C]):
+		while A[B]not in E:B+=1
+		raise suffixed_err(A,B,f"Found invalid character {A[B]!r}")
+	return C
+def skip_comment(src,pos):
+	A=pos
+	try:B=src[A]
+	except IndexError:B=_B
+	if B=='#':return skip_until(src,A+1,_D,error_on=ILLEGAL_COMMENT_CHARS,error_on_eof=_C)
+	return A
+def skip_comments_and_array_ws(src,pos):
+	A=pos
+	while _A:
+		B=A;A=skip_chars(src,A,TOML_WS_AND_NEWLINE);A=skip_comment(src,A)
+		if A==B:return A
+def create_dict_rule(src,pos,out):
+	D=out;B=src;A=pos;A+=1;A=skip_chars(B,A,TOML_WS);A,C=parse_key(B,A)
+	if D.flags.is_(C,Flags.EXPLICIT_NEST)or D.flags.is_(C,Flags.FROZEN):raise suffixed_err(B,A,f"Cannot declare {C} twice")
+	D.flags.set(C,Flags.EXPLICIT_NEST,recursive=_C)
+	try:D.data.get_or_create_nest(C)
+	except KeyError:raise suffixed_err(B,A,_G) from _B
+	if not B.startswith(']',A):raise suffixed_err(B,A,"Expected ']' at the end of a table declaration")
+	return A+1,C
+def create_list_rule(src,pos,out):
+	D=out;B=src;A=pos;A+=2;A=skip_chars(B,A,TOML_WS);A,C=parse_key(B,A)
+	if D.flags.is_(C,Flags.FROZEN):raise suffixed_err(B,A,f"Cannot mutate immutable namespace {C}")
+	D.flags.unset_all(C);D.flags.set(C,Flags.EXPLICIT_NEST,recursive=_C)
+	try:D.data.append_nest_to_list(C)
+	except KeyError:raise suffixed_err(B,A,_G) from _B
+	if not B.startswith(']]',A):raise suffixed_err(B,A,"Expected ']]' at the end of an array declaration")
+	return A+2,C
+def key_value_rule(src,pos,out,header,parse_float):
+	E=header;C=out;B=src;A=pos;A,D,H=parse_key_value_pair(B,A,parse_float);K,I=D[:-1],D[-1];F=E+K;L=(E+D[:A]for A in range(1,len(D)))
+	for G in L:
+		if C.flags.is_(G,Flags.EXPLICIT_NEST):raise suffixed_err(B,A,f"Cannot redefine namespace {G}")
+		C.flags.add_pending(G,Flags.EXPLICIT_NEST)
+	if C.flags.is_(F,Flags.FROZEN):raise suffixed_err(B,A,f"Cannot mutate immutable namespace {F}")
+	try:J=C.data.get_or_create_nest(F)
+	except KeyError:raise suffixed_err(B,A,_G) from _B
+	if I in J:raise suffixed_err(B,A,_G)
+	if isinstance(H,(dict,list)):C.flags.set(E+D,Flags.FROZEN,recursive=_A)
+	J[I]=H;return A
+def parse_key_value_pair(src,pos,parse_float):
+	B=src;A=pos;A,D=parse_key(B,A)
+	try:C=B[A]
+	except IndexError:C=_B
+	if C!='=':raise suffixed_err(B,A,"Expected '=' after a key in a key/value pair")
+	A+=1;A=skip_chars(B,A,TOML_WS);A,E=parse_value(B,A,parse_float);return A,D,E
+def parse_key(src,pos):
+	B=src;A=pos;A,C=parse_key_part(B,A);D=C,;A=skip_chars(B,A,TOML_WS)
+	while _A:
+		try:E=B[A]
+		except IndexError:E=_B
+		if E!='.':return A,D
+		A+=1;A=skip_chars(B,A,TOML_WS);A,C=parse_key_part(B,A);D+=C,;A=skip_chars(B,A,TOML_WS)
+def parse_key_part(src,pos):
+	B=src;A=pos
+	try:C=B[A]
+	except IndexError:C=_B
+	if C in BARE_KEY_CHARS:D=A;A=skip_chars(B,A,BARE_KEY_CHARS);return A,B[D:A]
+	if C=="'":return parse_literal_str(B,A)
+	if C=='"':return parse_one_line_basic_str(B,A)
+	raise suffixed_err(B,A,'Invalid initial character for a key part')
+def parse_one_line_basic_str(src,pos):pos+=1;return parse_basic_str(src,pos,multiline=_C)
+def parse_array(src,pos,parse_float):
+	B=src;A=pos;A+=1;C=[];A=skip_comments_and_array_ws(B,A)
+	if B.startswith(']',A):return A+1,C
+	while _A:
+		A,E=parse_value(B,A,parse_float);C.append(E);A=skip_comments_and_array_ws(B,A);D=B[A:A+1]
+		if D==']':return A+1,C
+		if D!=',':raise suffixed_err(B,A,'Unclosed array')
+		A+=1;A=skip_comments_and_array_ws(B,A)
+		if B.startswith(']',A):return A+1,C
+def parse_inline_table(src,pos,parse_float):
+	B=src;A=pos;A+=1;D=NestedDict();F=Flags();A=skip_chars(B,A,TOML_WS)
+	if B.startswith('}',A):return A+1,D.dict
+	while _A:
+		A,C,G=parse_key_value_pair(B,A,parse_float);J,E=C[:-1],C[-1]
+		if F.is_(C,Flags.FROZEN):raise suffixed_err(B,A,f"Cannot mutate immutable namespace {C}")
+		try:H=D.get_or_create_nest(J,access_lists=_C)
+		except KeyError:raise suffixed_err(B,A,_G) from _B
+		if E in H:raise suffixed_err(B,A,f"Duplicate inline table key {E!r}")
+		H[E]=G;A=skip_chars(B,A,TOML_WS);I=B[A:A+1]
+		if I=='}':return A+1,D.dict
+		if I!=',':raise suffixed_err(B,A,'Unclosed inline table')
+		if isinstance(G,(dict,list)):F.set(C,Flags.FROZEN,recursive=_A)
+		A+=1;A=skip_chars(B,A,TOML_WS)
+def parse_basic_str_escape(src,pos,*,multiline=_C):
+	E="Unescaped '\\' in a string";D='\\\n';B=src;A=pos;C=B[A:A+2];A+=2
+	if multiline and C in{'\\ ','\\\t',D}:
+		if C!=D:
+			A=skip_chars(B,A,TOML_WS)
+			try:F=B[A]
+			except IndexError:return A,''
+			if F!=_D:raise suffixed_err(B,A,E)
+			A+=1
+		A=skip_chars(B,A,TOML_WS_AND_NEWLINE);return A,''
+	if C=='\\u':return parse_hex_char(B,A,4)
+	if C=='\\U':return parse_hex_char(B,A,8)
+	try:return A,BASIC_STR_ESCAPE_REPLACEMENTS[C]
+	except KeyError:raise suffixed_err(B,A,E) from _B
+def parse_basic_str_escape_multiline(src,pos):return parse_basic_str_escape(src,pos,multiline=_A)
+def parse_hex_char(src,pos,hex_len):
+	C=hex_len;B=src;A=pos;D=B[A:A+C]
+	if len(D)!=C or not HEXDIGIT_CHARS.issuperset(D):raise suffixed_err(B,A,'Invalid hex value')
+	A+=C;E=int(D,16)
+	if not is_unicode_scalar_value(E):raise suffixed_err(B,A,'Escaped character is not a Unicode scalar value')
+	return A,chr(E)
+def parse_literal_str(src,pos):A=pos;A+=1;B=A;A=skip_until(src,A,"'",error_on=ILLEGAL_LITERAL_STR_CHARS,error_on_eof=_A);return A+1,src[B:A]
+def parse_multiline_str(src,pos,*,literal):
+	B=src;A=pos;A+=3
+	if B.startswith(_D,A):A+=1
+	if literal:C="'";E=skip_until(B,A,"'''",error_on=ILLEGAL_MULTILINE_LITERAL_STR_CHARS,error_on_eof=_A);D=B[A:E];A=E+3
+	else:C='"';A,D=parse_basic_str(B,A,multiline=_A)
+	if not B.startswith(C,A):return A,D
+	A+=1
+	if not B.startswith(C,A):return A,D+C
+	A+=1;return A,D+C*2
+def parse_basic_str(src,pos,*,multiline):
+	F=multiline;B=src;A=pos
+	if F:G=ILLEGAL_MULTILINE_BASIC_STR_CHARS;H=parse_basic_str_escape_multiline
+	else:G=ILLEGAL_BASIC_STR_CHARS;H=parse_basic_str_escape
+	C='';D=A
+	while _A:
+		try:E=B[A]
+		except IndexError:raise suffixed_err(B,A,'Unterminated string') from _B
+		if E=='"':
+			if not F:return A+1,C+B[D:A]
+			if B.startswith('"""',A):return A+3,C+B[D:A]
+			A+=1;continue
+		if E=='\\':C+=B[D:A];A,I=H(B,A);C+=I;D=A;continue
+		if E in G:raise suffixed_err(B,A,f"Illegal character {E!r}")
+		A+=1
+def parse_value(src,pos,parse_float):
+	D=parse_float;B=src;A=pos
+	try:C=B[A]
+	except IndexError:C=_B
+	if C=='"':
+		if B.startswith('"""',A):return parse_multiline_str(B,A,literal=_C)
+		return parse_one_line_basic_str(B,A)
+	if C=="'":
+		if B.startswith("'''",A):return parse_multiline_str(B,A,literal=_A)
+		return parse_literal_str(B,A)
+	if C=='t':
+		if B.startswith('true',A):return A+4,_A
+	if C=='f':
+		if B.startswith('false',A):return A+5,_C
+	if C=='[':return parse_array(B,A,D)
+	if C=='{':return parse_inline_table(B,A,D)
+	E=RE_DATETIME.match(B,A)
+	if E:
+		try:J=match_to_datetime(E)
+		except ValueError as K:raise suffixed_err(B,A,'Invalid date or datetime') from K
+		return E.end(),J
+	F=RE_LOCALTIME.match(B,A)
+	if F:return F.end(),match_to_localtime(F)
+	G=RE_NUMBER.match(B,A)
+	if G:return G.end(),match_to_number(G,D)
+	H=B[A:A+3]
+	if H in{'inf','nan'}:return A+3,D(H)
+	I=B[A:A+4]
+	if I in{'-inf','+inf','-nan','+nan'}:return A+4,D(I)
+	raise suffixed_err(B,A,'Invalid value')
+def suffixed_err(src,pos,msg):
+	def A(src,pos):
+		B=src;A=pos
+		if A>=len(B):return'end of document'
+		C=B.count(_D,0,A)+1
+		if C==1:D=A+1
+		else:D=A-B.rindex(_D,0,A)
+		return f"line {C}, column {D}"
+	return TOMLDecodeError(f"{msg} (at {A(src,pos)})")
+def is_unicode_scalar_value(codepoint):A=codepoint;return 0<=A<=55295 or 57344<=A<=1114111
+def make_safe_parse_float(parse_float):
+	A=parse_float
+	if A is float:return float
+	def B(float_str):
+		B=A(float_str)
+		if isinstance(B,(dict,list)):raise ValueError('parse_float must not return dicts or lists')
+		return B
+	return B
\ No newline at end of file
diff --git a/dynaconf/vendor/tomllib/_re.py b/dynaconf/vendor/tomllib/_re.py
new file mode 100644
index 0000000..da26ba2
--- /dev/null
+++ b/dynaconf/vendor/tomllib/_re.py
@@ -0,0 +1,32 @@
+from __future__ import annotations
+from datetime import date,datetime,time,timedelta,timezone,tzinfo
+from functools import lru_cache
+import re
+from typing import Any
+from ._types import ParseFloat
+_TIME_RE_STR='([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\\.([0-9]{1,6})[0-9]*)?'
+RE_NUMBER=re.compile('\n0\n(?:\n    x[0-9A-Fa-f](?:_?[0-9A-Fa-f])*   # hex\n    |\n    b[01](?:_?[01])*                 # bin\n    |\n    o[0-7](?:_?[0-7])*               # oct\n)\n|\n[+-]?(?:0|[1-9](?:_?[0-9])*)         # dec, integer part\n(?P<floatpart>\n    (?:\\.[0-9](?:_?[0-9])*)?         # optional fractional part\n    (?:[eE][+-]?[0-9](?:_?[0-9])*)?  # optional exponent part\n)\n',flags=re.VERBOSE)
+RE_LOCALTIME=re.compile(_TIME_RE_STR)
+RE_DATETIME=re.compile(f"""
+([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])  # date, e.g. 1988-10-27
+(?:
+    [Tt ]
+    {_TIME_RE_STR}
+    (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))?  # optional time offset
+)?
+""",flags=re.VERBOSE)
+def match_to_datetime(match):
+	H,I,J,B,K,L,C,M,D,N,O=match.groups();E,F,G=int(H),int(I),int(J)
+	if B is None:return date(E,F,G)
+	P,Q,R=int(B),int(K),int(L);S=int(C.ljust(6,'0'))if C else 0
+	if D:A=cached_tz(N,O,D)
+	elif M:A=timezone.utc
+	else:A=None
+	return datetime(E,F,G,P,Q,R,S,tzinfo=A)
+@lru_cache(maxsize=None)
+def cached_tz(hour_str,minute_str,sign_str):A=1 if sign_str=='+'else-1;return timezone(timedelta(hours=A*int(hour_str),minutes=A*int(minute_str)))
+def match_to_localtime(match):B,C,D,A=match.groups();E=int(A.ljust(6,'0'))if A else 0;return time(int(B),int(C),int(D),E)
+def match_to_number(match,parse_float):
+	A=match
+	if A.group('floatpart'):return parse_float(A.group())
+	return int(A.group(),0)
\ No newline at end of file
diff --git a/dynaconf/vendor/tomllib/_types.py b/dynaconf/vendor/tomllib/_types.py
new file mode 100644
index 0000000..1fe9083
--- /dev/null
+++ b/dynaconf/vendor/tomllib/_types.py
@@ -0,0 +1,4 @@
+from typing import Any,Callable,Tuple
+ParseFloat=Callable[[str],Any]
+Key=Tuple[str,...]
+Pos=int
\ No newline at end of file
diff --git a/dynaconf/vendor/tomllib/_writer.py b/dynaconf/vendor/tomllib/_writer.py
new file mode 100644
index 0000000..887bd21
--- /dev/null
+++ b/dynaconf/vendor/tomllib/_writer.py
@@ -0,0 +1,89 @@
+from __future__ import annotations
+_C=True
+_B=False
+_A='\n'
+from collections.abc import Generator,Mapping
+from datetime import date,datetime,time
+from decimal import Decimal
+import string
+from types import MappingProxyType
+from typing import Any,BinaryIO,NamedTuple
+ASCII_CTRL=frozenset((chr(A)for A in range(32)))|frozenset(chr(127))
+ILLEGAL_BASIC_STR_CHARS=frozenset('"\\')|ASCII_CTRL-frozenset('\t')
+BARE_KEY_CHARS=frozenset(string.ascii_letters+string.digits+'-_')
+ARRAY_TYPES=list,tuple
+ARRAY_INDENT=' '*4
+MAX_LINE_LENGTH=100
+COMPACT_ESCAPES=MappingProxyType({'\x08':'\\b',_A:'\\n','\x0c':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'})
+def dump(__obj,__fp,*,multiline_strings=_B):
+	A=Context(multiline_strings,{})
+	for B in gen_table_chunks(__obj,A,name=''):__fp.write(B.encode())
+def dumps(__obj,*,multiline_strings=_B):A=Context(multiline_strings,{});return ''.join(gen_table_chunks(__obj,A,name=''))
+class Context(NamedTuple):allow_multiline:bool;inline_table_cache:dict[int,str]
+def gen_table_chunks(table,ctx,*,name,inside_aot=_B):
+	H=inside_aot;G=ctx;C=name;D=_B;E=[];F=[]
+	for (B,A) in table.items():
+		if isinstance(A,dict):F.append((B,A,_B))
+		elif is_aot(A)and not all((is_suitable_inline_table(B,G)for B in A)):F.extend(((B,C,_C)for C in A))
+		else:E.append((B,A))
+	if H or C and(E or not F):D=_C;yield f"[[{C}]]\n"if H else f"[{C}]\n"
+	if E:
+		D=_C
+		for (B,A) in E:yield f"{format_key_part(B)} = {format_literal(A,G)}\n"
+	for (B,A,J) in F:
+		if D:yield _A
+		else:D=_C
+		I=format_key_part(B);K=f"{C}.{I}"if C else I;yield from gen_table_chunks(A,G,name=K,inside_aot=J)
+def format_literal(obj,ctx,*,nest_level=0):
+	B=ctx;A=obj
+	if isinstance(A,bool):return'true'if A else'false'
+	if isinstance(A,(int,float,date,datetime)):return str(A)
+	if isinstance(A,Decimal):return format_decimal(A)
+	if isinstance(A,time):
+		if A.tzinfo:raise ValueError('TOML does not support offset times')
+		return str(A)
+	if isinstance(A,str):return format_string(A,allow_multiline=B.allow_multiline)
+	if isinstance(A,ARRAY_TYPES):return format_inline_array(A,B,nest_level)
+	if isinstance(A,dict):return format_inline_table(A,B)
+	raise TypeError(f"Object of type {type(A)} is not TOML serializable")
+def format_decimal(obj):
+	C='-inf';B='inf';A=obj
+	if A.is_nan():return'nan'
+	if A==Decimal(B):return B
+	if A==Decimal(C):return C
+	return str(A)
+def format_inline_table(obj,ctx):
+	B=obj;A=ctx;C=id(B)
+	if C in A.inline_table_cache:return A.inline_table_cache[C]
+	if not B:D='{}'
+	else:D='{ '+', '.join((f"{format_key_part(C)} = {format_literal(D,A)}"for(C,D)in B.items()))+' }'
+	A.inline_table_cache[C]=D;return D
+def format_inline_array(obj,ctx,nest_level):
+	A=nest_level
+	if not obj:return'[]'
+	B=ARRAY_INDENT*(1+A);C=ARRAY_INDENT*A;return'[\n'+',\n'.join((B+format_literal(C,ctx,nest_level=A+1)for C in obj))+f",\n{C}]"
+def format_key_part(part):
+	A=part
+	if A and BARE_KEY_CHARS.issuperset(A):return A
+	return format_string(A,allow_multiline=_B)
+def format_string(s,*,allow_multiline):
+	D=allow_multiline and _A in s
+	if D:A='"""\n';s=s.replace('\r\n',_A)
+	else:A='"'
+	B=E=0
+	while _C:
+		try:C=s[B]
+		except IndexError:
+			A+=s[E:B]
+			if D:return A+'"""'
+			return A+'"'
+		if C in ILLEGAL_BASIC_STR_CHARS:
+			A+=s[E:B]
+			if C in COMPACT_ESCAPES:
+				if D and C==_A:A+=_A
+				else:A+=COMPACT_ESCAPES[C]
+			else:A+='\\u'+hex(ord(C))[2:].rjust(4,'0')
+			E=B+1
+		B+=1
+def is_aot(obj):A=obj;return bool(isinstance(A,ARRAY_TYPES)and A and all((isinstance(B,dict)for B in A)))
+def is_suitable_inline_table(obj,ctx):A=f"{ARRAY_INDENT}{format_inline_table(obj,ctx)},";return len(A)<=MAX_LINE_LENGTH and _A not in A
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
index e91517f..3947dfa 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,16 @@
 [bdist_wheel]
 universal = 1
 
+[flake8]
+ignore = F403
+	W504
+	W503
+	F841
+	E401
+	F401
+	E402
+max-line-length = 79
+
 [mypy]
 ignore_missing_imports = True
 
diff --git a/setup.py b/setup.py
index 959ee73..2e6533e 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
-import io
+from __future__ import annotations
+
 import os
-import sys
 
 from setuptools import find_packages
 from setuptools import setup
@@ -9,7 +9,7 @@ from setuptools import setup
 def read(*names, **kwargs):
     """Read a file."""
     content = ""
-    with io.open(
+    with open(
         os.path.join(os.path.dirname(__file__), *names),
         encoding=kwargs.get("encoding", "utf8"),
     ) as open_file:
@@ -17,11 +17,34 @@ def read(*names, **kwargs):
     return content
 
 
+test_requirements = [
+    "pytest",
+    "pytest-cov",
+    "pytest-xdist",
+    "pytest-mock",
+    "flake8",
+    "pep8-naming",
+    "flake8-debugger",
+    "flake8-print",
+    "flake8-todo",
+    "radon",
+    "flask>=0.12",
+    "django",
+    "python-dotenv",
+    "toml",
+    "codecov",
+    "redis",
+    "hvac",
+    "configobj",
+]
+
+
 setup(
     name="dynaconf",
     version=read("dynaconf", "VERSION"),
-    url="https://github.com/rochacbruno/dynaconf",
+    url="https://github.com/dynaconf/dynaconf",
     license="MIT",
+    license_files=["LICENSE", "vendor_licenses/*"],
     author="Bruno Rocha",
     author_email="rochacbruno@gmail.com",
     description="The dynamic configurator for your Python Project",
@@ -31,8 +54,8 @@ setup(
         exclude=[
             "tests",
             "tests.*",
-            "example",
-            "example.*",
+            "tests_functional",
+            "tests_functional.*",
             "docs",
             "legacy_docs",
             "legacy_docs.*",
@@ -48,22 +71,7 @@ setup(
     include_package_data=True,
     zip_safe=False,
     platforms="any",
-    install_requires=["typing; python_version<'3.5'"],
-    tests_require=[
-        "pytest",
-        "pytest-cov",
-        "pytest-xdist",
-        "flake8",
-        "pep8-naming",
-        "flake8-debugger",
-        "flake8-print",
-        "flake8-todo",
-        "radon",
-        "flask>=0.12",
-        "python-dotenv",
-        "toml",
-        "codecov",
-    ],
+    tests_require=test_requirements,
     extras_require={
         "redis": ["redis"],
         "vault": ["hvac"],
@@ -72,8 +80,9 @@ setup(
         "ini": ["configobj"],
         "configobj": ["configobj"],
         "all": ["redis", "ruamel.yaml", "configobj", "hvac"],
+        "test": test_requirements,
     },
-    python_requires=">=3.7",
+    python_requires=">=3.8",
     entry_points={"console_scripts": ["dynaconf=dynaconf.cli:main"]},
     setup_requires=["setuptools>=38.6.0"],
     classifiers=[
@@ -87,9 +96,10 @@ setup(
         "Programming Language :: Python",
         "Programming Language :: Python :: 3",
         "Programming Language :: Python :: 3 :: Only",
-        "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.8",
         "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
+        "Programming Language :: Python :: 3.11",
         "Topic :: Utilities",
         "Topic :: Software Development :: Libraries",
         "Topic :: Software Development :: Libraries :: Python Modules",
diff --git a/tests/test_base.py b/tests/test_base.py
new file mode 100644
index 0000000..18363ba
--- /dev/null
+++ b/tests/test_base.py
@@ -0,0 +1,1076 @@
+from __future__ import annotations
+
+import os
+
+import pytest
+
+from dynaconf import Dynaconf
+from dynaconf import LazySettings
+from dynaconf.loaders import toml_loader
+from dynaconf.loaders import yaml_loader
+from dynaconf.strategies.filtering import PrefixFilter
+from dynaconf.utils.parse_conf import true_values
+from dynaconf.vendor.box.box_list import BoxList
+
+
+def test_deleted_raise(settings):
+    """asserts variable can be deleted"""
+    assert "TODELETE" in settings
+    assert settings.TODELETE is True
+    del settings.TODELETE
+    with pytest.raises(AttributeError):
+        assert settings.TODELETE is True
+    assert settings.exists("TODELETE") is False
+    assert settings.get("TODELETE") is None
+
+
+def test_delete_and_set_again(settings):
+    """asserts variable can be deleted and set again"""
+
+    # set
+    settings.TODELETE2 = True
+    assert "TODELETE2" in settings
+    assert settings.TODELETE2 is True
+
+    # delete
+    del settings.TODELETE2
+    assert settings.exists("TODELETE2") is False
+    assert settings.get("TODELETE2") is None
+
+    # set again
+    settings.TODELETE2 = "new value"
+    assert settings.TODELETE2 == "new value"
+
+
+def test_accepts_only_upper():
+    """Only upper case names are allowed if lowercase_read=False
+    lower case are converted"""
+
+    settings = LazySettings(debug=True, lowercase_read=False)
+
+    assert settings.DEBUG is True
+    assert settings.get("debug") is True
+    assert settings.get("DEBUG") is True
+    assert settings.get("Debug") is True
+    assert settings.exists("debug")
+    with pytest.raises(AttributeError):
+        # access in lower case is not allowed
+        assert settings.debug is True
+
+
+def test_populate_obj(settings):
+    class Obj:
+        pass
+
+    obj = Obj()
+
+    settings.populate_obj(obj)
+
+    assert obj.DEBUG is True
+    assert obj.VALUE == 42.1
+
+
+def test_populate_obj_with_keys(settings):
+    class Obj:
+        pass
+
+    obj = Obj()
+
+    settings.populate_obj(obj, ["VALUE"])
+
+    assert obj.VALUE == 42.1
+
+    with pytest.raises(AttributeError):
+        assert obj.DEBUG is True
+
+
+def test_populate_obj_with_ignore(settings):
+    class Obj:
+        pass
+
+    obj = Obj()
+
+    settings.populate_obj(obj, ignore=["VALUE"])
+
+    assert obj.DEBUG is True
+
+    with pytest.raises(AttributeError):
+        assert obj.VALUE == 42.1
+
+
+def test_call_works_as_get(settings):
+    """settings.get('name') is the same as settings('name')"""
+
+    assert settings("debug") == settings.get("DEBUG")
+    assert settings("non_exist", default="hello") == "hello"
+    assert settings.get("non_exist", default="hello") == "hello"
+    assert settings.__call__("debug") == settings.DEBUG
+    assert settings._wrapped.__call__("debug") == settings.DEBUG
+
+
+def test_keys_are_equal(settings):
+    assert set(list(settings.keys())) == set(list(settings.store.keys()))
+
+
+def test_values_are_equal(settings):
+    for item in settings.values():
+        assert item in settings.store.values()
+
+
+def test_get_env(settings):
+    settings.environ["FRUIT"] = "BANANA"
+    assert settings.exists_in_environ("fruit") is True
+    assert settings.environ["FRUIT"] == settings.get_environ("fruit")
+    assert os.environ["FRUIT"] == settings.environ.get("FRUIT")
+
+    settings.environ["SALARY"] = "180.235"
+    assert settings.get_environ("salary", cast="@float") == 180.235
+
+    settings.environ["ENVINT"] = "@int 24"
+    assert settings.get_environ("envint", cast=True) == 24
+
+
+def test_float(settings):
+    settings.set("money", "500.42")
+    assert settings.exists("MONEY")
+    assert settings.MONEY == "500.42"
+    assert settings.MONEY != 500.42
+    assert settings.store["MONEY"] == "500.42"
+    assert "MONEY" not in settings._deleted
+    assert "money" not in settings._deleted
+    assert isinstance(settings.as_float("money"), float)
+    assert settings.as_float("MONEY") == 500.42
+
+
+def test_int(settings):
+    settings.set("age", "500")
+    assert settings.exists("AGE")
+    assert settings.AGE == "500"
+    assert settings.AGE != 500
+    assert settings.store["AGE"] == "500"
+    assert "AGE" not in settings._deleted
+    assert "age" not in settings._deleted
+    assert isinstance(settings.as_int("age"), int)
+    assert settings.as_int("age") == 500
+
+
+def test_bool(settings):
+    for true_value in true_values:
+        # ('t', 'true', 'enabled', '1', 'on', 'yes')
+        settings.set("feature", true_value)
+        assert settings.exists("FEATURE")
+        assert settings.FEATURE == true_value
+        assert settings.FEATURE is not True
+        assert settings.store["FEATURE"] == true_value
+        assert "FEATURE" not in settings._deleted
+        assert "feature" not in settings._deleted
+        assert isinstance(settings.as_bool("feature"), bool)
+        assert settings.as_bool("FEATURE") is True
+
+    # anything else is a false value
+    false_values = ["f", "false", "False", "disabled", "0", "off", "no"]
+    for false_value in false_values:
+        settings.set("feature", false_value)
+        assert settings.exists("FEATURE")
+        assert settings.FEATURE == false_value
+        assert settings.FEATURE is not False
+        assert settings.store["FEATURE"] == false_value
+        assert "FEATURE" not in settings._deleted
+        assert "feature" not in settings._deleted
+        assert isinstance(settings.as_bool("feature"), bool)
+        assert settings.as_bool("FEATURE") is False
+
+
+def test_as_json(settings):
+    settings.set("fruits", '["banana", "apple", "kiwi"]')
+    assert settings.exists("FRUITS")
+    assert settings.FRUITS == '["banana", "apple", "kiwi"]'
+    assert settings.FRUITS != ["banana", "apple", "kiwi"]
+    assert settings.store["FRUITS"] == '["banana", "apple", "kiwi"]'
+    assert "FRUITS" not in settings._deleted
+    assert "fruits" not in settings._deleted
+    assert isinstance(settings.as_json("fruits"), list)
+    assert settings.as_json("fruits") == ["banana", "apple", "kiwi"]
+
+    settings.set("person", '{"name": "Bruno"}')
+    assert settings.exists("PERSON")
+    assert settings.PERSON == '{"name": "Bruno"}'
+    assert settings.PERSON != {"name": "Bruno"}
+    assert settings.store["PERSON"] == '{"name": "Bruno"}'
+    assert "PERSON" not in settings._deleted
+    assert "person" not in settings._deleted
+    assert isinstance(settings.as_json("person"), dict)
+    assert settings.as_json("person") == {"name": "Bruno"}
+
+
+def test_env_should_be_string(settings):
+    with pytest.raises(ValueError):
+        settings.setenv(123456)
+
+
+def test_env_should_not_have_underline(settings):
+    with pytest.raises(ValueError):
+        settings.setenv("COOL_env")
+
+
+def test_path_for(settings):
+    assert settings.path_for(os.path.sep, "tmp", "bla") == os.path.join(
+        os.path.sep, "tmp", "bla"
+    )
+    assert settings.path_for("foo", "bar", "blaz") == os.path.join(
+        settings._root_path, "foo", "bar", "blaz"
+    )
+
+
+def test_get_item(settings):
+    assert settings["DOTENV_INT"] == 1
+    assert settings["PORT"] == 5000
+    with pytest.raises(KeyError):
+        settings["DONOTEXISTTHISKEY"]
+
+
+def test_set_item(settings):
+    settings["FOO"] = "bar"
+    assert settings.FOO == "bar"
+    assert "FOO" in settings._defaults
+    assert settings("FOO") == "bar"
+    assert settings.get("FOO") == "bar"
+
+
+def test_set(settings):
+    # NOTE: it is recommended to call set(x, 1) or ['x'] = 1
+    # instead of settings.BAZ = 'bar'
+    settings.set("BAZ", "bar")
+    assert settings.BAZ == "bar"
+    assert "BAZ" in settings._defaults
+    assert settings("BAZ") == "bar"
+    assert settings.get("BAZ") == "bar"
+
+
+def test_global_set_merge(settings):
+    settings.set("MERGE_ENABLED_FOR_DYNACONF", True)
+    settings.set(
+        "MERGE_KEY", {"items": [{"name": "item 1"}, {"name": "item 2"}]}
+    )
+    settings.set(
+        "MERGE_KEY", {"items": [{"name": "item 3"}, {"name": "item 4"}]}
+    )
+    assert settings.MERGE_KEY == {
+        "items": [
+            {"name": "item 1"},
+            {"name": "item 2"},
+            {"name": "item 3"},
+            {"name": "item 4"},
+        ]
+    }
+
+
+def test_global_merge_shortcut(settings):
+    settings.set("MERGE_ENABLED_FOR_DYNACONF", True)
+    settings.set("MERGE_KEY", ["item1"])
+    settings.set("MERGE_KEY", ["item1"])
+    assert settings.MERGE_KEY == ["item1"]
+
+
+def test_local_set_merge_dict():
+    settings = Dynaconf()
+    settings.set("DATABASE", {"host": "localhost", "port": 666})
+    # calling twice  does not change anything
+    settings.set("DATABASE", {"host": "localhost", "port": 666})
+    assert settings.DATABASE == {"host": "localhost", "port": 666}
+
+    settings.set(
+        "DATABASE", {"host": "new", "user": "admin", "dynaconf_merge": True}
+    )
+    assert settings.DATABASE == {"host": "new", "port": 666, "user": "admin"}
+    assert settings.DATABASE.HOST == "new"
+    assert settings.DATABASE.user == "admin"
+
+    settings.set("DATABASE.attrs", {"a": ["b", "c"]})
+    settings.set("DATABASE.attrs", {"dynaconf_merge": {"foo": "bar"}})
+    assert settings.DATABASE.attrs == {"a": ["b", "c"], "foo": "bar"}
+
+    settings.set("DATABASE.attrs", {"yeah": "baby", "dynaconf_merge": True})
+    assert settings.DATABASE.attrs == {
+        "a": ["b", "c"],
+        "foo": "bar",
+        "yeah": "baby",
+    }
+
+    settings.set(
+        "DATABASE.attrs",
+        {"a": ["d", "e", "dynaconf_merge"], "dynaconf_merge": True},
+    )
+
+    assert settings.DATABASE.attrs == {
+        "a": ["b", "c", "d", "e"],
+        "foo": "bar",
+        "yeah": "baby",
+    }
+
+    settings.set("DATABASE.attrs.a", ["d", "e", "f", "dynaconf_merge_unique"])
+    assert settings.DATABASE.attrs.a == ["b", "c", "d", "e", "f"]
+
+
+def test_local_set_merge_list(settings):
+    settings.set("PLUGINS", ["core"])
+    settings.set("PLUGINS", ["core"])
+    assert settings.PLUGINS == ["core"]
+
+    settings.set("PLUGINS", ["debug_toolbar", "dynaconf_merge"])
+    assert settings.PLUGINS == ["core", "debug_toolbar"]
+
+
+def test_local_set_merge_list_unique(settings):
+    settings.set("SCRIPTS", ["install.sh", "deploy.sh"])
+    settings.set("SCRIPTS", ["install.sh", "deploy.sh"])
+    assert settings.SCRIPTS == ["install.sh", "deploy.sh"]
+
+    settings.set(
+        "SCRIPTS", ["dev.sh", "test.sh", "deploy.sh", "dynaconf_merge_unique"]
+    )
+    assert settings.SCRIPTS == ["install.sh", "dev.sh", "test.sh", "deploy.sh"]
+
+
+def test_set_explicit_merge_token(tmpdir):
+    data = {
+        "a_list": [1, 2],
+        "b_list": [1],
+        "a_dict": {"name": "Bruno"},
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data, merge=False)
+    settings = LazySettings(settings_file="settings.toml")
+    assert settings.A_LIST == [1, 2]
+    assert settings.B_LIST == [1]
+    assert settings.A_DICT == {"name": "Bruno"}
+    assert settings.A_DICT.name == "Bruno"
+
+    settings.set("a_list", [3], merge=True)
+    assert settings.A_LIST == [1, 2, 3]
+
+    settings.set("b_list", "@merge [2]")
+    assert settings.B_LIST == [1, 2]
+
+    settings.set("b_list", "@merge [3, 4]")
+    assert settings.B_LIST == [1, 2, 3, 4]
+
+    settings.set("b_list", "@merge 5")
+    assert settings.B_LIST == [1, 2, 3, 4, 5]
+
+    settings.set("b_list", "@merge 6.6")
+    assert settings.B_LIST == [1, 2, 3, 4, 5, 6.6]
+
+    settings.set("b_list", "@merge false")
+    assert settings.B_LIST == [1, 2, 3, 4, 5, 6.6, False]
+
+    settings.set("b_list", "@merge foo,bar")
+    assert settings.B_LIST == [1, 2, 3, 4, 5, 6.6, False, "foo", "bar"]
+
+    settings.set("b_list", "@merge zaz")
+    assert settings.B_LIST == [1, 2, 3, 4, 5, 6.6, False, "foo", "bar", "zaz"]
+
+    settings.set("a_dict", "@merge {city='Guarulhos'}")
+    assert settings.A_DICT.name == "Bruno"
+    assert settings.A_DICT.city == "Guarulhos"
+
+    settings.set("a_dict", "@merge country=Brasil")
+    assert settings.A_DICT.name == "Bruno"
+    assert settings.A_DICT.city == "Guarulhos"
+    assert settings.A_DICT.country == "Brasil"
+
+    settings.set("new_key", "@merge foo=bar")
+    assert settings.NEW_KEY == {"foo": "bar"}
+
+
+def test_set_new_merge_issue_241_1(tmpdir):
+    data = {
+        "default": {
+            "name": "Bruno",
+            "colors": ["red", "green"],
+            "data": {
+                "links": {"twitter": "rochacbruno", "site": "brunorocha.org"}
+            },
+        }
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data, merge=False)
+    settings = LazySettings(environments=True, settings_file="settings.toml")
+    assert settings.NAME == "Bruno"
+    assert settings.COLORS == ["red", "green"]
+    assert settings.DATA.links == {
+        "twitter": "rochacbruno",
+        "site": "brunorocha.org",
+    }
+
+
+def test_set_new_merge_issue_241_2(tmpdir):
+    data = {
+        "default": {
+            "name": "Bruno",
+            "colors": ["red", "green"],
+            "data": {
+                "links": {"twitter": "rochacbruno", "site": "brunorocha.org"}
+            },
+        }
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data, merge=False)
+
+    data = {
+        "dynaconf_merge": True,
+        "default": {
+            "colors": ["blue"],
+            "data": {"links": {"github": "rochacbruno.github.io"}},
+        },
+    }
+    toml_loader.write(
+        str(tmpdir.join("settings.local.toml")), data, merge=False
+    )
+
+    settings = LazySettings(environments=True, settings_file="settings.toml")
+    assert settings.NAME == "Bruno"
+    assert settings.COLORS == ["red", "green", "blue"]
+    assert settings.DATA.links == {
+        "twitter": "rochacbruno",
+        "site": "brunorocha.org",
+        "github": "rochacbruno.github.io",
+    }
+
+
+def test_set_new_merge_issue_241_3(tmpdir):
+    data = {
+        "name": "Bruno",
+        "colors": ["red", "green"],
+        "data": {
+            "links": {"twitter": "rochacbruno", "site": "brunorocha.org"}
+        },
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data, merge=False)
+
+    data = {
+        "name": "Tommy Shelby",
+        "colors": {"dynaconf_merge": ["yellow", "pink"]},
+        "data": {"links": {"site": "pb.com"}},
+    }
+    toml_loader.write(
+        str(tmpdir.join("settings.local.toml")), data, merge=False
+    )
+
+    settings = LazySettings(settings_file="settings.toml")
+    assert settings.NAME == "Tommy Shelby"
+    assert settings.COLORS == ["red", "green", "yellow", "pink"]
+    assert settings.DATA.links == {"site": "pb.com"}
+
+
+def test_set_new_merge_issue_241_4(tmpdir):
+    data = {
+        "name": "Bruno",
+        "colors": ["red", "green"],
+        "data": {
+            "links": {"twitter": "rochacbruno", "site": "brunorocha.org"}
+        },
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data, merge=False)
+
+    data = {"data__links__telegram": "t.me/rochacbruno"}
+    toml_loader.write(
+        str(tmpdir.join("settings.local.toml")), data, merge=False
+    )
+
+    settings = LazySettings(settings_file="settings.toml")
+    assert settings.NAME == "Bruno"
+    assert settings.COLORS == ["red", "green"]
+    assert settings.DATA.links == {
+        "twitter": "rochacbruno",
+        "site": "brunorocha.org",
+        "telegram": "t.me/rochacbruno",
+    }
+
+
+def test_set_new_merge_issue_241_5(tmpdir):
+    data = {
+        "default": {
+            "name": "Bruno",
+            "colors": ["red", "green"],
+            "data": {
+                "links": {"twitter": "rochacbruno", "site": "brunorocha.org"}
+            },
+        }
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data, merge=False)
+
+    data = {"default": {"colors": "@merge ['blue']"}}
+    toml_loader.write(
+        str(tmpdir.join("settings.local.toml")), data, merge=False
+    )
+
+    settings = LazySettings(environments=True, settings_file="settings.toml")
+    assert settings.NAME == "Bruno"
+    assert settings.COLORS == ["red", "green", "blue"]
+    assert settings.DATA.links == {
+        "twitter": "rochacbruno",
+        "site": "brunorocha.org",
+    }
+
+
+def test_exists(settings):
+    settings.set("BOOK", "TAOCP")
+    assert settings.exists("BOOK") is True
+
+
+def test_dotted_traversal_access(settings):
+    settings.set(
+        "PARAMS",
+        {
+            "PASSWORD": "secret",
+            "SSL": {"CONTEXT": "SECURE"},
+            "DOTTED.KEY": True,
+        },
+        dotted_lookup=False,
+    )
+    assert settings.get("PARAMS") == {
+        "PASSWORD": "secret",
+        "SSL": {"CONTEXT": "SECURE"},
+        "DOTTED.KEY": True,
+    }
+
+    assert settings("PARAMS.PASSWORD") == "secret"
+    assert settings("PARAMS.SSL.CONTEXT") == "SECURE"
+    assert settings("PARAMS.TOKEN.IMAGINARY", 1234) == 1234
+    assert settings("IMAGINARY_KEY.FOO") is None
+    assert settings("IMAGINARY_KEY") is None
+
+    assert settings["PARAMS.PASSWORD"] == "secret"
+    assert settings["PARAMS.SSL.CONTEXT"] == "SECURE"
+    assert settings.PARAMS.SSL.CONTEXT == "SECURE"
+
+    assert settings.exists("PARAMS") is True
+    assert settings.exists("PARAMS.PASSWORD") is True
+    assert settings.exists("PARAMS.SSL") is True
+    assert settings.exists("PARAMS.SSL.FAKE") is False
+    assert settings.exists("PARAMS.SSL.CONTEXT") is True
+
+    # Dotted traversal should not work for dictionary-like key access.
+    with pytest.raises(KeyError):
+        settings["PARAMS.DOESNOTEXIST"]
+
+    # Disable dot-traversal on a per-call basis.
+    assert settings("PARAMS.PASSWORD", dotted_lookup=False) is None
+
+    assert settings("PARAMS.DOTTED.KEY") is None
+    assert settings("PARAMS").get("DOTTED.KEY") is True
+
+    settings.set("DOTTED.KEY", True, dotted_lookup=False)
+    assert settings("DOTTED.KEY", dotted_lookup=False) is True
+
+    settings.set("NESTED_1", {"nested_2": {"nested_3": {"nested_4": True}}})
+
+    assert settings.NESTED_1.nested_2.nested_3.nested_4 is True
+    assert settings["NESTED_1.nested_2.nested_3.nested_4"] is True
+    assert settings("NESTED_1.nested_2.nested_3.nested_4") is True
+    # First key is always transformed to upper()
+    assert settings("nested_1.nested_2.nested_3.nested_4") is True
+
+    # using cast
+    settings.set("me.name", '@json ["bruno", "rocha"]')
+    settings.set("me.number", "42")
+    assert settings.get("me.name", cast=True, default=["bruno", "rocha"]) == [
+        "bruno",
+        "rocha",
+    ]
+    assert settings.get("me.number", cast="@int", default=42) == 42
+
+    # nested separator test
+    assert settings.get("ME__NUMBER") == "42"
+
+
+def test_dotted_set(settings):
+    settings.set("MERGE_ENABLED_FOR_DYNACONF", False)
+
+    settings.set("nested_1.nested_2.nested_3.nested_4", "secret")
+
+    assert settings.NESTED_1.NESTED_2.NESTED_3.NESTED_4 == "secret"
+    assert settings.NESTED_1.NESTED_2.NESTED_3.to_dict() == {
+        "nested_4": "secret"
+    }
+    assert settings.NESTED_1.NESTED_2.to_dict() == {
+        "nested_3": {"nested_4": "secret"}
+    }
+
+    assert settings.get("nested_1").to_dict() == {
+        "nested_2": {"nested_3": {"nested_4": "secret"}}
+    }
+
+    with pytest.raises(KeyError):
+        settings.NESTED_1.NESTED_2_0
+
+    settings.set("nested_1.nested_2_0", "Hello")
+    assert settings.NESTED_1.NESTED_2_0 == "Hello"
+
+    settings.set("nested_1.nested_2.nested_3.nested_4", "Updated Secret")
+    assert settings.NESTED_1.NESTED_2.NESTED_3.NESTED_4 == "Updated Secret"
+    assert settings.NESTED_1.NESTED_2.NESTED_3.to_dict() == {
+        "nested_4": "Updated Secret"
+    }
+    assert settings.NESTED_1.NESTED_2.to_dict() == {
+        "nested_3": {"nested_4": "Updated Secret"}
+    }
+
+    assert settings.get("nested_1").to_dict() == {
+        "nested_2": {"nested_3": {"nested_4": "Updated Secret"}},
+        "nested_2_0": "Hello",
+    }
+
+
+def test_dotted_set_with_merge(settings):
+    settings.set("MERGE_ENABLED_FOR_DYNACONF", False)
+
+    start_data = {
+        "default": {
+            "NAME": "testdb",
+            "ENGINE": "db.foo.bar",
+            "PORT": 6666,
+            "PARAMS": ["a", "b", "c"],
+            "ATTRS": {"a": 1, "b": 2},
+        }
+    }
+    settings.set("DATABASES", start_data)
+
+    assert settings.DATABASES == start_data
+
+    # Change DB name
+    settings.set("DATABASES.default.NAME", "bladb")
+    assert settings.DATABASES != start_data
+    assert settings.DATABASES["default"].keys() == start_data["default"].keys()
+    settings.DATABASES.default.NAME == "bladb"
+
+    # Replace items on a list
+    assert settings.DATABASES.default.PARAMS == ["a", "b", "c"]
+    settings.set("DATABASES.default.PARAMS", ["d", "e"])
+    assert settings.DATABASES != start_data
+    assert settings.DATABASES["default"].keys() == start_data["default"].keys()
+    assert settings.DATABASES.default.PARAMS == ["d", "e"]
+
+    # Add new items to the list
+    settings.set("DATABASES.default.PARAMS", '@merge ["e", "f", "g"]')
+    assert settings.DATABASES != start_data
+    assert settings.DATABASES["default"].keys() == start_data["default"].keys()
+    assert settings.DATABASES.default.PARAMS == ["d", "e", "e", "f", "g"]
+
+    # Replace a dict
+    assert settings.DATABASES.default.ATTRS == {"a": 1, "b": 2}
+    settings.set("DATABASES.default.ATTRS", {"c": 3})
+    assert settings.DATABASES != start_data
+    assert settings.DATABASES["default"].keys() == start_data["default"].keys()
+    assert settings.DATABASES.default.ATTRS == {"c": 3}
+
+    # Add new item to the dict
+    settings.set("DATABASES.default.ATTRS", '@merge {"b": 2, "d": 4}')
+    assert settings.DATABASES != start_data
+    assert settings.DATABASES["default"].keys() == start_data["default"].keys()
+    assert settings.DATABASES.default.ATTRS == {"b": 2, "c": 3, "d": 4}
+
+    # Replace the entire list
+    settings.set("DATABASES.default.PARAMS", ["x", "y", "z"], tomlfy=True)
+    assert settings.DATABASES != start_data
+    assert settings.DATABASES["default"].keys() == start_data["default"].keys()
+    assert settings.DATABASES.default.PARAMS == ["x", "y", "z"]
+
+    # Replace the entire dict
+    settings.set("DATABASES.default.ATTRS", "{x=26}", tomlfy=True)
+    assert settings.DATABASES != start_data
+    assert settings.DATABASES["default"].keys() == start_data["default"].keys()
+    assert settings.DATABASES.default.ATTRS == {"x": 26}
+
+
+def test_from_env_method(clean_env, tmpdir):
+    data = {
+        "default": {"a_default": "From default env"},
+        "development": {
+            "value": "From development env",
+            "only_in_development": True,
+        },
+        "other": {"value": "From other env", "only_in_other": True},
+    }
+    toml_path = str(tmpdir.join("base_settings.toml"))
+    toml_loader.write(toml_path, data, merge=False)
+    settings = LazySettings(settings_file=toml_path, environments=True)
+    settings.set("ARBITRARY_KEY", "arbitrary value")
+
+    assert settings.VALUE == "From development env"
+    assert settings.A_DEFAULT == "From default env"
+    assert settings.ONLY_IN_DEVELOPMENT is True
+    assert settings.ARBITRARY_KEY == "arbitrary value"
+    assert settings.get("ONLY_IN_OTHER") is None
+
+    # clone the settings object pointing to a new env
+    other_settings = settings.from_env("other")
+    assert other_settings.VALUE == "From other env"
+    assert other_settings.A_DEFAULT == "From default env"
+    assert other_settings.ONLY_IN_OTHER is True
+    assert other_settings.get("ARBITRARY_KEY") is None
+    assert other_settings.get("ONLY_IN_DEVELOPMENT") is None
+    with pytest.raises(AttributeError):
+        # values set programmatically are not cloned
+        other_settings.ARBITRARY_KEY
+    with pytest.raises(AttributeError):
+        # values set only in a specific env not cloned
+        other_settings.ONLY_IN_DEVELOPMENT
+    # assert it is cached not created twice
+    assert other_settings is settings.from_env("other")
+
+    # Now the same using keep=True
+    other_settings = settings.from_env("other", keep=True)
+    assert other_settings.VALUE == "From other env"
+    assert other_settings.A_DEFAULT == "From default env"
+    assert other_settings.ONLY_IN_OTHER is True
+    assert other_settings.ONLY_IN_DEVELOPMENT is True
+    assert settings.ARBITRARY_KEY == "arbitrary value"
+
+    # assert it is created not cached
+    assert other_settings is not settings.from_env("other")
+
+    # settings remains the same
+    assert settings.VALUE == "From development env"
+    assert settings.A_DEFAULT == "From default env"
+    assert settings.ONLY_IN_DEVELOPMENT is True
+    assert settings.ARBITRARY_KEY == "arbitrary value"
+    assert settings.get("ONLY_IN_OTHER") is None
+
+    # additional kwargs
+    data = {
+        "default": {"a_default": "From default env"},
+        "production": {"value": "From prod env", "only_in_prod": True},
+        "other": {"value": "From other env", "only_in_other": True},
+    }
+    toml_path = str(tmpdir.join("other_settings.toml"))
+    toml_loader.write(toml_path, data, merge=False)
+
+    new_other_settings = other_settings.from_env(
+        "production", keep=True, SETTINGS_FILE_FOR_DYNACONF=toml_path
+    )
+
+    # production values
+    assert new_other_settings.VALUE == "From prod env"
+    assert new_other_settings.ONLY_IN_PROD is True
+    # keep=True values
+    assert new_other_settings.ONLY_IN_OTHER is True
+    assert new_other_settings.ONLY_IN_DEVELOPMENT is True
+    assert settings.A_DEFAULT == "From default env"
+
+
+def test_from_env_method_with_prefix(clean_env, tmpdir):
+    data = {
+        "default": {"prefix_a_default": "From default env"},
+        "development": {
+            "prefix_value": "From development env",
+            "prefix_only_in_development": True,
+        },
+        "other": {
+            "prefix_value": "From other env",
+            "prefix_only_in_other": True,
+            "not_prefixed": "no prefix",
+        },
+    }
+    toml_path = str(tmpdir.join("base_settings.toml"))
+    toml_loader.write(toml_path, data, merge=False)
+    settings = LazySettings(
+        settings_file=toml_path,
+        environments=True,
+        filter_strategy=PrefixFilter("prefix"),
+    )
+    settings.set("ARBITRARY_KEY", "arbitrary value")
+
+    assert settings.VALUE == "From development env"
+    assert settings.A_DEFAULT == "From default env"
+    assert settings.ONLY_IN_DEVELOPMENT is True
+    assert settings.ARBITRARY_KEY == "arbitrary value"
+    assert settings.get("ONLY_IN_OTHER") is None
+
+    # clone the settings object pointing to a new env
+    other_settings = settings.from_env("other")
+    assert other_settings.VALUE == "From other env"
+    assert other_settings.A_DEFAULT == "From default env"
+    assert other_settings.ONLY_IN_OTHER is True
+    assert other_settings.get("ARBITRARY_KEY") is None
+    assert other_settings.get("ONLY_IN_DEVELOPMENT") is None
+    with pytest.raises(AttributeError):
+        other_settings.not_prefixed
+    with pytest.raises(AttributeError):
+        # values set programmatically are not cloned
+        other_settings.ARBITRARY_KEY
+    with pytest.raises(AttributeError):
+        # values set only in a specific env not cloned
+        other_settings.ONLY_IN_DEVELOPMENT
+    # assert it is cached not created twice
+    assert other_settings is settings.from_env("other")
+
+
+def test_preload(tmpdir):
+    data = {
+        "data": {"links": {"twitter": "rochacbruno", "site": "brunorocha.org"}}
+    }
+    toml_loader.write(str(tmpdir.join("preload.toml")), data, merge=False)
+
+    data = {
+        "dynaconf_merge": True,
+        "data": {"links": {"github": "rochacbruno.github.io"}},
+    }
+    toml_loader.write(
+        str(tmpdir.join("main_settings.toml")), data, merge=False
+    )
+
+    data = {
+        "dynaconf_merge": True,
+        "data": {"links": {"mastodon": "mastodon.social/@rochacbruno"}},
+    }
+    toml_loader.write(str(tmpdir.join("included.toml")), data, merge=False)
+
+    settings = LazySettings(
+        PRELOAD_FOR_DYNACONF=["preload.toml"],
+        SETTINGS_FILE_FOR_DYNACONF="main_settings.toml",
+        INCLUDES_FOR_DYNACONF=["included.toml"],
+    )
+
+    assert settings.DATA.links == {
+        "twitter": "rochacbruno",
+        "site": "brunorocha.org",
+        "github": "rochacbruno.github.io",
+        "mastodon": "mastodon.social/@rochacbruno",
+    }
+
+
+def test_config_aliases(tmpdir):
+    data = {
+        "hello": {"name": "Bruno", "passwd": 1234},
+        "awesome": {"passwd": 5678},
+    }
+    toml_loader.write(str(tmpdir.join("blarg.toml")), data, merge=False)
+
+    settings = LazySettings(
+        envvar_prefix="BRUCE",
+        core_loaders=["TOML"],
+        loaders=["dynaconf.loaders.env_loader"],
+        default_env="hello",
+        env_switcher="BRUCE_ENV",
+        prelaod=[],
+        settings_file=["blarg.toml"],
+        includes=[],
+        ENV="awesome",
+        environments=True,
+    )
+
+    assert settings.NAME == "Bruno"
+    assert settings.PASSWD == 5678
+
+    assert settings.ENVVAR_PREFIX_FOR_DYNACONF == "BRUCE"
+    assert settings.CORE_LOADERS_FOR_DYNACONF == ["TOML"]
+    assert settings.LOADERS_FOR_DYNACONF == ["dynaconf.loaders.env_loader"]
+    assert len(settings._loaders) == 1
+    assert settings.DEFAULT_ENV_FOR_DYNACONF == "hello"
+    assert settings.ENV_SWITCHER_FOR_DYNACONF == "BRUCE_ENV"
+    assert settings.PRELOAD_FOR_DYNACONF == []
+    assert settings.SETTINGS_FILE_FOR_DYNACONF == ["blarg.toml"]
+    assert settings.INCLUDES_FOR_DYNACONF == []
+    assert settings.ENV_FOR_DYNACONF == "awesome"
+    assert settings.current_env == "awesome"
+
+
+def test_envless_mode(tmpdir):
+    data = {
+        "foo": "bar",
+        "hello": "world",
+        "default": 1,
+        "databases": {"default": {"port": 8080}},
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data)
+
+    settings = LazySettings(
+        settings_file="settings.toml"
+    )  # already the default
+    assert settings.FOO == "bar"
+    assert settings.HELLO == "world"
+    assert settings.DEFAULT == 1
+    assert settings.DATABASES.default.port == 8080
+
+
+def test_envless_mode_with_prefix(tmpdir):
+    data = {
+        "prefix_foo": "bar",
+        "hello": "world",
+        "prefix_default": 1,
+        "prefix_databases": {"default": {"port": 8080}},
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data)
+
+    settings = LazySettings(
+        settings_file="settings.toml", filter_strategy=PrefixFilter("prefix")
+    )  # already the default
+    assert settings.FOO == "bar"
+    with pytest.raises(AttributeError):
+        settings.HELLO
+    assert settings.DEFAULT == 1
+    assert settings.DATABASES.default.port == 8080
+
+
+def test_lowercase_read_mode(tmpdir):
+    """
+    Starting on 3.0.0 lowercase keys are enabled by default
+    """
+    data = {
+        "foo": "bar",
+        "hello": "world",
+        "default": 1,
+        "databases": {"default": {"port": 8080}},
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data)
+
+    # settings_files misspelled.. should be `settings_file`
+    settings = LazySettings(settings_files="settings.toml")
+
+    assert settings.FOO == "bar"
+    assert settings.foo == "bar"
+    assert settings.HELLO == "world"
+    assert settings.hello == "world"
+    assert settings.DEFAULT == 1
+    assert settings.default == 1
+    assert settings.DATABASES.default.port == 8080
+    assert settings.databases.default.port == 8080
+
+    assert "foo" in settings
+    assert "FOO" in settings
+
+    # test __dir__
+    results = dir(settings)
+    assert "foo" in results
+    assert "FOO" in results
+
+    results = dir(settings.databases)
+    assert "default" in results
+    assert "DEFAULT" in results
+
+
+def test_settings_dict_like_iteration(tmpdir):
+    """Settings can be iterated just like a dict"""
+    data = {
+        "foo": "bar",
+        "hello": "world",
+        "default": 1,
+        "databases": {"default": {"port": 8080}},
+    }
+    toml_loader.write(str(tmpdir.join("settings.toml")), data)
+
+    # settings_files misspelled.. should be `settings_file`
+    settings = LazySettings(settings_files="settings.toml")
+
+    for key in settings:
+        assert key in settings._store
+
+    for key, value in settings.items():
+        assert settings._store[key] == value
+
+
+def test_prefix_is_not_str_raises():
+    with pytest.raises(TypeError):
+        toml_loader.load(LazySettings(filter_strategy=PrefixFilter(int)))
+    with pytest.raises(TypeError):
+        toml_loader.load(LazySettings(filter_strategy=PrefixFilter(True)))
+
+
+def test_clone():
+    # create a settings object
+    settings = LazySettings(FOO="bar")
+    assert settings.FOO == "bar"
+
+    # clone it
+    cloned = settings.dynaconf.clone()
+    assert cloned.FOO == "bar"
+
+    # modify the cloned settings
+    cloned.FOO = "baz"
+    assert cloned.FOO == "baz"
+
+    # assert original settings is not modified
+    assert settings.FOO == "bar"
+
+
+def test_clone_with_module_type():
+    # create a settings object
+    settings = LazySettings(FOO="bar", A_MODULE=os)
+    # adding a module type makes object unpickaable
+    # then .clone raised an error, this was fixed by copying the dict.
+    assert settings.FOO == "bar"
+
+    # clone it
+    cloned = settings.dynaconf.clone()
+    assert cloned.FOO == "bar"
+
+    # modify the cloned settings
+    cloned.FOO = "baz"
+    assert cloned.FOO == "baz"
+
+    # assert original settings is not modified
+    assert settings.FOO == "bar"
+
+    assert settings.A_MODULE == cloned.A_MODULE
+
+
+def test_wrap_existing_settings():
+    """
+    Wrap an existing settings object
+    """
+    settings = LazySettings(FOO="bar")
+    assert settings.FOO == "bar"
+
+    # wrap it
+    wrapped = LazySettings(settings._wrapped)
+    assert wrapped.FOO == "bar"
+
+    # modify the wrapped settings
+    wrapped.FOO = "baz"
+    assert wrapped.FOO == "baz"
+
+    # assert original settings is also modified as they have the same wrapped
+    assert settings.FOO == "baz"
+
+
+def test_wrap_existing_settings_clone():
+    """
+    Wrap an existing settings object
+    """
+    settings = LazySettings(FOO="bar")
+    assert settings.FOO == "bar"
+
+    # wrap it
+    wrapped = LazySettings(settings.dynaconf.clone())
+    assert wrapped.FOO == "bar"
+
+    # modify the wrapped settings
+    wrapped.FOO = "baz"
+    assert wrapped.FOO == "baz"
+
+    # assert original settings is not changes as we used a wrapped clone
+    assert settings.FOO == "bar"
+
+
+def test_list_entries_from_yaml_should_not_duplicate_when_merged(tmpdir):
+    data = {
+        "default": {
+            "SOME_KEY": "value",
+            "SOME_LIST": ["item_1", "item_2", "item_3"],
+        },
+        "other": {"SOME_KEY": "new_value", "SOME_LIST": ["item_4", "item_5"]},
+    }
+    yaml_loader.write(str(tmpdir.join("test_settings.yaml")), data)
+
+    settings = Dynaconf(
+        settings_files="test_settings.yaml",
+        environments=True,
+        merge_enabled=True,
+    )
+
+    expected_default_value = BoxList(["item_1", "item_2", "item_3"])
+    expected_other_value = BoxList(
+        ["item_1", "item_2", "item_3", "item_4", "item_5"]
+    )
+
+    assert settings.from_env("default").SOME_LIST == expected_default_value
+    assert settings.from_env("other").SOME_LIST == expected_other_value
diff --git a/tests/test_basic.py b/tests/test_basic.py
new file mode 100644
index 0000000..c102c8f
--- /dev/null
+++ b/tests/test_basic.py
@@ -0,0 +1,7 @@
+from __future__ import annotations
+
+from dynaconf import settings
+
+
+def test_has_wrapped():
+    assert settings.configured is True
diff --git a/tests/test_cli.py b/tests/test_cli.py
new file mode 100644
index 0000000..3ff506d
--- /dev/null
+++ b/tests/test_cli.py
@@ -0,0 +1,466 @@
+from __future__ import annotations
+
+import json
+import os
+from pathlib import Path
+
+import pytest
+
+from dynaconf import default_settings
+from dynaconf import LazySettings
+from dynaconf.cli import EXTS
+from dynaconf.cli import main
+from dynaconf.cli import read_file_in_root_directory
+from dynaconf.cli import WRITERS
+from dynaconf.utils.files import read_file
+from dynaconf.vendor.click.testing import CliRunner
+
+
+runner = CliRunner()
+settings = LazySettings(OPTION_FOR_TESTS=True, environments=True)
+
+
+def run(cmd, env=None, attr="output"):
+    result = runner.invoke(main, cmd, env=env, catch_exceptions=False)
+    return getattr(result, attr)
+
+
+def test_version():
+    assert read_file_in_root_directory("VERSION") in run(["--version"])
+
+
+def test_help():
+    assert "Dynaconf - Command Line Interface" in run(["--help"])
+
+
+def test_banner(clean_env):
+    assert "Learn more at:" in run(["--banner"])
+
+
+def test_init_with_instance_raises(tmpdir):
+    result = run(
+        [
+            "-i",
+            "tests.test_cli.settings",
+            "init",
+            "--env",
+            "test",
+            f"--path={str(tmpdir)}",
+        ]
+    )
+    assert "-i/--instance option is not allowed for `init` command" in result
+
+
+def test_init_with_env_warns(tmpdir):
+    result = run(["init", "--env", "test", f"--path={str(tmpdir)}"])
+    assert "The --env/-e option is deprecated" in result
+
+
+@pytest.mark.parametrize("fileformat", EXTS)
+def test_init_with_path(fileformat, tmpdir):
+    # run twice to force load of existing files
+    if fileformat == "env":
+        path = tmpdir.join(".env")
+        secs_path = None
+    else:
+        path = tmpdir.join(f"settings.{fileformat}")
+        secs_path = tmpdir.join(f"/.secrets.{fileformat}")
+
+    for _ in (1, 2):
+        run(
+            [
+                "init",
+                f"--format={fileformat}",
+                "-v",
+                "name=bruno",
+                "-s",
+                "token=secret for",
+                f"--path={str(tmpdir)}",
+                "-y",
+            ]
+        )
+
+    sets = Path(str(path))
+    assert sets.exists() is True
+    assert "bruno" in read_file(
+        str(sets), encoding=default_settings.ENCODING_FOR_DYNACONF
+    )
+
+    if secs_path:
+        secs = Path(str(secs_path))
+        assert secs.exists() is True
+        assert "secret for" in read_file(
+            str(secs), encoding=default_settings.ENCODING_FOR_DYNACONF
+        )
+
+    if fileformat != "env":
+        gign = Path(str(tmpdir.join(".gitignore")))
+        assert gign.exists() is True
+        assert ".secrets.*" in read_file(
+            str(gign), encoding=default_settings.ENCODING_FOR_DYNACONF
+        )
+
+
+def test_list(testdir):
+    """Test list command shows only user defined vars"""
+    result = run(
+        ["list"],
+        env={
+            "ROOT_PATH_FOR_DYNACONF": testdir,
+            "INSTANCE_FOR_DYNACONF": "tests.config.settings",
+        },
+    )
+    assert "TEST_KEY<str> 'test_value'" in result
+
+
+def test_get(testdir):
+    """Tests get command"""
+    result = run(
+        ["get", "TEST_KEY"],
+        env={
+            "ROOT_PATH_FOR_DYNACONF": testdir,
+            "INSTANCE_FOR_DYNACONF": "tests.config.settings",
+        },
+    )
+    assert result == "test_value"
+
+
+def test_get_json_dict(testdir):
+    """Tests get command printing json"""
+    env = env = {
+        "ROOT_PATH_FOR_DYNACONF": testdir,
+        "DYNACONF_DATA__KEY": "value",
+        "DYNACONF_DATA__OTHERKEY": "other value",
+        "INSTANCE_FOR_DYNACONF": "tests.config.settings",
+    }
+    result = run(["get", "data"], env=env)
+    assert result == '{"KEY": "value", "OTHERKEY": "other value"}'
+
+
+def test_get_lower(testdir):
+    """Tests get command"""
+    result = run(
+        ["get", "test_key"],
+        env={
+            "ROOT_PATH_FOR_DYNACONF": testdir,
+            "INSTANCE_FOR_DYNACONF": "tests.config.settings",
+        },
+    )
+    assert result == "test_value"
+
+
+def test_get_unparsed(testdir):
+    """Tests get command"""
+    result = run(
+        ["get", "COMMENTJSON_ENABLED_FOR_DYNACONF", "-u"],
+        env={
+            "ROOT_PATH_FOR_DYNACONF": testdir,
+            "INSTANCE_FOR_DYNACONF": "tests.config.settings",
+        },
+    )
+    assert result == "@bool False"
+
+
+def test_get_with_default(testdir):
+    """Tests get command"""
+    result = run(
+        ["get", "this_obviously_doesnt_exist_yet", "-d", "Hello123"],
+        env={
+            "ROOT_PATH_FOR_DYNACONF": testdir,
+            "INSTANCE_FOR_DYNACONF": "tests.config.settings",
+        },
+    )
+    assert result == "Hello123"
+
+
+def test_get_other_env(tmpdir):
+    """Tests get command"""
+    settings_file = tmpdir.join("settings.json")
+    settings_file.write(
+        '{"prod": {"name": "admin"}, "development": {"name": "dev"}}'
+    )
+    instance_file = tmpdir.join("myconfig.py")
+    instance_file.write(
+        "settings = __import__('dynaconf').Dynaconf("
+        f"settings_file=r'{str(settings_file)}',"
+        "environments=True"
+        ")"
+    )
+
+    result = run(
+        ["get", "name"],
+        env={
+            "INSTANCE_FOR_DYNACONF": "myconfig.settings",
+        },
+    )
+    assert result == "dev"
+
+    result = run(
+        ["get", "name", "-e", "prod"],
+        env={
+            "INSTANCE_FOR_DYNACONF": "myconfig.settings",
+        },
+    )
+    assert result == "admin"
+
+
+def test_help_dont_require_instance(testdir):
+    result = os.system("dynaconf list --help")
+    assert result == 0
+
+
+def test_list_export_json(testdir):
+    result = run(
+        ["-i", "tests.config.settings", "list", "-o", "sets.json"],
+        env={"ROOT_PATH_FOR_DYNACONF": testdir},
+    )
+    assert "TEST_KEY<str> 'test_value'" in result
+    assert json.loads(read_file("sets.json"))["TEST_KEY"] == "test_value"
+
+
+def test_list_with_all(testdir):
+    """Test list command with --all includes interval vars"""
+    result = run(
+        ["-i", "tests.config.settings", "list", "-a"],
+        env={"ROOT_PATH_FOR_DYNACONF": testdir},
+    )
+
+    assert "TEST_KEY<str> 'test_value'" in result
+
+
+@pytest.mark.parametrize("loader", WRITERS)
+def test_list_with_loader(loader):
+    result = run(["-i", "tests.config.settings", "list", "-l", loader])
+    assert "Working in main environment" in result
+
+
+@pytest.mark.parametrize("env", ["default", "development"])
+def test_list_with_env(testdir, env):
+    result = run(
+        ["-i", "tests.config.settingsenv", "list", "-e", env],
+        env={"ROOT_PATH_FOR_DYNACONF": testdir},
+    )
+    assert f"Working in {env} environment" in result
+
+
+def test_list_with_instance():
+    result = run(["-i", "tests.test_cli.settings", "list"])
+    assert "OPTION_FOR_TESTS<bool> True" in result
+
+
+def test_list_with_instance_from_env():
+    result = run(
+        ["list"], {"INSTANCE_FOR_DYNACONF": "tests.test_cli.settings"}
+    )
+    assert "OPTION_FOR_TESTS<bool> True" in result
+
+
+def test_instance_attribute_error():
+    result = run(["-i", "tests.test_cli.idontexist", "list"])
+    assert "has no attribute 'idontexist'" in result
+
+
+def test_instance_import_error():
+    result = run(["-i", "idontexist.settings", "list"])
+    assert "Error: No module named 'idontexist'" in result
+
+
+def test_instance_pypath_error():
+    result = run(["-i", "idontexist", "list"])
+    assert "Error: invalid path to settings instance: idontexist" in result
+
+
+def test_list_with_key():
+    result = run(["-i", "tests.config.settings", "list", "-k", "TEST_KEY"])
+    assert "TEST_KEY<str> 'test_value'" in result
+
+
+def test_list_with_invalid_key():
+    result = run(["-i", "tests.config.settings", "list", "-k", "TEST_KEY.foo"])
+    assert "Key not found" in result
+
+
+def test_list_with_key_export_json(tmpdir):
+    result = run(
+        [
+            "-i",
+            "tests.config.settings",
+            "list",
+            "-k",
+            "TEST_KEY",
+            "-o",
+            "sets.json",
+        ]
+    )
+
+    assert "TEST_KEY<str> 'test_value'" in result
+
+    assert "TEST_KEY" in read_file("sets.json")
+    assert json.loads(read_file("sets.json"))["TEST_KEY"] == "test_value"
+    with pytest.raises(KeyError):
+        json.loads(read_file("sets.json"))["ANOTHER_KEY"]
+
+
+def test_list_with_missing_key():
+    result = run(["-i", "tests.config.settings", "list", "-k", "NOTEXISTS"])
+    assert "Key not found" in result
+
+
+@pytest.mark.parametrize("writer", EXTS)
+@pytest.mark.parametrize("env", ["default", "development"])
+@pytest.mark.parametrize("onlydir", (True, False))
+def test_write(writer, env, onlydir, tmpdir):
+    if onlydir is True:
+        tmpfile = tmpdir
+    else:
+        tmpfile = tmpdir.join(f"settings.{writer}")
+
+    settingspath = tmpdir.join(f"settings.{writer}")
+    secretfile = tmpdir.join(f".secrets.{writer}")
+    env_file = tmpdir.join(".env")
+
+    result = run(
+        [
+            "write",
+            writer,
+            "-v",
+            "TESTVALUE=1",
+            "-s",
+            "SECRETVALUE=2",
+            "-e",
+            env,
+            "-y",
+            "-p",
+            str(tmpfile),
+        ]
+    )
+    if writer != "env":
+        assert f"Data successful written to {settingspath}" in result
+        assert "TESTVALUE" in read_file(
+            str(settingspath), encoding=default_settings.ENCODING_FOR_DYNACONF
+        )
+        assert "SECRETVALUE" in read_file(
+            str(secretfile), encoding=default_settings.ENCODING_FOR_DYNACONF
+        )
+    else:
+        assert f"Data successful written to {env_file}" in result
+        assert "TESTVALUE" in read_file(
+            str(env_file), encoding=default_settings.ENCODING_FOR_DYNACONF
+        )
+        assert "SECRETVALUE" in read_file(
+            str(env_file), encoding=default_settings.ENCODING_FOR_DYNACONF
+        )
+
+
+@pytest.mark.parametrize("path", (".env", "./.env"))
+def test_write_dotenv(path, tmpdir):
+    env_file = tmpdir.join(path)
+
+    result = run(
+        [
+            "write",
+            "env",
+            "-v",
+            "TESTVALUE=1",
+            "-s",
+            "SECRETVALUE=2",
+            "-y",
+            "-p",
+            str(env_file),
+        ]
+    )
+
+    assert f"Data successful written to {env_file}" in result
+    assert "TESTVALUE" in read_file(
+        str(env_file), encoding=default_settings.ENCODING_FOR_DYNACONF
+    )
+    assert "SECRETVALUE" in read_file(
+        str(env_file), encoding=default_settings.ENCODING_FOR_DYNACONF
+    )
+
+
+VALIDATION = """
+[default]
+version = {must_exist=true}
+name = {must_exist=true}
+password = {must_exist=false}
+
+# invalid rule, must always be a dict
+a = 1
+
+  [default.age]
+  must_exist = true
+  lte = 30
+  gte = 10
+
+[production]
+project = {eq="hello_world"}
+host = {is_not_in=['test.com']}
+"""
+
+TOML_VALID = """
+[default]
+version = "1.0.0"
+name = "Dynaconf"
+age = 15
+
+[production]
+project = "hello_world"
+password = 'exists only in prod'
+"""
+
+TOML_INVALID = """
+[default]
+version = "1.0.0"
+name = "Dynaconf"
+age = 35
+
+[production]
+project = "This is not hello_world"
+password = 'exists only in prod'
+host = "test.com"
+"""
+
+
+def test_validate(tmpdir):
+    validation_file = tmpdir.join("dynaconf_validators.toml")
+    validation_file.write(VALIDATION)
+
+    toml_valid = tmpdir.mkdir("valid").join("settings.toml")
+    toml_valid.write(TOML_VALID)
+
+    toml_invalid = tmpdir.mkdir("invalid").join("settings.toml")
+    toml_invalid.write(TOML_INVALID)
+
+    result = run(
+        [
+            "-i",
+            "tests.config.settingsenv",
+            "validate",
+            "-p",
+            str(validation_file),
+        ],
+        {"SETTINGS_FILE_FOR_DYNACONF": str(toml_valid)},
+    )
+    assert "Validation success!" in result
+
+    result = run(
+        [
+            "-i",
+            "tests.test_cli.settings",
+            "validate",
+            "-p",
+            str(Path(str(validation_file)).parent),
+        ],
+        {"SETTINGS_FILE_FOR_DYNACONF": str(toml_invalid)},
+    )
+    assert "age must lte 30 but it is 35 in env default" in result
+    assert (
+        "project must eq hello_world but it is This is not hello_world "
+        "in env production" in result
+    )
+    assert (
+        "host must is_not_in ['test.com'] but it is test.com in env "
+        "production" in result
+    )
+    assert "Validation success!" not in result
diff --git a/tests/test_compat.py b/tests/test_compat.py
new file mode 100644
index 0000000..5205580
--- /dev/null
+++ b/tests/test_compat.py
@@ -0,0 +1,56 @@
+from __future__ import annotations
+
+import os
+
+import pytest
+
+from dynaconf import LazySettings
+
+
+@pytest.mark.parametrize(
+    "deprecated,value,new",
+    [
+        ("DYNACONF_NAMESPACE", "FOO", "ENV_FOR_DYNACONF"),
+        ("NAMESPACE_FOR_DYNACONF", "FOO", "ENV_FOR_DYNACONF"),
+        ("DYNACONF_SETTINGS_MODULE", "dfoo.py", "SETTINGS_FILE_FOR_DYNACONF"),
+        ("SETTINGS_MODULE", "dfoo.py", "SETTINGS_FILE_FOR_DYNACONF"),
+        ("PROJECT_ROOT", "./", "ROOT_PATH_FOR_DYNACONF"),
+        ("DYNACONF_SILENT_ERRORS", True, "SILENT_ERRORS_FOR_DYNACONF"),
+        ("DYNACONF_ALWAYS_FRESH_VARS", ["BAR"], "FRESH_VARS_FOR_DYNACONF"),
+        ("GLOBAL_ENV_FOR_DYNACONF", "MYAPP", "ENVVAR_PREFIX_FOR_DYNACONF"),
+        ("BASE_NAMESPACE_FOR_DYNACONF", "THIS", "DEFAULT_ENV_FOR_DYNACONF"),
+    ],
+)
+def test_dynaconf_namespace_renamed(tmpdir, recwarn, deprecated, value, new):
+    settings = LazySettings(**{deprecated: value})
+
+    assert len(recwarn) == 1
+    assert issubclass(recwarn[0].category, DeprecationWarning)
+    assert deprecated in str(recwarn[0].message)
+    assert new in str(recwarn[0].message)
+    assert settings.get(new) == value
+
+
+def test_envvar_prefix_for_dynaconf(tmpdir, recwarn):
+    os.environ["AWESOMEAPP_FOO"] = "1"
+    os.environ["AWESOMEAPP_BAR"] = "false"
+    os.environ["AWESOMEAPP_LIST"] = '["item1", "item2"]'
+    os.environ["AWESOMEAPP_FLOAT"] = "42.2"
+
+    settings = LazySettings(ENVVAR_PREFIX_FOR_DYNACONF="AWESOMEAPP")
+
+    assert settings.FOO == 1
+    assert settings.BAR is False
+    assert settings.LIST == ["item1", "item2"]
+    assert settings.FLOAT == 42.2
+
+    settings2 = LazySettings(GLOBAL_ENV_FOR_DYNACONF="AWESOMEAPP")
+
+    assert len(recwarn) == 1
+    assert issubclass(recwarn[0].category, DeprecationWarning)
+    assert "GLOBAL_ENV_FOR_DYNACONF" in str(recwarn[0].message)
+
+    assert settings2.FOO == 1
+    assert settings2.BAR is False
+    assert settings2.LIST == ["item1", "item2"]
+    assert settings2.FLOAT == 42.2
diff --git a/tests/test_django.py b/tests/test_django.py
new file mode 100644
index 0000000..55c6d57
--- /dev/null
+++ b/tests/test_django.py
@@ -0,0 +1,44 @@
+from __future__ import annotations
+
+import os
+import sys
+
+import dynaconf
+
+
+def test_djdt_382(tmpdir):
+    settings_file = tmpdir.join("settings.py")
+    settings_file.write("\n".join(["SECRET_KEY = 'dasfadfds2'"]))
+    tmpdir.join("__init__.py").write("")
+    os.environ["DJANGO_SETTINGS_MODULE"] = "settings"
+    sys.path.append(str(tmpdir))
+    __import__("settings")
+    settings = dynaconf.DjangoDynaconf("settings", environments=True)
+    settings.configure(settings_module="settings")
+    assert settings.SECRET_KEY == "dasfadfds2"
+    assert settings.is_overridden("FOO") is False
+
+
+def test_override_settings_596(tmpdir):
+    settings_file = tmpdir.join("other_settings.py")
+    settings_file.write("\n".join(["SECRET_KEY = 'abcdef'"]))
+    tmpdir.join("__init__.py").write("")
+    os.environ["DJANGO_SETTINGS_MODULE"] = "other_settings"
+    sys.path.append(str(tmpdir))
+    __import__("other_settings")
+    settings = dynaconf.DjangoDynaconf("other_settings", environments=True)
+    settings.configure(settings_module="other_settings")
+    assert settings.SECRET_KEY == "abcdef"
+
+    # mimic what django.test.utils.override_settings does
+    class UserSettingsHolder(dynaconf.LazySettings):
+        _django_override = True
+
+    override = UserSettingsHolder(settings._wrapped)
+    override.SECRET_KEY = "foobar"
+
+    # overridden settings is changed
+    assert override.SECRET_KEY == "foobar"
+
+    # original not changed
+    assert settings.SECRET_KEY == "abcdef"
diff --git a/tests/test_dynabox.py b/tests/test_dynabox.py
new file mode 100644
index 0000000..b78f4c3
--- /dev/null
+++ b/tests/test_dynabox.py
@@ -0,0 +1,108 @@
+from __future__ import annotations
+
+from collections import namedtuple
+
+import pytest
+
+from dynaconf.utils.boxing import DynaBox
+from dynaconf.vendor.box import Box
+from dynaconf.vendor.box import BoxKeyError
+from dynaconf.vendor.box import BoxList
+
+
+DBDATA = namedtuple("DbData", ["server", "port"])
+
+
+box = DynaBox(
+    {
+        "server": {
+            "HOST": "server.com",
+            "port": 8080,
+            "PARAMS": {
+                "username": "admin",
+                "PASSWORD": "secret",
+                "token": {"TYPE": 1, "value": 2},
+            },
+        },
+        "database": DBDATA(server="db.com", port=3306),
+    },
+)
+
+
+def test_named_tuple_is_not_transformed():
+    """Issue: https://github.com/dynaconf/dynaconf/issues/595"""
+    assert isinstance(box.database, DBDATA)
+    assert isinstance(box.database, tuple)
+
+
+def test_datatypes():
+    assert isinstance(box.server, dict)
+    assert isinstance(box.server, DynaBox)
+    assert isinstance(box.server.host, str)
+    assert isinstance(box.server.PORT, int)
+
+
+def test_access_lowercase():
+    assert box.server.host == "server.com"
+    assert box.server.port == 8080
+    assert box.server.params.username == "admin"
+    assert box.server.params.password == "secret"
+    assert box.server.params.token.type == 1
+    assert box.server.params.token.value == 2
+
+
+def test_access_uppercase():
+    assert box.SERVER.HOST == "server.com"
+    assert box.SERVER.PORT == 8080
+    assert box.SERVER.PARAMS.USERNAME == "admin"
+    assert box.SERVER.PARAMS.PASSWORD == "secret"
+    assert box.SERVER.PARAMS.TOKEN.TYPE == 1
+    assert box.SERVER.PARAMS.TOKEN.VALUE == 2
+
+
+def test_access_items():
+    assert box["SERVER"]["HOST"] == "server.com"
+    assert box["SERVER"]["PORT"] == 8080
+    assert box["SERVER"]["PARAMS"]["USERNAME"] == "admin"
+    assert box["SERVER"]["PARAMS"]["PASSWORD"] == "secret"
+    assert box["SERVER"]["PARAMS"]["TOKEN"]["TYPE"] == 1
+    assert box["SERVER"]["PARAMS"]["TOKEN"]["VALUE"] == 2
+
+
+def test_access_items_lower():
+    assert box["server"]["HOST"] == "server.com"
+    assert box["server"]["PORT"] == 8080
+    assert box["server"]["params"]["USERNAME"] == "admin"
+    assert box["server"]["params"]["PASSWORD"] == "secret"
+    assert box["server"]["params"]["TOKEN"]["TYPE"] == 1
+    assert box["server"]["params"]["TOKEN"]["VALUE"] == 2
+
+
+def test_get():
+    assert box.get("server").get("host") == "server.com"
+    assert box.get("server").get("port") == 8080
+    assert box.get("server").get("params").username == "admin"
+    assert box.get("server").get("params").password == "secret"
+    assert box.get("server").get("params").token.type == 1
+    assert box.get("server").get("params").token.value == 2
+    assert box.get("server").get("blabla") is None
+    assert box.get("server").get("blabla", "foo") == "foo"
+
+
+def test_copy_no_cause_inf_recursion():
+    box.__copy__()
+    box.copy()
+
+
+def test_accessing_dynabox_inside_boxlist_inside_dynabox():
+    data = DynaBox({"nested": [{"deeper": "nest"}]})
+    assert data.nested[0].deeper == "nest"
+    assert data.NESTED[0].deeper == "nest"
+    assert data.NESTED[0].DEEPER == "nest"
+
+    data = DynaBox({"nested": BoxList([DynaBox({"deeper": "nest"})])})
+    assert data.nested[0].deeper == "nest"
+    assert data.NESTED[0].deeper == "nest"
+    assert isinstance(data.NESTED, BoxList)
+    assert isinstance(data.NESTED[0], DynaBox)
+    assert data.NESTED[0].DEEPER == "nest"
diff --git a/tests/test_endtoend.py b/tests/test_endtoend.py
new file mode 100644
index 0000000..725b020
--- /dev/null
+++ b/tests/test_endtoend.py
@@ -0,0 +1,67 @@
+from __future__ import annotations
+
+import os
+
+
+def test_end_to_end(settings):
+    """
+    settings is fixture configured in conftest.py
+    """
+    assert settings.HOSTNAME == "host.com"
+
+    assert settings.PORT == 5000
+    assert isinstance(settings.PORT, int)
+
+    assert settings.VALUE == 42.1
+    assert isinstance(settings.VALUE, float)
+
+    assert settings.DEBUG is True
+    assert isinstance(settings.DEBUG, bool)
+
+    assert settings.ALIST == ["item1", "item2", "item3"]
+    assert isinstance(settings.ALIST, list)
+    assert len(settings.ALIST) == 3
+
+    assert settings.ADICT == {"key": "value"}
+    assert isinstance(settings.ADICT, dict)
+    assert "key" in settings.ADICT
+
+    assert settings.get("FOO", default="bar") == "bar"
+
+    assert settings.HOSTNAME == "host.com"
+
+    if settings.exists_in_environ("TRAVIS"):
+        assert settings.ENV_BOOLEAN is True
+        assert settings.ENV_INT == 42
+        assert settings.ENV_FLOAT == 42.2
+        assert settings.ENV_LIST == ["dyna", "conf"]
+        assert settings.ENV_PURE_INT == 42
+        assert settings.ENV_STR_INT == "42"
+        assert settings.as_int("ENV_PURE_INT") == 42
+        assert settings.get("ENV_PURE_INT", cast="@int") == 42
+        assert isinstance(settings.ENV_DICT, dict)
+
+        os.environ["ENVVAR_PREFIX_FOR_DYNACONF"] = "OTHER"
+        with settings.using_env("OTHER"):
+            assert settings.TESTING is True
+            assert settings.ENABLED is True
+            assert settings.DISABLED is False
+        os.environ["ENVVAR_PREFIX_FOR_DYNACONF"] = "DYNACONF"
+
+
+def test_boxed_data(settings):
+    assert settings.BOXED_DATA.host == "server.com"
+    assert settings.BOXED_DATA.port == 8080
+    assert settings.BOXED_DATA.params.username == "admin"
+    assert settings.BOXED_DATA.params.password == "secret"
+    assert settings.BOXED_DATA.params.token.type == 1
+    assert settings.BOXED_DATA.params.token.value == 2
+
+
+def test_boxed_data_call(settings):
+    assert settings("boxed_data").host == "server.com"
+    assert settings("boxed_data").port == 8080
+    assert settings("boxed_data").params.username == "admin"
+    assert settings("boxed_data").params.password == "secret"
+    assert settings("boxed_data").params.token.type == 1
+    assert settings("boxed_data").params.token.value == 2
diff --git a/tests/test_env_loader.py b/tests/test_env_loader.py
new file mode 100644
index 0000000..2e85a00
--- /dev/null
+++ b/tests/test_env_loader.py
@@ -0,0 +1,507 @@
+from __future__ import annotations
+
+import os
+import sys
+from collections import OrderedDict
+from os import environ
+
+import pytest
+
+from dynaconf import settings  # noqa
+from dynaconf.loaders.env_loader import load
+from dynaconf.loaders.env_loader import load_from_env
+from dynaconf.loaders.env_loader import write
+
+# GLOBAL ENV VARS
+environ["DYNACONF_HOSTNAME"] = "host.com"
+environ["DYNACONF_PORT"] = "@int 5000"
+environ["DYNACONF_ALIST"] = '@json ["item1", "item2", "item3", 123]'
+environ["DYNACONF_ADICT"] = '@json {"key": "value", "int": 42}'
+environ["DYNACONF_DEBUG"] = "@bool true"
+environ["DYNACONF_MUSTBEFRESH"] = "first"
+environ["DYNACONF_MUSTBEALWAYSFRESH"] = "first"
+environ["DYNACONF_SHOULDBEFRESHINCONTEXT"] = "first"
+environ["DYNACONF_VALUE"] = "@float 42.1"
+
+# environ['FRESH_VARS_FOR_DYNACONF'] = '@json ["MUSTBEALWAYSFRESH"]'
+# settings.configure(IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF=True)
+settings.configure(
+    FRESH_VARS_FOR_DYNACONF=["MUSTBEALWAYSFRESH"],
+    ROOT_PATH_FOR_DYNACONF=os.path.dirname(os.path.abspath(__file__)),
+)
+
+SETTINGS_DATA = OrderedDict()
+# Numbers
+SETTINGS_DATA["DYNACONF_INTEGER"] = 42
+SETTINGS_DATA["DYNACONF_FLOAT"] = 3.14
+# Text
+# 'DYNACONF_STRING': Hello,
+SETTINGS_DATA["DYNACONF_STRING2"] = "Hello"
+SETTINGS_DATA["DYNACONF_STRING2_LONG"] = "Hello World!"
+SETTINGS_DATA["DYNACONF_BOOL"] = True
+SETTINGS_DATA["DYNACONF_BOOL2"] = False
+# Use extra quotes to force a string from other type
+SETTINGS_DATA["DYNACONF_STRING21"] = '"42"'
+SETTINGS_DATA["DYNACONF_STRING22"] = "'true'"
+# Arrays must be homogeneous in toml syntax
+SETTINGS_DATA["DYNACONF_ARRAY"] = [1, 2, 3]
+SETTINGS_DATA["DYNACONF_ARRAY2"] = [1.1, 2.2, 3.3]
+SETTINGS_DATA["DYNACONF_ARRAY3"] = ["a", "b", "c"]
+# Dictionaries
+SETTINGS_DATA["DYNACONF_DICT"] = {"val": 123}
+
+SETTINGS_DATA_GROUND_TRUTH = """DYNACONF_TESTING=true
+DYNACONF_INTEGER=42
+DYNACONF_FLOAT=3.14
+DYNACONF_STRING2=Hello
+DYNACONF_STRING2_LONG="Hello World!"
+DYNACONF_BOOL=True
+DYNACONF_BOOL2=False
+DYNACONF_STRING21="42"
+DYNACONF_STRING22="true"
+DYNACONF_ARRAY="[1, 2, 3]"
+DYNACONF_ARRAY2="[1.1, 2.2, 3.3]"
+DYNACONF_ARRAY3="[\'a\', \'b\', \'c\']"
+DYNACONF_DICT="{\'val\': 123}"
+"""
+
+
+def test_write(tmpdir):
+    settings_path = tmpdir.join(".env")
+
+    write(settings_path, SETTINGS_DATA)
+
+    ground_truth = SETTINGS_DATA_GROUND_TRUTH.split("\n")
+
+    with open(str(settings_path)) as fp:
+        lines = fp.readlines()
+        for idx, line in enumerate(lines):
+            line = line.strip()
+            if line.split("=")[0] == "DYNACONF_TESTING":
+                continue  # this key is written by the test itself; skip.
+            assert line == ground_truth[idx].strip()
+
+
+def test_env_loader():
+    assert settings.HOSTNAME == "host.com"
+    assert settings.PORT == 5000
+    assert settings.ALIST == ["item1", "item2", "item3", 123]
+    assert settings.ADICT == {"key": "value", "int": 42}
+
+
+def test_single_key():
+    environ["DYNACONF_HOSTNAME"] = "changedhost.com"
+    load(settings, key="HOSTNAME")
+    # hostname is reloaded
+    assert settings.HOSTNAME == "changedhost.com"
+
+
+def test_dotenv_loader():
+    assert settings.DOTENV_INT == 1
+    assert settings.DOTENV_STR == "hello"
+    assert settings.DOTENV_FLOAT == 4.2
+    assert settings.DOTENV_BOOL is False
+    assert settings.DOTENV_JSON == ["1", "2"]
+    assert settings.DOTENV_NOTE is None
+
+
+def test_get_fresh():
+    assert settings.MUSTBEFRESH == "first"
+    environ["DYNACONF_MUSTBEFRESH"] = "second"
+    with pytest.raises(AssertionError):
+        # fresh should now be second
+        assert settings.exists("MUSTBEFRESH")
+        assert settings.get_fresh("MUSTBEFRESH") == "first"
+    assert settings.get_fresh("MUSTBEFRESH") == "second"
+
+    environ["DYNACONF_THISMUSTEXIST"] = "@int 1"
+    # must tnot exist yet (not loaded)
+    assert settings.exists("THISMUSTEXIST") is False
+    # must exist because fresh will call loaders
+    assert settings.exists("THISMUSTEXIST", fresh=True) is True
+    # loaders run only once
+    assert settings.get("THISMUSTEXIST") == 1
+
+    environ["DYNACONF_THISMUSTEXIST"] = "@int 23"
+    del environ["DYNACONF_THISMUSTEXIST"]
+    # this should error because envvar got cleaned
+    # but it is not, so cleaners should be fixed
+    assert settings.get_fresh("THISMUSTEXIST") is None
+    with pytest.raises(AttributeError):
+        settings.THISMUSTEXIST
+    with pytest.raises(KeyError):
+        settings["THISMUSTEXIST"]
+
+    environ["DYNACONF_THISMUSTEXIST"] = "@int 23"
+    load(settings)
+    assert settings.get("THISMUSTEXIST") == 23
+
+
+def test_always_fresh():
+    # assert environ['FRESH_VARS_FOR_DYNACONF'] == '@json ["MUSTBEALWAYSFRESH"]'  # noqa
+    assert settings.FRESH_VARS_FOR_DYNACONF == ["MUSTBEALWAYSFRESH"]
+    assert settings.MUSTBEALWAYSFRESH == "first"
+    environ["DYNACONF_MUSTBEALWAYSFRESH"] = "second"
+    assert settings.MUSTBEALWAYSFRESH == "second"
+    environ["DYNACONF_MUSTBEALWAYSFRESH"] = "third"
+    assert settings.MUSTBEALWAYSFRESH == "third"
+
+
+def test_fresh_context():
+    assert settings.SHOULDBEFRESHINCONTEXT == "first"
+    environ["DYNACONF_SHOULDBEFRESHINCONTEXT"] = "second"
+    assert settings.SHOULDBEFRESHINCONTEXT == "first"
+    with settings.fresh():
+        assert settings.get("DOTENV_INT") == 1
+        assert settings.SHOULDBEFRESHINCONTEXT == "second"
+
+
+def test_cleaner():
+    settings.clean()
+    with pytest.raises(AttributeError):
+        assert settings.HOSTNAME == "host.com"
+
+
+def test_empty_string_prefix():
+    environ["_VALUE"] = "underscored"
+    load_from_env(
+        identifier="env_global", key=None, prefix="", obj=settings, silent=True
+    )
+    assert settings.VALUE == "underscored"
+
+
+def test_no_prefix():
+    environ["VALUE"] = "no_prefix"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix=False,
+        obj=settings,
+        silent=True,
+    )
+    assert settings.VALUE == "no_prefix"
+
+
+def test_none_as_string_prefix():
+    environ["NONE_VALUE"] = "none as prefix"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="none",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.VALUE == "none as prefix"
+
+
+def test_backwards_compat_using_env_argument():
+    environ["BLARG_VALUE"] = "BLARG as prefix"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        env="BLARG",  # renamed to `prefix` on 3.0.0
+        obj=settings,
+        silent=True,
+    )
+    assert settings.VALUE == "BLARG as prefix"
+
+
+def test_load_signed_integer():
+    environ["799_SIGNED_NEG_INT"] = "-1"
+    environ["799_SIGNED_POS_INT"] = "+1"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="799",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.SIGNED_NEG_INT == -1
+    assert settings.SIGNED_POS_INT == 1
+
+
+def test_env_is_not_str_raises():
+    with pytest.raises(TypeError):
+        load_from_env(settings, prefix=int)
+    with pytest.raises(TypeError):
+        load_from_env(settings, prefix=True)
+
+
+def test_can_load_in_to_dict():
+    os.environ["LOADTODICT"] = "true"
+    sets = {}
+    load_from_env(sets, prefix=False, key="LOADTODICT")
+    assert sets["LOADTODICT"] is True
+
+
+def clean_environ(prefix):
+    keys = [k for k in environ if k.startswith(prefix)]
+    for key in keys:
+        environ.pop(key)
+
+
+@pytest.mark.skipif(
+    sys.platform.startswith("win"),
+    reason="Windows env vars are case insensitive",
+)
+def test_load_dunder(clean_env):
+    """Test load and merge with dunder settings"""
+    clean_environ("DYNACONF_DATABASES")
+    settings.set(
+        "DATABASES",
+        {
+            "default": {
+                "NAME": "db",
+                "ENGINE": "module.foo.engine",
+                "ARGS": {"timeout": 30},
+                "PORTS": [123, 456],
+            }
+        },
+    )
+    # change engine
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default__ENGINE"] = "other.module"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES.default.ENGINE == "other.module"
+
+    # change timeout directly
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default__ARGS__timeout"] = "99"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES.default.ARGS.timeout == 99
+
+    # add to ARGS
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default__ARGS"] = "@merge {retries=10}"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES.default.ARGS.retries == 10
+    assert settings.DATABASES.default.ARGS.timeout == 99
+
+    # Ensure dictionary keeps its format
+    assert settings.DATABASES == {
+        "default": {
+            "NAME": "db",
+            "ENGINE": "other.module",
+            "ARGS": {"timeout": 99, "retries": 10},
+            "PORTS": [123, 456],
+        }
+    }
+    assert "default" in settings["DATABASES"].keys()
+    assert "DEFAULT" not in settings["DATABASES"].keys()
+    assert "NAME" in settings["DATABASES"]["default"].keys()
+    assert "name" not in settings["DATABASES"]["default"].keys()
+
+    # Clean args
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default__ARGS"] = "{timeout=8}"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES.default.ARGS == {"timeout": 8}
+
+    # Make args empty
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default__ARGS"] = "{}"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES.default.ARGS == {}
+
+    # Remove ARGS key
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default__ARGS"] = "@del"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert "ARGS" not in settings.DATABASES.default.keys()
+
+    # add to existing PORTS
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default__PORTS"] = "@merge [789, 101112]"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert "ARGS" not in settings.DATABASES.default.keys()
+    assert settings.DATABASES.default.PORTS == [123, 456, 789, 101112]
+
+    # reset PORTS
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default__PORTS"] = "[789, 101112]"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert "ARGS" not in settings.DATABASES.default.keys()
+    assert settings.DATABASES.default.PORTS == [789, 101112]
+
+    # delete PORTS
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default__PORTS"] = "@del"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert "ARGS" not in settings.DATABASES.default.keys()
+    assert "PORTS" not in settings.DATABASES.default.keys()
+
+    # reset default key
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default"] = "{}"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES.default == {}
+
+    # remove default
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__default"] = "@del"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES == {}
+
+    # set value to databases
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES__foo"] = "bar"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES == {"foo": "bar"}
+
+    # reset databases
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES"] = "{hello='world'}"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES == {"hello": "world"}
+
+    # also reset databases
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES"] = "{yes='no'}"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert settings.DATABASES == {"yes": "no"}
+
+    # remove databases
+    clean_environ("DYNACONF_DATABASES")
+    environ["DYNACONF_DATABASES"] = "@del"
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        prefix="dynaconf",
+        obj=settings,
+        silent=True,
+    )
+    assert "DATABASES" not in settings
+
+
+def test_filtering_unknown_variables():
+    # Predefine some known variable.
+    settings.MYCONFIG = "bar"
+    # Enable environment filtering.
+    settings.IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF = True
+
+    # Pollute the environment.
+    environ["IGNOREME"] = "foo"
+
+    load_from_env(
+        obj=settings,
+        prefix=False,
+        key=None,
+        silent=True,
+        identifier="env_global",
+        env=False,
+    )
+
+    # Verify the filter works.
+    assert not settings.get("IGNOREME")
+    # Smoke test.
+    assert settings.get("MYCONFIG") == "bar"
+
+
+def test_filtering_unknown_variables_with_prefix():
+    # Predefine some known variable.
+    settings.MYCONFIG = "bar"
+    # Enable environment filtering.
+    settings.IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF = True
+
+    # Pollute the environment.
+    environ["APP_IGNOREME"] = "foo"
+    # Also change legitimate variable.
+    environ["APP_MYCONFIG"] = "ham"
+
+    load_from_env(
+        obj=settings,
+        prefix="APP",
+        key=None,
+        silent=True,
+        identifier="env_global",
+        env=False,
+    )
+
+    # Verify the filter works.
+    assert not settings.get("IGNOREME")
+    # Smoke test.
+    assert settings.get("MYCONFIG") == "ham"
diff --git a/tests/test_envvar_prefix.py b/tests/test_envvar_prefix.py
new file mode 100644
index 0000000..35011b4
--- /dev/null
+++ b/tests/test_envvar_prefix.py
@@ -0,0 +1,46 @@
+from __future__ import annotations
+
+import os
+
+import pytest
+
+from dynaconf import LazySettings
+
+TOML = """
+[global]
+var = "my value"
+
+[false]
+thisvar = "should not be set"
+"""
+
+
+def test_envvar_prefix_lazysettings(tmpdir):
+    os.environ["DYNACONF_PREFIXED_VAR"] = "this is prefixed"
+    tmpfile = tmpdir.mkdir("sub").join("test_no_envvar_prefix.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(
+        environments=True,
+        envvar_prefix=False,
+        settings_file=str(tmpfile),
+    )
+
+    assert settings.VAR == "my value"
+    assert settings.DYNACONF_PREFIXED_VAR == "this is prefixed"
+
+
+def test_envvar_prefix_false_from_envvar(tmpdir):
+    os.environ["DYNACONF_PREFIXED_VAR"] = "this is prefixed"
+    os.environ["ENVVAR_PREFIX_FOR_DYNACONF"] = "false"
+    tmpfile = tmpdir.mkdir("sub").join("test_no_envvar_prefix.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(environments=True, settings_file=str(tmpfile))
+
+    assert settings.VAR == "my value"
+    assert settings.DYNACONF_PREFIXED_VAR == "this is prefixed"
+
+    with pytest.raises(AttributeError):
+        assert settings.THISVAR == "should not be set"
+    del os.environ["ENVVAR_PREFIX_FOR_DYNACONF"]
diff --git a/tests/test_feature_flag.py b/tests/test_feature_flag.py
new file mode 100644
index 0000000..5cbdeb5
--- /dev/null
+++ b/tests/test_feature_flag.py
@@ -0,0 +1,36 @@
+from __future__ import annotations
+
+import os
+
+from dynaconf import LazySettings
+
+
+TOML = """
+[default]
+DATA = true
+
+[premiumuser]
+DASHBOARD="True"
+
+[simpleuser]
+DASHBOARD=false
+"""
+
+
+def test_feature_flag(tmpdir):
+
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(environments=True, settings_file=str(tmpfile))
+
+    assert settings.flag("dashboard", "premiumuser") is True
+    assert settings.flag("dashboard", "simpleuser") is False
+    assert settings.flag("dashboard") is False
+
+    # ensure data is fresh
+    os.environ["DYNACONF_DASHBOARD"] = "@bool on"
+    assert settings.flag("dashboard") is True
+
+    os.environ["DYNACONF_DASHBOARD"] = "False"
+    assert settings.flag("dashboard") is False
diff --git a/tests/test_flask.py b/tests/test_flask.py
new file mode 100644
index 0000000..fbd40d1
--- /dev/null
+++ b/tests/test_flask.py
@@ -0,0 +1,144 @@
+from __future__ import annotations
+
+from collections import namedtuple
+
+import pytest
+from flask import Flask
+
+from dynaconf.contrib import FlaskDynaconf
+from tests_functional.flask_with_dotenv.app import app as flask_app
+
+
+DBDATA = namedtuple("DbData", ["server", "port"])
+
+
+def test_named_tuple_config():
+    app = Flask(__name__)
+    app.config["DBDATA"] = DBDATA(server="localhost", port=5432)
+    FlaskDynaconf(app)
+    assert app.config["DBDATA"].server == "localhost"
+    assert app.config["DBDATA"].port == 5432
+    assert isinstance(app.config["DBDATA"], DBDATA)
+
+
+def test_named_tuple_config_using_initapp():
+    app = Flask(__name__)
+    FlaskDynaconf(app)
+    app.config["DBDATA"] = DBDATA(server="localhost", port=5432)
+    assert app.config["DBDATA"].server == "localhost"
+    assert app.config["DBDATA"].port == 5432
+    assert isinstance(app.config["DBDATA"], DBDATA)
+
+
+def test_dynamic_load_exts(settings):
+    """Assert that a config based extensions are loaded"""
+    app = Flask(__name__)
+    app.config["EXTENSIONS"] = [
+        "tests_functional.dummy_flask_extension.dummy:init_app"
+    ]
+    FlaskDynaconf(app, dynaconf_instance=settings)
+    app.config.load_extensions()
+    assert app.config.EXTENSIONS == [
+        "tests_functional.dummy_flask_extension.dummy:init_app"
+    ]
+    assert app.is_dummy_loaded is True
+
+
+def test_dynamic_load_entry_point(settings):
+    """Assert that a config based extensions support entry point syntax"""
+    app = Flask(__name__)
+    app.config["EXTENSIONS"] = [
+        "tests_functional.dummy_flask_extension:dummy_instance.init_app"
+    ]
+    FlaskDynaconf(app, dynaconf_instance=settings)
+    app.config.load_extensions()
+    assert app.config.EXTENSIONS == [
+        "tests_functional.dummy_flask_extension:dummy_instance.init_app"
+    ]
+    assert app.extensions["dummy"].__class__.__name__ == "DummyExtensionType"
+
+
+def test_dynamic_load_exts_list(settings):
+    """Assert that a config based extensions are loaded"""
+    app = Flask(__name__)
+    app.config["EXTENSIONS"] = [
+        "tests_functional.dummy_flask_extension.dummy:init_app"
+    ]
+    FlaskDynaconf(app, dynaconf_instance=settings, extensions_list=True)
+    assert app.config.EXTENSIONS == [
+        "tests_functional.dummy_flask_extension.dummy:init_app"
+    ]
+    assert app.is_dummy_loaded is True
+
+
+def test_dynamic_load_exts_no_list(settings):
+    """Assert that a config based extensions are loaded"""
+    app = Flask(__name__)
+    FlaskDynaconf(app, dynaconf_instance=settings, extensions_list=True)
+
+
+def test_flask_dynaconf(settings):
+    """
+    Test Flask app wrapped with FlaskDynaconf
+    """
+    app = Flask(__name__)
+    app.config["MY_VAR"] = "foo"
+    FlaskDynaconf(app, dynaconf_instance=settings)
+    app.config["MY_VAR2"] = "bar"
+
+    assert app.config.HOSTNAME == "host.com"
+    assert app.config.MY_VAR == "foo"
+
+    assert app.config["HOSTNAME"] == "host.com"
+    assert app.config["MY_VAR"] == "foo"
+
+    assert app.config.get("HOSTNAME") == "host.com"
+    assert app.config.get("MY_VAR") == "foo"
+
+    assert app.config("HOSTNAME") == "host.com"
+    assert app.config("MY_VAR") == "foo"
+
+    assert "HOSTNAME" in app.config
+    assert "MY_VAR" in app.config
+
+    # ref: #521
+    assert "NONEXISTENETVAR" not in app.config
+    assert ("NONEXISTENETVAR" in app.config) is False
+
+    assert "MY_VAR" in app.config
+    assert "MY_VAR2" in app.config
+    assert "MY_VAR" in app.config.keys()
+    assert "MY_VAR2" in app.config.keys()
+    assert ("MY_VAR", "foo") in app.config.items()
+    assert ("MY_VAR2", "bar") in app.config.items()
+    assert "foo" in app.config.values()
+    assert "bar" in app.config.values()
+    assert "MY_VAR" in list(app.config)
+    assert "MY_VAR2" in list(app.config)
+    assert app.config.setdefault("MY_VAR", "default") == "foo"
+    assert app.config.setdefault("MY_VAR2", "default") == "bar"
+    assert app.config.setdefault("DEFAULT_VAR", "default") == "default"
+    assert app.config["DEFAULT_VAR"] == "default"
+
+    with pytest.raises(KeyError):
+        app.config["NONEXISTENETVAR"]
+
+    with pytest.raises(AttributeError):
+        app.config.nonexistentattribute
+
+
+def test_flask_with_dot_env():
+    envvars = {
+        "HELLO": "hello flask",
+        "INTVAR": 42,
+        "FLOATVAR": 4.2,
+        "BOOLVAR": True,
+        "JSONVAR": ["flask", "rocks"],
+    }
+    for key, value in envvars.items():
+        assert flask_app.config[key] == value
+
+
+def test_flask_dotenv_cli():
+    with flask_app.test_client() as client:
+        assert client.get("/test").data == b"hello flask"
diff --git a/tests/test_ini_loader.py b/tests/test_ini_loader.py
new file mode 100644
index 0000000..9beda06
--- /dev/null
+++ b/tests/test_ini_loader.py
@@ -0,0 +1,208 @@
+from __future__ import annotations
+
+import pytest
+
+from dynaconf import LazySettings
+from dynaconf.loaders.ini_loader import load
+from dynaconf.strategies.filtering import PrefixFilter
+
+settings = LazySettings(environments=True, ENV_FOR_DYNACONF="PRODUCTION")
+
+
+INI = """
+a = 'a,b'
+[default]
+password = '@int 99999'
+host = "server.com"
+port = '@int 8080'
+alist = item1, item2, '@int 23'
+
+  [[service]]
+  url = "service.com"
+  port = '@int 80'
+
+    [[[auth]]]
+    password = "qwerty"
+    test = '@int 1234'
+
+[development]
+password = '@int 88888'
+host = "devserver.com"
+
+[production]
+password = '@int 11111'
+host = "prodserver.com"
+
+[global]
+global_value = 'global'
+"""
+
+INI2 = """
+[global]
+secret = "@float 42"
+password = '@int 123456'
+host = "otherini.com"
+"""
+
+INIS = [INI, INI2]
+
+
+def test_load_from_ini():
+    """Assert loads from INI string"""
+    load(settings, filename=INI)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PORT == 8080
+    assert settings.ALIST == ["item1", "item2", 23]
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=INI, env="DEVELOPMENT")
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=INI)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PORT == 8080
+
+
+def test_load_from_multiple_ini():
+    """Assert loads from INI string"""
+    load(settings, filename=INIS)
+    assert settings.HOST == "otherini.com"
+    assert settings.PASSWORD == 123456
+    assert settings.SECRET == 42.0
+    assert settings.PORT == 8080
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=INIS, env="DEVELOPMENT")
+    assert settings.PORT == 8080
+    assert settings.HOST == "otherini.com"
+    load(settings, filename=INIS)
+    assert settings.HOST == "otherini.com"
+    assert settings.PASSWORD == 123456
+    load(settings, filename=INI, env="DEVELOPMENT")
+    assert settings.PORT == 8080
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=INI)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PASSWORD == 11111
+
+
+def test_no_filename_is_none():
+    """Assert if passed no filename return is None"""
+    assert load(settings) is None
+
+
+def test_key_error_on_invalid_env():
+    """Assert error raised if env is not found in INI"""
+    with pytest.raises(KeyError):
+        load(settings, filename=INI, env="FOOBAR", silent=False)
+
+
+def test_no_key_error_on_invalid_env():
+    """Assert error raised if env is not found in INI"""
+    load(settings, filename=INI, env="FOOBAR", silent=True)
+
+
+def test_load_single_key():
+    """Test loading a single key"""
+    ini = """
+    a = "a,b"
+    [foo]
+    bar = "blaz"
+    ZAZ = "naz"
+    lowerkey = 'hello'
+    UPPERKEY = 'world'
+    """
+    load(settings, filename=ini, env="FOO", key="bar")
+    assert settings.BAR == "blaz"
+    assert settings.exists("BAR") is True
+    assert settings.exists("ZAZ") is False
+    load(settings, filename=ini, env="FOO", key="ZAZ")
+    assert settings.ZAZ == "naz"
+    load(settings, filename=ini, env="FOO", key="LOWERKEY")
+    assert settings.LOWERKEY == "hello"
+    load(settings, filename=ini, env="FOO", key="upperkey")
+    assert settings.UPPERKEY == "world"
+
+
+def test_empty_value():
+    load(settings, filename="")
+
+
+def test_multiple_filenames():
+    load(settings, filename="a.ini,b.ini,c.conf,d.properties")
+
+
+def test_cleaner():
+    load(settings, filename=INI)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PORT == 8080
+    assert settings.ALIST == ["item1", "item2", 23]
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=INI, env="DEVELOPMENT")
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=INI)
+    assert settings.HOST == "prodserver.com"
+
+    settings.clean()
+    with pytest.raises(AttributeError):
+        assert settings.HOST == "prodserver.com"
+
+
+def test_using_env(tmpdir):
+    load(settings, filename=INI)
+    assert settings.HOST == "prodserver.com"
+
+    tmpfile = tmpdir.mkdir("sub").join("test_using_env.ini")
+    tmpfile.write(INI)
+    with settings.using_env("DEVELOPMENT", filename=str(tmpfile)):
+        assert settings.HOST == "devserver.com"
+    assert settings.HOST == "prodserver.com"
+
+
+def test_load_dunder():
+    """Test load with dunder settings"""
+    ini = """
+    a = "a,b"
+    [foo]
+    colors__white__code = '#FFFFFF'
+    COLORS__white__name = 'white'
+    """
+    load(settings, filename=ini, env="FOO")
+    assert settings.COLORS.white.code == "#FFFFFF"
+    assert settings.COLORS.white.name == "white"
+
+
+def test_envless():
+    settings = LazySettings()
+    ini = """
+    a = "a,b"
+    colors__white__code = '#FFFFFF'
+    COLORS__white__name = 'white'
+    """
+    load(settings, filename=ini)
+    assert settings.a == "a,b"
+    assert settings.COLORS.white.code == "#FFFFFF"
+    assert settings.COLORS.white.name == "white"
+
+
+def test_prefix():
+    settings = LazySettings(filter_strategy=PrefixFilter("prefix"))
+    ini = """
+    prefix_a = "a,b"
+    prefix_colors__white__code = '#FFFFFF'
+    COLORS__white__name = 'white'
+    """
+    load(settings, filename=ini)
+    assert settings.a == "a,b"
+    assert settings.COLORS.white.code == "#FFFFFF"
+    with pytest.raises(AttributeError):
+        settings.COLORS.white.name
diff --git a/tests/test_json_loader.py b/tests/test_json_loader.py
new file mode 100644
index 0000000..53f0f6d
--- /dev/null
+++ b/tests/test_json_loader.py
@@ -0,0 +1,231 @@
+from __future__ import annotations
+
+import json
+
+import pytest
+
+from dynaconf import LazySettings
+from dynaconf.loaders.json_loader import DynaconfEncoder
+from dynaconf.loaders.json_loader import load
+from dynaconf.strategies.filtering import PrefixFilter
+
+
+settings = LazySettings(environments=True, ENV_FOR_DYNACONF="PRODUCTION")
+
+
+JSON = """
+{
+    "a": "a,b",
+    "default": {
+        "password": "@int 99999",
+        "host": "server.com",
+        "port": "@int 8080",
+        "alist": ["item1", "item2", 23],
+        "service": {
+          "url": "service.com",
+          "port": 80,
+          "auth": {
+            "password": "qwerty",
+            "test": 1234
+          }
+        }
+    },
+    "development": {
+        "password": "@int 88888",
+        "host": "devserver.com"
+    },
+    "production": {
+        "password": "@int 11111",
+        "host": "prodserver.com"
+    },
+    "global": {
+        "global_value": "global"
+    }
+}
+"""
+
+# the @float is not needed in JSON but kept to ensure it works
+JSON2 = """
+{
+  "global": {
+    "secret": "@float 42",
+    "password": 123456,
+    "host": "otherjson.com"
+  }
+}
+"""
+
+JSONS = [JSON, JSON2]
+
+
+def test_load_from_json():
+    """Assert loads from JSON string"""
+    load(settings, filename=JSON)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PORT == 8080
+    assert settings.ALIST == ["item1", "item2", 23]
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=JSON, env="DEVELOPMENT")
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=JSON)
+    assert settings.HOST == "prodserver.com"
+
+
+def test_load_from_multiple_json():
+    """Assert loads from JSON string"""
+    load(settings, filename=JSONS)
+    assert settings.HOST == "otherjson.com"
+    assert settings.PASSWORD == 123456
+    assert settings.SECRET == 42.0
+    assert settings.PORT == 8080
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=JSONS, env="DEVELOPMENT")
+    assert settings.PORT == 8080
+    assert settings.HOST == "otherjson.com"
+    load(settings, filename=JSONS)
+    assert settings.HOST == "otherjson.com"
+    assert settings.PASSWORD == 123456
+    load(settings, filename=JSON, env="DEVELOPMENT")
+    assert settings.PORT == 8080
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=JSON)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PASSWORD == 11111
+
+
+def test_no_filename_is_none():
+    """Assert if passed no filename return is None"""
+    assert load(settings) is None
+
+
+def test_key_error_on_invalid_env():
+    """Assert error raised if env is not found in JSON"""
+    with pytest.raises(KeyError):
+        load(settings, filename=JSON, env="FOOBAR", silent=False)
+
+
+def test_no_key_error_on_invalid_env():
+    """Assert error raised if env is not found in JSON"""
+    load(settings, filename=JSON, env="FOOBAR", silent=True)
+
+
+def test_load_single_key():
+    """Test loading a single key"""
+    _JSON = """
+    {
+      "foo": {
+        "bar": "blaz",
+        "zaz": "naz"
+      }
+    }
+    """
+    load(settings, filename=_JSON, env="FOO", key="bar")
+    assert settings.BAR == "blaz"
+    assert settings.exists("BAR") is True
+    assert settings.exists("ZAZ") is False
+
+
+def test_empty_value():
+    load(settings, filename="")
+
+
+def test_multiple_filenames():
+    load(settings, filename="a.json,b.json,c.json,d.json")
+
+
+def test_cleaner():
+    load(settings, filename=JSON)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PORT == 8080
+    assert settings.ALIST == ["item1", "item2", 23]
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=JSON, env="DEVELOPMENT")
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=JSON)
+    assert settings.HOST == "prodserver.com"
+
+    settings.clean()
+    with pytest.raises(AttributeError):
+        assert settings.HOST == "prodserver.com"
+
+
+def test_using_env(tmpdir):
+    load(settings, filename=JSON)
+    assert settings.HOST == "prodserver.com"
+
+    tmpfile = tmpdir.mkdir("sub").join("test_using_env.json")
+    tmpfile.write(JSON)
+    with settings.using_env("DEVELOPMENT", filename=str(tmpfile)):
+        assert settings.HOST == "devserver.com"
+    assert settings.HOST == "prodserver.com"
+
+
+def test_load_dunder():
+    """Test loading with dunder settings"""
+    _JSON = """
+    {
+      "foo": {
+        "colors__yellow__code": "#FFCC00",
+        "COLORS__yellow__name": "Yellow"
+      }
+    }
+    """
+    load(settings, filename=_JSON, env="FOO")
+    assert settings.COLORS.yellow.code == "#FFCC00"
+    assert settings.COLORS.yellow.name == "Yellow"
+
+
+def test_dynaconf_encoder():
+    class Dummy:
+        def _dynaconf_encode(self):
+            return "Dummy"
+
+    class DummyNotSerializable:
+        _dynaconf_encode = 42
+
+    data = {"dummy": Dummy()}
+    data_error = {"dummy": DummyNotSerializable()}
+
+    assert json.dumps(data, cls=DynaconfEncoder) == '{"dummy": "Dummy"}'
+
+    with pytest.raises(TypeError):
+        json.dumps(data_error, cls=DynaconfEncoder)
+
+
+def test_envless():
+    settings = LazySettings()
+    _json = """
+    {
+        "colors__yellow__code": "#FFCC00",
+        "COLORS__yellow__name": "Yellow"
+    }
+    """
+    load(settings, filename=_json)
+    assert settings.COLORS.yellow.code == "#FFCC00"
+    assert settings.COLORS.yellow.name == "Yellow"
+
+
+def test_prefix():
+    settings = LazySettings(filter_strategy=PrefixFilter("prefix"))
+    _json = """
+    {
+        "prefix_colors__yellow__code": "#FFCC00",
+        "COLORS__yellow__name": "Yellow"
+    }
+    """
+    load(settings, filename=_json)
+    assert settings.COLORS.yellow.code == "#FFCC00"
+    with pytest.raises(AttributeError):
+        settings.COLORS.yellow.name
diff --git a/tests/test_nested_loading.py b/tests/test_nested_loading.py
new file mode 100644
index 0000000..543b3dc
--- /dev/null
+++ b/tests/test_nested_loading.py
@@ -0,0 +1,386 @@
+from __future__ import annotations
+
+import pytest
+
+from dynaconf.base import LazySettings
+
+
+TOML = """
+[default]
+dynaconf_include = ["plugin1.toml", "plugin2.toml", "plugin2.toml"]
+DEBUG = false
+SERVER = "base.example.com"
+PORT = 6666
+
+[development]
+DEBUG = false
+SERVER = "dev.example.com"
+
+[production]
+DEBUG = false
+SERVER = "prod.example.com"
+"""
+
+MIXED = """
+[default]
+dynaconf_include = ["plugin1.toml", "plugin2.{0}"]
+DEBUG = false
+SERVER = "base.example.com"
+PORT = 6666
+
+[development]
+DEBUG = false
+SERVER = "dev.example.com"
+
+[production]
+DEBUG = false
+SERVER = "prod.example.com"
+"""
+
+MIXED_MERGE = """
+[default]
+dynaconf_include = [
+    "plugin1.toml",
+    "plugin2.json",
+    "plugin2.yaml",
+    "plugin2.ini",
+    "plugin2.py"
+]
+DEBUG = false
+SERVER = "base.example.com"
+PORT = 6666
+
+[development]
+DEBUG = false
+SERVER = "dev.example.com"
+
+[production]
+DEBUG = false
+SERVER = "prod.example.com"
+
+
+[custom.nested_1]
+base = 1
+
+[custom.nested_1.nested_2]
+base = 2
+
+[custom.nested_1.nested_2.nested_3]
+base = 3
+
+[custom.nested_1.nested_2.nested_3.nested_4]
+base = 4
+"""
+
+TOML_PLUGIN = """
+[default]
+SERVER = "toml.example.com"
+PLUGIN_NAME = "testing"
+
+[development]
+SERVER = "toml.example.com"
+PLUGIN = "extra development var"
+
+[production]
+SERVER = "toml.example.com"
+PLUGIN = "extra production var"
+
+[custom.nested_1.nested_2.nested_3.nested_4]
+toml = 5
+"""
+
+TOML_PLUGIN_2 = """
+[default]
+SERVER = "plugin2.example.com"
+PLUGIN_2_SPECIAL = true
+PORT = 4040
+
+[custom.nested_1.nested_2.nested_3.nested_4]
+toml = 5
+"""
+
+TOML_PLUGIN_TEXT = """
+[default]
+database_uri = "toml.example.com"
+port = 8080
+
+[custom.nested_1.nested_2.nested_3.nested_4]
+toml = 5
+"""
+
+JSON_PLUGIN_TEXT = """
+{
+    "default": {
+        "database_uri": "json.example.com",
+        "port": 8080
+    },
+    "custom": {
+        "nested_1": {
+            "nested_2": {
+                "nested_3": {
+                    "nested_4": {
+                        "json": 5
+                    }
+                }
+            }
+        }
+    }
+}
+"""
+
+YAML_PLUGIN_TEXT = """
+default:
+  database_uri: "yaml.example.com"
+  port: 8080
+
+custom:
+  nested_1:
+    nested_2:
+      nested_3:
+        nested_4:
+          yaml: 5
+"""
+
+INI_PLUGIN_TEXT = """
+[default]
+database_uri="ini.example.com"
+port="@int 8080"
+
+[custom]
+  [[nested_1]]
+    [[[nested_2]]]
+      [[[[nested_3]]]]
+          [[[[[nested_4]]]]]
+            ini="@int 5"
+"""
+
+PY_PLUGIN_TEXT = """
+DATABASE_URI = "py.example.com"
+PORT = 8080
+NESTED_1 = {
+    "nested_2": {
+        "nested_3": {
+            "nested_4": {
+                "py": 5
+            }
+        }
+    }
+}
+"""
+
+PLUGIN_TEXT = {
+    "toml": TOML_PLUGIN_TEXT,
+    "yaml": YAML_PLUGIN_TEXT,
+    "json": JSON_PLUGIN_TEXT,
+    "ini": INI_PLUGIN_TEXT,
+    "py": PY_PLUGIN_TEXT,
+}
+
+
+def test_invalid_include_path(tmpdir):
+    """Ensure non existing paths are not loaded."""
+
+    settings_file = tmpdir.join("settings.toml")
+    settings_file.write(TOML)
+
+    settings = LazySettings(
+        environments=True,
+        ENV_FOR_DYNACONF="DEFAULT",
+        silent=False,
+        LOADERS_FOR_DYNACONF=False,
+        SETTINGS_FILE_FOR_DYNACONF=str(settings_file),
+    )
+
+    # Ensure overrides not happened
+    assert settings.SERVER == "base.example.com"
+    assert settings.DEBUG is False
+
+
+def test_load_nested_toml(tmpdir):
+    """Load a TOML file that includes other TOML files."""
+
+    settings_file = tmpdir.join("settings.toml")
+    settings_file.write(TOML)
+
+    toml_plugin_file = tmpdir.join("plugin1.toml")
+    toml_plugin_file.write(TOML_PLUGIN)
+
+    toml_plugin_file = tmpdir.join("plugin2.toml")
+    toml_plugin_file.write(TOML_PLUGIN_2)
+
+    settings = LazySettings(
+        environments=True,
+        ENV_FOR_DYNACONF="DEFAULT",
+        silent=False,
+        LOADERS_FOR_DYNACONF=False,
+        ROOT_PATH_FOR_DYNACONF=str(tmpdir),
+        SETTINGS_FILE_FOR_DYNACONF=str(settings_file),
+    )
+
+    # Ensure overrides that happen via TOML plugin config load.
+    assert settings.SERVER == "plugin2.example.com"
+    assert settings.DEBUG is False
+    assert settings.PLUGIN_NAME == "testing"
+
+    # From the second TOML plugin
+    assert settings.PORT == 4040
+    assert settings.PLUGIN_2_SPECIAL is True
+
+
+@pytest.mark.parametrize("ext", ["toml", "json", "yaml", "ini", "py"])
+def test_load_nested_different_types(ext, tmpdir):
+    """Load a TOML file that includes other various settings file types."""
+
+    settings_file = tmpdir.join("settings.toml")
+    settings_file.write(MIXED.format(ext))
+
+    toml_plugin_file = tmpdir.join("plugin1.toml")
+    toml_plugin_file.write(TOML_PLUGIN)
+
+    json_plugin_file = tmpdir.join(f"plugin2.{ext}")
+    json_plugin_file.write(PLUGIN_TEXT[ext])
+
+    settings = LazySettings(
+        environments=True,
+        ENV_FOR_DYNACONF="DEFAULT",
+        silent=False,
+        LOADERS_FOR_DYNACONF=False,
+        ROOT_PATH_FOR_DYNACONF=str(tmpdir),
+        SETTINGS_FILE_FOR_DYNACONF=str(settings_file),
+    )
+
+    assert settings.DEBUG is False
+    assert settings.DATABASE_URI == f"{ext}.example.com"
+    assert settings.PORT == 8080
+    assert settings.SERVER == "toml.example.com"
+    assert settings.PLUGIN_NAME == "testing"
+
+
+def test_load_nested_different_types_with_merge(tmpdir):
+    """Check merge works for includes."""
+
+    settings_file = tmpdir.join("settings.toml")
+    settings_file.write(MIXED_MERGE)
+
+    toml_plugin_file = tmpdir.join("plugin1.toml")
+    toml_plugin_file.write(TOML_PLUGIN)
+
+    for ext in ["toml", "json", "yaml", "ini", "py"]:
+        json_plugin_file = tmpdir.join(f"plugin2.{ext}")
+        json_plugin_file.write(PLUGIN_TEXT[ext])
+
+    settings = LazySettings(
+        environments=True,
+        ENV_FOR_DYNACONF="custom",
+        silent=False,
+        LOADERS_FOR_DYNACONF=False,
+        ROOT_PATH_FOR_DYNACONF=str(tmpdir),
+        SETTINGS_FILE_FOR_DYNACONF=str(settings_file),
+        MERGE_ENABLED_FOR_DYNACONF=True,
+    )
+
+    assert settings.DEBUG is False
+    assert settings.DATABASE_URI == f"{ext}.example.com"
+    assert settings.PORT == 8080
+    assert settings.SERVER == "toml.example.com"
+    assert settings.PLUGIN_NAME == "testing"
+
+    # merge asserts
+    assert settings.NESTED_1.base == 1
+    assert settings.NESTED_1.nested_2.base == 2
+    assert settings.NESTED_1.nested_2.nested_3.base == 3
+    assert settings.NESTED_1.nested_2.nested_3.nested_4.base == 4
+    for ext in ["toml", "json", "yaml", "ini", "py"]:
+        assert settings.NESTED_1.nested_2.nested_3.nested_4[ext] == 5
+
+
+def test_programmatically_file_load(tmpdir):
+    """Check file can be included programmatically"""
+    settings_file = tmpdir.join("settings.toml")
+    settings_file.write(
+        """
+       [default]
+       default_var = 'default'
+    """
+    )
+
+    settings = LazySettings(
+        environments=True, SETTINGS_FILE_FOR_DYNACONF=str(settings_file)
+    )
+    assert settings.DEFAULT_VAR == "default"
+
+    toml_plugin_file = tmpdir.join("plugin1.toml")
+    toml_plugin_file.write(
+        """
+        [development]
+        plugin_value = 'plugin'
+    """
+    )
+
+    settings.load_file(path=str(toml_plugin_file))
+    assert settings.PLUGIN_VALUE == "plugin"
+
+    settings.setenv("production")
+    assert settings.DEFAULT_VAR == "default"
+    # programmatically loaded file is not persisted
+    # once `env` is changed, or a `reload` it will be missed
+    # to persist it needs to go to `INCLUDES_FOR_DYNACONF` variable
+    with pytest.raises(AttributeError):
+        assert settings.PLUGIN_VALUE == "plugin"
+
+
+def test_include_via_python_module_name(tmpdir):
+    """Check if an include can be a Python module name"""
+    settings_file = tmpdir.join("settings.toml")
+    settings_file.write(
+        """
+       [default]
+       default_var = 'default'
+    """
+    )
+
+    dummy_folder = tmpdir.mkdir("dummy")
+    dummy_folder.join("dummy_module.py").write('FOO = "164110"')
+    dummy_folder.join("__init__.py").write('print("initing dummy...")')
+
+    settings = LazySettings(
+        environments=True,
+        SETTINGS_FILE_FOR_DYNACONF=str(settings_file),
+        INCLUDES_FOR_DYNACONF=["dummy.dummy_module"],
+    )
+
+    assert settings.DEFAULT_VAR == "default"
+    assert settings.FOO == "164110"
+
+
+def test_include_via_python_module_name_and_others(tmpdir):
+    """Check if an include can be a Python module name plus others"""
+    settings_file = tmpdir.join("settings.toml")
+    settings_file.write(
+        """
+       [default]
+       default_var = 'default'
+    """
+    )
+
+    dummy_folder = tmpdir.mkdir("dummy")
+    dummy_folder.join("dummy_module.py").write('FOO = "164110"')
+    dummy_folder.join("__init__.py").write('print("initing dummy...")')
+
+    yaml_file = tmpdir.join("otherfile.yaml")
+    yaml_file.write(
+        """
+       default:
+         yaml_value: 748632
+    """
+    )
+
+    settings = LazySettings(
+        environments=True,
+        SETTINGS_FILE_FOR_DYNACONF=str(settings_file),
+        INCLUDES_FOR_DYNACONF=["dummy.dummy_module", "otherfile.yaml"],
+    )
+
+    assert settings.DEFAULT_VAR == "default"
+    assert settings.FOO == "164110"
+    assert settings.YAML_VALUE == 748632
diff --git a/tests/test_py_loader.py b/tests/test_py_loader.py
new file mode 100644
index 0000000..625d87c
--- /dev/null
+++ b/tests/test_py_loader.py
@@ -0,0 +1,189 @@
+from __future__ import annotations
+
+import io
+import os
+
+import pytest
+
+from dynaconf import default_settings
+from dynaconf import LazySettings
+from dynaconf.loaders.py_loader import load
+from dynaconf.loaders.py_loader import try_to_load_from_py_module_name
+from dynaconf.utils import DynaconfDict
+
+
+def test_py_loader_from_file(tmpdir):
+
+    settings = DynaconfDict()
+    dummy_path = tmpdir.join("dummy_module.py")
+    with open(
+        str(dummy_path), "w", encoding=default_settings.ENCODING_FOR_DYNACONF
+    ) as f:
+        f.write('FOO = "bar"')
+
+    load(settings, "dummy_module.py")
+    os.remove("dummy_module.py")
+    load(settings, "dummy_module.py")  # will be ignored not found
+
+    assert settings.get("FOO") == "bar"
+
+
+def test_py_loader_from_module(tmpdir):
+
+    settings = DynaconfDict()
+    dummy_folder = tmpdir.mkdir("dummy")
+
+    dummy_folder.join("dummy_module.py").write('FOO = "bar"')
+    dummy_folder.join("__init__.py").write('print("initing dummy...")')
+
+    load(settings, "dummy.dummy_module")
+
+    assert settings.exists("FOO")
+
+
+def test_try_to_load_from_py_module_name(tmpdir):
+    settings = DynaconfDict()
+    dummy_folder = tmpdir.mkdir("dummy")
+
+    dummy_folder.join("dummy_module.py").write('FOO = "bar"')
+    dummy_folder.join("__init__.py").write('print("initing dummy...")')
+
+    try_to_load_from_py_module_name(settings, "dummy.dummy_module")
+
+    assert settings.exists("FOO")
+
+
+def test_negative_try_to_load_from_py_module_name(tmpdir):
+    settings = DynaconfDict()
+    with pytest.raises(ImportError):
+        try_to_load_from_py_module_name(settings, "foo.bar.dummy")
+
+
+def test_silently_try_to_load_from_py_module_name(tmpdir):
+    settings = DynaconfDict()
+    try_to_load_from_py_module_name(settings, "foo.bar.dummy", silent=True)
+
+    assert settings.exists("FOO") is False
+
+
+def test_py_loader_from_file_dunder(clean_env, tmpdir):
+    """Test load with dunder settings"""
+
+    settings = LazySettings(
+        DATABASES={
+            "default": {
+                "NAME": "db",
+                "ENGINE": "module.foo.engine",
+                "ARGS": {"timeout": 30},
+                "PORTS": [123, 456],
+            }
+        }
+    )
+    dummy_path = tmpdir.join("dummy_module.py")
+    with open(
+        str(dummy_path), "w", encoding=default_settings.ENCODING_FOR_DYNACONF
+    ) as f:
+        f.write('F = "bar"')
+        f.write("\n")
+        f.write('COLORS__white__code = "#FFFFFF"')
+        f.write("\n")
+        f.write('DATABASES__default__ENGINE = "other.module"')
+
+    load(settings, "dummy_module.py")
+    os.remove("dummy_module.py")
+    load(settings, "dummy_module.py")  # will be ignored not found
+
+    assert settings.get("F") == "bar"
+    assert settings.COLORS == {"white": {"code": "#FFFFFF"}}
+    assert settings.DATABASES.default.NAME == "db"
+    assert settings.DATABASES.default.ENGINE == "other.module"
+
+
+def test_post_load_hooks(clean_env, tmpdir):
+    """Test post load hooks works
+
+    This test uses 3 settings files
+
+    PRELOAD = "plugin_folder/plugin.py"
+    SETTINGS_FILE = "settings.py"
+    HOOKFILES = ["plugin_folder/dynaconf_hooks.py", "dynaconf_hooks.py"]
+
+    The hook file has a function called "post" which is called after
+    loading the settings, that function accepts the argument `settings`
+    which is a copy of the settings object, and returns a dictionary
+    of settings to be merged.
+    """
+
+    # Arrange
+    plugin_folder = tmpdir.mkdir("plugin_folder")
+    plugin_folder.join("__init__.py").write('print("initing plugin...")')
+
+    plugin_path = plugin_folder.join("plugin.py")
+    plugin_hook = plugin_folder.join("dynaconf_hooks.py")
+    settings_path = tmpdir.join("settings.py")
+    settings_hook = tmpdir.join("dynaconf_hooks.py")
+
+    to_write = {
+        str(plugin_path): ["PLUGIN_NAME = 'DummyPlugin'"],
+        str(settings_path): [
+            "INSTALLED_APPS = ['admin']",
+            "COLORS = ['red', 'green']",
+            "DATABASES = {'default': {'NAME': 'db'}}",
+            "BANDS = ['Rush', 'Yes']",
+        ],
+        str(plugin_hook): [
+            "post = lambda settings: "
+            "{"
+            "'PLUGIN_NAME': settings.PLUGIN_NAME.lower(),"
+            "'COLORS': '@merge blue',"
+            "'DATABASES__default': '@merge PORT=5151',"
+            "'DATABASES__default__VERSION': 42,"
+            "'DATABASES__default__FORCED_INT': '@int 12',",
+            "'BANDS': ['Anathema', 'dynaconf_merge']" "}",
+        ],
+        str(settings_hook): [
+            "post = lambda settings: "
+            "{"
+            "'INSTALLED_APPS': [settings.PLUGIN_NAME],"
+            "'dynaconf_merge': True,"
+            "}"
+        ],
+    }
+
+    for path, lines in to_write.items():
+        with open(
+            str(path), "w", encoding=default_settings.ENCODING_FOR_DYNACONF
+        ) as f:
+            for line in lines:
+                f.write(line)
+                f.write("\n")
+
+    # Act
+    settings = LazySettings(
+        preload=["plugin_folder.plugin"], settings_file="settings.py"
+    )
+
+    # Assert
+    assert settings.PLUGIN_NAME == "dummyplugin"
+    assert settings.INSTALLED_APPS == ["admin", "dummyplugin"]
+    assert settings.COLORS == ["red", "green", "blue"]
+    assert settings.DATABASES.default.NAME == "db"
+    assert settings.DATABASES.default.PORT == 5151
+    assert settings.DATABASES.default.VERSION == 42
+    assert settings.DATABASES.default.FORCED_INT == 12
+    assert settings.BANDS == ["Rush", "Yes", "Anathema"]
+    assert settings._loaded_hooks[str(plugin_hook)] == {
+        "post": {
+            "PLUGIN_NAME": "dummyplugin",
+            "COLORS": "@merge blue",
+            "DATABASES__default": "@merge PORT=5151",
+            "DATABASES__default__VERSION": 42,
+            "DATABASES__default__FORCED_INT": "@int 12",
+            "BANDS": ["Anathema", "dynaconf_merge"],
+        }
+    }
+    assert settings._loaded_hooks[str(settings_hook)] == {
+        "post": {
+            "INSTALLED_APPS": ["dummyplugin"],
+        }
+    }
diff --git a/tests/test_redis.py b/tests/test_redis.py
new file mode 100644
index 0000000..3c6b02b
--- /dev/null
+++ b/tests/test_redis.py
@@ -0,0 +1,108 @@
+from __future__ import annotations
+
+import os
+
+import pytest
+
+from dynaconf import LazySettings
+from dynaconf.loaders.redis_loader import delete
+from dynaconf.loaders.redis_loader import load
+from dynaconf.loaders.redis_loader import write
+
+
+def custom_checker(ip_address, port):
+    # This function should be check if the redis server is online and ready
+    # write(settings, {"SECRET": "redis_works"})
+    # return load(settings, key="SECRET")
+    return True
+
+
+DYNACONF_TEST_REDIS_URL = os.environ.get("DYNACONF_TEST_REDIS_URL", None)
+if DYNACONF_TEST_REDIS_URL:
+
+    @pytest.fixture(scope="module")
+    def docker_redis():
+        return DYNACONF_TEST_REDIS_URL
+
+else:
+
+    @pytest.fixture(scope="module")
+    def docker_redis(docker_services):
+        docker_services.start("redis")
+        public_port = docker_services.wait_for_service(
+            "redis", 6379, check_server=custom_checker
+        )
+        url = f"http://{docker_services.docker_ip}:{public_port}"
+        return url
+
+
+@pytest.mark.integration
+def test_redis_not_configured():
+    with pytest.raises(RuntimeError) as excinfo:
+        settings = LazySettings(environments=True)
+        write(settings, {"OTHER_SECRET": "redis_works"})
+    assert "export REDIS_ENABLED_FOR_DYNACONF=true" in str(excinfo.value)
+
+
+@pytest.mark.integration
+def test_write_redis_without_data(docker_redis):
+    os.environ["REDIS_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["REDIS_HOST_FOR_DYNACONF"] = "localhost"
+    os.environ["REDIS_PORT_FOR_DYNACONF"] = "6379"
+    settings = LazySettings(environments=True)
+    with pytest.raises(AttributeError) as excinfo:
+        write(settings)
+    assert "Data must be provided" in str(excinfo.value)
+
+
+@pytest.mark.integration
+def test_write_to_redis(docker_redis):
+    os.environ["REDIS_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["REDIS_HOST_FOR_DYNACONF"] = "localhost"
+    os.environ["REDIS_PORT_FOR_DYNACONF"] = "6379"
+    settings = LazySettings(environments=True)
+
+    write(settings, {"SECRET": "redis_works_with_docker"})
+    load(settings, key="SECRET")
+    assert settings.get("SECRET") == "redis_works_with_docker"
+
+
+@pytest.mark.integration
+def test_load_from_redis_with_key(docker_redis):
+    os.environ["REDIS_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["REDIS_HOST_FOR_DYNACONF"] = "localhost"
+    os.environ["REDIS_PORT_FOR_DYNACONF"] = "6379"
+    settings = LazySettings(environments=True)
+    load(settings, key="SECRET")
+    assert settings.get("SECRET") == "redis_works_with_docker"
+
+
+@pytest.mark.integration
+def test_write_and_load_from_redis_without_key(docker_redis):
+    os.environ["REDIS_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["REDIS_HOST_FOR_DYNACONF"] = "localhost"
+    os.environ["REDIS_PORT_FOR_DYNACONF"] = "6379"
+    settings = LazySettings(environments=True)
+    write(settings, {"SECRET": "redis_works_perfectly"})
+    load(settings)
+    assert settings.get("SECRET") == "redis_works_perfectly"
+
+
+@pytest.mark.integration
+def test_delete_from_redis(docker_redis):
+    os.environ["REDIS_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["REDIS_HOST_FOR_DYNACONF"] = "localhost"
+    os.environ["REDIS_PORT_FOR_DYNACONF"] = "6379"
+    settings = LazySettings(environments=True)
+    write(settings, {"OTHER_SECRET": "redis_works"})
+    load(settings)
+    assert settings.get("OTHER_SECRET") == "redis_works"
+    delete(settings, key="OTHER_SECRET")
+    assert load(settings, key="OTHER_SECRET") is None
+
+
+@pytest.mark.integration
+def test_delete_all_from_redis(docker_redis):
+    settings = LazySettings(environments=True)
+    delete(settings)
+    assert load(settings, key="OTHER_SECRET") is None
diff --git a/tests/test_toml_loader.py b/tests/test_toml_loader.py
new file mode 100644
index 0000000..82cde80
--- /dev/null
+++ b/tests/test_toml_loader.py
@@ -0,0 +1,256 @@
+from __future__ import annotations
+
+import pytest
+
+from dynaconf import LazySettings
+from dynaconf.loaders.toml_loader import encode_nulls
+from dynaconf.loaders.toml_loader import load
+from dynaconf.strategies.filtering import PrefixFilter
+
+settings = LazySettings(environments=True, ENV_FOR_DYNACONF="PRODUCTION")
+
+
+TOML = """
+a = "a,b"
+[default]
+password = "@int 99999"
+host = "server.com"
+port = "@int 8080"
+alist = [
+  "item1",
+  "item2",
+  "@int 23"
+]
+
+  [default.service]
+  url = "service.com"
+  port = 80.0
+
+    [default.service.auth]
+    password = "qwerty"
+    test = 1234.0
+
+[development]
+password = "@int 88888"
+host = "devserver.com"
+
+[production]
+password = "@int 11111"
+HOST = "prodserver.com"
+
+[GLOBAL]
+global_value = "global"
+"""
+
+TOML2 = """
+[global]
+secret = "@float 42"
+password = 123456.0
+host = "othertoml.com"
+"""
+
+INVALID_TOML_TO_BE_REMOVED_ON_4_0_0 = """
+[global]
+secret = "@float 42"
+password = 123456.0
+host = "othertoml.com"
+emojis = "😀😀😀😀"
+encoded_variable="This has accents like � and � � � � just to test encoding �"
+# The above is not allowed by TOML, but it is allowed by Dynaconf < 4.0.0
+"""
+
+
+TOMLS = [TOML, TOML2]
+
+
+def test_load_from_toml_with_invalid_unicode(tmpdir):
+    # THIS TEST MUST FAIL AND BE REMOVED ON 4.0.0
+    load(settings, filename=INVALID_TOML_TO_BE_REMOVED_ON_4_0_0)
+    assert settings.ENCODED_VARIABLE == (
+        "This has accents like � and � � � � just to test encoding �"
+    )
+
+    tmpfile = tmpdir.join("settings.toml")
+    with open(tmpfile.strpath, "w", encoding="utf-8") as f:
+        f.write(INVALID_TOML_TO_BE_REMOVED_ON_4_0_0)
+
+    _settings = LazySettings(
+        settings_files=[tmpfile.strpath], environments=True
+    )
+    assert _settings.ENCODED_VARIABLE == (
+        "This has accents like � and � � � � just to test encoding �"
+    )
+    assert _settings.EMOJIS == "😀😀😀😀"
+
+
+def test_load_from_toml():
+    """Assert loads from TOML string"""
+    load(settings, filename=TOML)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PORT == 8080
+    assert settings.ALIST == ["item1", "item2", 23]
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=TOML, env="DEVELOPMENT")
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=TOML)
+    assert settings.HOST == "prodserver.com"
+
+
+def test_load_from_multiple_toml():
+    """Assert loads from TOML string"""
+    load(settings, filename=TOMLS)
+    assert settings.HOST == "othertoml.com"
+    assert settings.PASSWORD == 123456
+    assert settings.SECRET == 42.0
+    assert settings.PORT == 8080
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=TOMLS, env="DEVELOPMENT")
+    assert settings.PORT == 8080
+    assert settings.HOST == "othertoml.com"
+    load(settings, filename=TOMLS)
+    assert settings.HOST == "othertoml.com"
+    assert settings.PASSWORD == 123456
+    load(settings, filename=TOML, env="DEVELOPMENT")
+    assert settings.PORT == 8080
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=TOML)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PASSWORD == 11111
+
+
+def test_no_filename_is_none():
+    """Assert if passed no filename return is None"""
+    assert load(settings) is None
+
+
+def test_key_error_on_invalid_env():
+    """Assert error raised if env is not found in TOML"""
+    with pytest.raises(KeyError):
+        load(settings, filename=TOML, env="FOOBAR", silent=False)
+
+
+def test_no_key_error_on_invalid_env():
+    """Assert error raised if env is not found in TOML"""
+    load(settings, filename=TOML, env="FOOBAR", silent=True)
+
+
+def test_load_single_key():
+    """Test loading a single key"""
+    toml = """
+    a = "a,b"
+    [foo]
+    bar = "blaz"
+    ZAZ = "naz"
+    lowerkey = 'hello'
+    UPPERKEY = 'world'
+    """
+    load(settings, filename=toml, env="FOO", key="bar")
+    assert settings.BAR == "blaz"
+    assert settings.exists("BAR") is True
+    assert settings.exists("ZAZ") is False
+    load(settings, filename=toml, env="FOO", key="ZAZ")
+    assert settings.ZAZ == "naz"
+    load(settings, filename=toml, env="FOO", key="LOWERKEY")
+    assert settings.LOWERKEY == "hello"
+    load(settings, filename=toml, env="FOO", key="upperkey")
+    assert settings.UPPERKEY == "world"
+
+
+def test_empty_value():
+    load(settings, filename="")
+
+
+def test_multiple_filenames():
+    load(settings, filename="a.toml,b.tml,c.toml,d.tml")
+
+
+def test_cleaner():
+    load(settings, filename=TOML)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PORT == 8080
+    assert settings.ALIST == ["item1", "item2", 23]
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=TOML, env="DEVELOPMENT")
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=TOML)
+    assert settings.HOST == "prodserver.com"
+
+    settings.clean()
+    with pytest.raises(AttributeError):
+        assert settings.HOST == "prodserver.com"
+
+
+def test_using_env(tmpdir):
+    load(settings, filename=TOML)
+    assert settings.HOST == "prodserver.com"
+
+    tmpfile = tmpdir.mkdir("sub").join("test_using_env.toml")
+    tmpfile.write(TOML)
+    with settings.using_env("DEVELOPMENT", filename=str(tmpfile)):
+        assert settings.HOST == "devserver.com"
+    assert settings.HOST == "prodserver.com"
+
+
+def test_load_dunder():
+    """Test load with dunder settings"""
+    toml = """
+    a = "a,b"
+    [foo]
+    colors__gray__code = '#CCCCCC'
+    COLORS__gray__name = 'Gray'
+    """
+    load(settings, filename=toml, env="FOO")
+    assert settings.COLORS.gray.code == "#CCCCCC"
+    assert settings.COLORS.gray.name == "Gray"
+
+
+def test_encode_nulls():
+    assert encode_nulls(None) == "@none "
+    assert encode_nulls([None, None]) == ["@none ", "@none "]
+    assert encode_nulls((None, None)) == ["@none ", "@none "]
+    assert encode_nulls({"nullable": None}) == {"nullable": "@none "}
+    assert encode_nulls(1) == 1
+    assert encode_nulls(1.1) == 1.1
+    assert encode_nulls(True) is True
+    assert encode_nulls(False) is False
+    assert encode_nulls("") == ""
+    assert encode_nulls("text") == "text"
+
+
+def test_envless():
+    settings = LazySettings()
+    ini = """
+    a = "a,b"
+    colors__white__code = '#FFFFFF'
+    COLORS__white__name = 'white'
+    """
+    load(settings, filename=ini)
+    assert settings.a == "a,b"
+    assert settings.COLORS.white.code == "#FFFFFF"
+    assert settings.COLORS.white.name == "white"
+
+
+def test_prefix():
+    settings = LazySettings(filter_strategy=PrefixFilter("prefix"))
+    ini = """
+    prefix_a = "a,b"
+    prefix_colors__white__code = '#FFFFFF'
+    COLORS__white__name = 'white'
+    """
+    load(settings, filename=ini)
+    assert settings.a == "a,b"
+    assert settings.COLORS.white.code == "#FFFFFF"
+    with pytest.raises(AttributeError):
+        settings.COLORS.white.name
diff --git a/tests/test_utils.py b/tests/test_utils.py
new file mode 100644
index 0000000..f664a9b
--- /dev/null
+++ b/tests/test_utils.py
@@ -0,0 +1,484 @@
+from __future__ import annotations
+
+import io
+import json
+import os
+from collections import namedtuple
+
+import pytest
+
+from dynaconf import default_settings
+from dynaconf import Dynaconf
+from dynaconf.loaders.json_loader import DynaconfEncoder
+from dynaconf.utils import build_env_list
+from dynaconf.utils import ensure_a_list
+from dynaconf.utils import extract_json_objects
+from dynaconf.utils import isnamedtupleinstance
+from dynaconf.utils import Missing
+from dynaconf.utils import missing
+from dynaconf.utils import object_merge
+from dynaconf.utils import trimmed_split
+from dynaconf.utils import upperfy
+from dynaconf.utils.files import find_file
+from dynaconf.utils.files import get_local_filename
+from dynaconf.utils.parse_conf import evaluate_lazy_format
+from dynaconf.utils.parse_conf import Formatters
+from dynaconf.utils.parse_conf import Lazy
+from dynaconf.utils.parse_conf import parse_conf_data
+from dynaconf.utils.parse_conf import try_to_encode
+from dynaconf.utils.parse_conf import unparse_conf_data
+
+
+def test_isnamedtupleinstance():
+    """Assert that isnamedtupleinstance works as expected"""
+    Db = namedtuple("Db", ["host", "port"])
+    assert isnamedtupleinstance(Db(host="localhost", port=3306))
+    assert not isnamedtupleinstance(dict(host="localhost", port=3306.0))
+    assert not isnamedtupleinstance(("localhost", "3306"))
+
+    class Foo(tuple):
+        def _fields(self):
+            return ["a", "b"]
+
+    assert not isnamedtupleinstance(Foo())
+
+
+def test_unparse():
+    """Assert bare types are reversed cast"""
+    assert unparse_conf_data("teste") == "teste"
+    assert unparse_conf_data(123) == "@int 123"
+    assert unparse_conf_data(123.4) == "@float 123.4"
+    assert unparse_conf_data(False) == "@bool False"
+    assert unparse_conf_data(True) == "@bool True"
+    assert unparse_conf_data(["a", "b"]) == '@json ["a", "b"]'
+    assert unparse_conf_data({"name": "Bruno"}) == '@json {"name": "Bruno"}'
+    assert unparse_conf_data(None) == "@none "
+    assert unparse_conf_data(Lazy("{foo}")) == "@format {foo}"
+
+
+def test_cast_bool(settings):
+    """Covers https://github.com/dynaconf/dynaconf/issues/14"""
+    assert parse_conf_data(False, box_settings=settings) is False
+    assert settings.get("SIMPLE_BOOL", cast="@bool") is False
+
+
+def test_find_file(tmpdir):
+    """
+    Create a temporary folder structure like the following:
+        tmpXiWxa5/
+        └── child1
+            └── child2
+                └── child3
+                    └── child4
+                       └── .env
+                       └── app.py
+
+    1) Then try to automatically `find_dotenv` starting in `child4`
+    """
+
+    curr_dir = tmpdir
+    dirs = []
+    for f in ["child1", "child2", "child3", "child4"]:
+        curr_dir = os.path.join(str(curr_dir), f)
+        dirs.append(curr_dir)
+        os.mkdir(curr_dir)
+
+    child4 = dirs[-1]
+
+    assert find_file("file-does-not-exist") == ""
+    assert find_file("/abs-file-does-not-exist") == ""
+
+    for _dir in dirs:
+        # search for abspath return the same path
+        assert os.path.isabs(_dir)
+        assert find_file(_dir) == _dir
+
+    # now place a .env file a few levels up and make sure it's found
+    filename = os.path.join(str(child4), ".env")
+    with open(
+        filename, "w", encoding=default_settings.ENCODING_FOR_DYNACONF
+    ) as f:
+        f.write("TEST=test\n")
+
+    assert find_file(project_root=str(child4)) == filename
+
+    # skip the inner child4/.env and force the find of /tmp.../.env
+    assert find_file(
+        project_root=str(child4), skip_files=[filename]
+    ) == os.path.join(str(tmpdir), ".env")
+
+
+def test_casting_str(settings):
+    res = parse_conf_data("@str 7")
+    assert isinstance(res, str) and res == "7"
+
+    settings.set("value", 7)
+    res = parse_conf_data("@str @jinja {{ this.value }}")(settings)
+    assert isinstance(res, str) and res == "7"
+
+    res = parse_conf_data("@str @format {this.value}")(settings)
+    assert isinstance(res, str) and res == "7"
+
+
+def test_casting_int(settings):
+    res = parse_conf_data("@int 2")
+    assert isinstance(res, int) and res == 2
+
+    settings.set("value", 2)
+    res = parse_conf_data("@int @jinja {{ this.value }}")(settings)
+    assert isinstance(res, int) and res == 2
+
+    res = parse_conf_data("@int @format {this.value}")(settings)
+    assert isinstance(res, int) and res == 2
+
+
+def test_casting_float(settings):
+    res = parse_conf_data("@float 0.3")
+    assert isinstance(res, float) and abs(res - 0.3) < 1e-6
+
+    settings.set("value", 0.3)
+    res = parse_conf_data("@float @jinja {{ this.value }}")(settings)
+    assert isinstance(res, float) and abs(res - 0.3) < 1e-6
+
+    res = parse_conf_data("@float @format {this.value}")(settings)
+    assert isinstance(res, float) and abs(res - 0.3) < 1e-6
+
+
+def test_casting_bool(settings):
+    res = parse_conf_data("@bool true")
+    assert isinstance(res, bool) and res is True
+
+    settings.set("value", "true")
+    res = parse_conf_data("@bool @jinja {{ this.value }}")(settings)
+    assert isinstance(res, bool) and res is True
+
+    settings.set("value", "false")
+    res = parse_conf_data("@bool @format {this.value}")(settings)
+    assert isinstance(res, bool) and res is False
+
+
+def test_casting_json(settings):
+    res = parse_conf_data("""@json {"FOO": "bar"}""")
+    assert isinstance(res, dict)
+    assert "FOO" in res and "bar" in res.values()
+
+    # Test how single quotes cases are handled.
+    # When jinja uses `attr` to render a json string,
+    # it may convert double quotes to single quotes.
+    settings.set("value", "{'FOO': 'bar'}")
+    res = parse_conf_data("@json @jinja {{ this.value }}")(settings)
+    assert isinstance(res, dict)
+    assert "FOO" in res and "bar" in res.values()
+
+    res = parse_conf_data("@json @format {this.value}")(settings)
+    assert isinstance(res, dict)
+    assert "FOO" in res and "bar" in res.values()
+
+    # Test jinja rendering a dict
+    settings.set("value", "OPTION1")
+    settings.set("OPTION1", {"bar": 1})
+    settings.set("OPTION2", {"bar": 2})
+    res = parse_conf_data("@jinja {{ this|attr(this.value) }}")(settings)
+    assert isinstance(res, str)
+    res = parse_conf_data("@json @jinja {{ this|attr(this.value) }}")(settings)
+    assert isinstance(res, dict)
+    assert "bar" in res and res["bar"] == 1
+
+
+def test_disable_cast(monkeypatch):
+    # this casts for int
+    assert parse_conf_data("@int 42", box_settings={}) == 42
+    # now gives pure string
+    with monkeypatch.context() as m:
+        m.setenv("AUTO_CAST_FOR_DYNACONF", "off")
+        assert parse_conf_data("@int 42", box_settings={}) == "@int 42"
+
+
+def test_disable_cast_on_instance():
+    settings = Dynaconf(auto_cast=False, environments=True)
+    assert settings.auto_cast_for_dynaconf is False
+    settings.set("SIMPLE_INT", "@int 42")
+    assert settings.get("SIMPLE_INT") == "@int 42"
+
+
+def test_tomlfy(settings):
+    assert parse_conf_data("1", tomlfy=True, box_settings=settings) == 1
+    assert parse_conf_data("true", tomlfy=True, box_settings=settings) is True
+    assert (
+        parse_conf_data("'true'", tomlfy=True, box_settings=settings) == "true"
+    )
+    assert parse_conf_data('"42"', tomlfy=True, box_settings=settings) == "42"
+    assert parse_conf_data(
+        "[1, 32, 3]", tomlfy=True, box_settings=settings
+    ) == [1, 32, 3]
+    assert parse_conf_data(
+        "[1.1, 32.1, 3.3]", tomlfy=True, box_settings=settings
+    ) == [1.1, 32.1, 3.3]
+    assert parse_conf_data(
+        "['a', 'b', 'c']", tomlfy=True, box_settings=settings
+    ) == ["a", "b", "c"]
+    assert parse_conf_data(
+        "[true, false]", tomlfy=True, box_settings=settings
+    ) == [True, False]
+    assert parse_conf_data(
+        "{key='value', v=1}", tomlfy=True, box_settings=settings
+    ) == {"key": "value", "v": 1}
+
+
+@pytest.mark.parametrize("test_input", ["something=42"])
+def test_tomlfy_unparseable(test_input, settings):
+    assert (
+        parse_conf_data(test_input, tomlfy=True, box_settings=settings)
+        == test_input
+    )
+
+
+def test_missing_sentinel():
+
+    # The missing singleton should always compare truthfully to itself
+    assert missing == missing
+
+    # new instances of Missing should be equal to each other due to
+    # explicit __eq__ implementation check for isinstance.
+    assert missing == Missing()
+
+    # The sentinel should not be equal to None, True, or False
+    assert missing is not None
+    assert missing is not True
+    assert missing is not False
+
+    # But the explicit typecasting of missing to a bool should evaluate to
+    # False
+    assert bool(missing) is False
+
+    assert str(missing) == "<dynaconf.missing>"
+
+
+def test_meta_values(settings):
+    reset = parse_conf_data(
+        "@reset [1, 2]", tomlfy=True, box_settings=settings
+    )
+    assert reset.value == [1, 2]
+    assert reset._dynaconf_reset is True
+    assert "Reset([1, 2])" in repr(reset)
+
+    _del = parse_conf_data("@del", tomlfy=True, box_settings=settings)
+    assert _del.value == ""
+    assert _del._dynaconf_del is True
+    assert "Del()" in repr(_del)
+
+
+def test_merge_existing_list():
+    existing = ["bruno", "karla"]
+    object_merge(existing, existing)
+    # calling twice the same object does not duplicate
+    assert existing == ["bruno", "karla"]
+
+    new = ["erik", "bruno"]
+    object_merge(existing, new)
+    assert new == ["bruno", "karla", "erik", "bruno"]
+
+
+def test_merge_existing_list_unique():
+    existing = ["bruno", "karla"]
+    new = ["erik", "bruno"]
+    object_merge(existing, new, unique=True)
+    assert new == ["karla", "erik", "bruno"]
+
+
+def test_merge_existing_dict():
+    existing = {"host": "localhost", "port": 666}
+    new = {"user": "admin"}
+
+    # calling with same data has no effect
+    object_merge(existing, existing)
+    assert existing == {"host": "localhost", "port": 666}
+
+    object_merge(existing, new)
+    assert new == {"host": "localhost", "port": 666, "user": "admin"}
+
+
+def test_merge_dict_with_meta_values(settings):
+    existing = {"A": 1, "B": 2, "C": 3}
+    new = {
+        "B": parse_conf_data("@del", tomlfy=True, box_settings=settings),
+        "C": parse_conf_data("4", tomlfy=True, box_settings=settings),
+    }
+    object_merge(existing, new)
+    assert new == {"A": 1, "C": 4}
+
+
+def test_trimmed_split():
+    # No sep
+    assert trimmed_split("hello") == ["hello"]
+
+    # a comma sep string
+    assert trimmed_split("ab.toml,cd.yaml") == ["ab.toml", "cd.yaml"]
+    # spaces are trimmed
+    assert trimmed_split(" ab.toml , cd.yaml ") == ["ab.toml", "cd.yaml"]
+
+    # a semicollon sep string
+    assert trimmed_split("ab.toml;cd.yaml") == ["ab.toml", "cd.yaml"]
+    # semicollon are trimmed
+    assert trimmed_split(" ab.toml ; cd.yaml ") == ["ab.toml", "cd.yaml"]
+
+    # has comma and also semicollon (semicollon has precedence)
+    assert trimmed_split("ab.toml,cd.yaml;ef.ini") == [
+        "ab.toml,cd.yaml",
+        "ef.ini",
+    ]
+
+    # has comma and also semicollon (changing precedence)
+    assert trimmed_split("ab.toml,cd.yaml;ef.ini", seps=(",", ";")) == [
+        "ab.toml",
+        "cd.yaml;ef.ini",
+    ]
+
+    # using different separator
+    assert trimmed_split("ab.toml|cd.yaml", seps=("|")) == [
+        "ab.toml",
+        "cd.yaml",
+    ]
+
+
+def test_ensure_a_list():
+
+    # No data is empty list
+    assert ensure_a_list(None) == []
+
+    # Sequence types is only converted
+    assert ensure_a_list([1, 2]) == [1, 2]
+    assert ensure_a_list((1, 2)) == [1, 2]
+    assert ensure_a_list({1, 2}) == [1, 2]
+
+    # A string is trimmed_splitted
+    assert ensure_a_list("ab.toml") == ["ab.toml"]
+    assert ensure_a_list("ab.toml,cd.toml") == ["ab.toml", "cd.toml"]
+    assert ensure_a_list("ab.toml;cd.toml") == ["ab.toml", "cd.toml"]
+
+    # other types get wrapped in a list
+    assert ensure_a_list(1) == [1]
+
+
+def test_get_local_filename():
+    settings_path = os.path.join("foo", "b", "conf.toml")
+    local_path = os.path.join("foo", "b", "conf.local.toml")
+    assert get_local_filename(settings_path) == local_path
+
+
+def test_upperfy():
+    assert upperfy("foo") == "FOO"
+    assert upperfy("foo__bar") == "FOO__bar"
+    assert upperfy("foo__bar__ZAZ") == "FOO__bar__ZAZ"
+    assert (
+        upperfy("foo__bar__ZAZ__naz__TAZ_ZAZ") == "FOO__bar__ZAZ__naz__TAZ_ZAZ"
+    )
+    assert upperfy("foo_bar") == "FOO_BAR"
+    assert upperfy("foo_BAR") == "FOO_BAR"
+
+
+def test_lazy_format_class():
+    value = Lazy("{this[FOO]}/bar")
+    settings = {"FOO": "foo"}
+    assert value(settings) == "foo/bar"
+    assert str(value) == value.value
+    assert repr(value) == f"'@{value.formatter} {value.value}'"
+
+
+def test_evaluate_lazy_format_decorator(settings):
+    class Settings:
+        FOO = "foo"
+        AUTO_CAST_FOR_DYNACONF = True
+
+        @evaluate_lazy_format
+        def get(self, key, default=None):
+            if key.endswith("_FOR_DYNACONF"):
+                return getattr(self, key)
+            return parse_conf_data("@format {this.FOO}/bar", box_settings=self)
+
+    settings = Settings()
+    assert settings.get("foo") == "foo/bar"
+
+
+def test_lazy_format_on_settings(settings):
+    os.environ["ENV_THING"] = "LazyFormat"
+    settings.set("set_1", "really")
+    settings.set("lazy", "@format {env[ENV_THING]}/{this[set_1]}/{this.SET_2}")
+    settings.set("set_2", "works")
+
+    assert settings.LAZY == settings.get("lazy") == "LazyFormat/really/works"
+
+
+def test_lazy_format_class_jinja():
+    value = Lazy("{{this['FOO']}}/bar", formatter=Formatters.jinja_formatter)
+    settings = {"FOO": "foo"}
+    assert value(settings) == "foo/bar"
+
+
+def test_evaluate_lazy_format_decorator_jinja(settings):
+    class Settings:
+        FOO = "foo"
+
+        AUTO_CAST_FOR_DYNACONF = True
+
+        @evaluate_lazy_format
+        def get(self, key, default=None):
+            if key.endswith("_FOR_DYNACONF"):
+                return getattr(self, key)
+            return parse_conf_data(
+                "@jinja {{this.FOO}}/bar", box_settings=settings
+            )
+
+    settings = Settings()
+    assert settings.get("foo") == "foo/bar"
+
+
+def test_lazy_format_on_settings_jinja(settings):
+    os.environ["ENV_THING"] = "LazyFormat"
+    settings.set("set_1", "really")
+    settings.set(
+        "lazy", "@jinja {{env.ENV_THING}}/{{this['set_1']}}/{{this.SET_2}}"
+    )
+    settings.set("set_2", "works")
+
+    assert settings.LAZY == settings.get("lazy") == "LazyFormat/really/works"
+
+
+def test_lazy_format_is_json_serializable():
+    value = Lazy("{this[FOO]}/bar")
+    assert (
+        json.dumps({"val": value}, cls=DynaconfEncoder)
+        == '{"val": "@format {this[FOO]}/bar"}'
+    )
+
+
+def test_try_to_encode():
+    value = Lazy("{this[FOO]}/bar")
+    assert try_to_encode(value) == "@format {this[FOO]}/bar"
+
+
+def test_del_raises_on_unwrap(settings):
+    value = parse_conf_data("@del ", box_settings=settings)
+    with pytest.raises(ValueError):
+        value.unwrap()
+
+
+def test_extract_json():
+    assert list(extract_json_objects("foo bar")) == []
+    assert list(extract_json_objects('foo bar {"a": 1}')) == [{"a": 1}]
+    assert list(extract_json_objects("foo bar {'a': 2{")) == []
+    assert list(extract_json_objects('{{{"x": {}}}}')) == [{"x": {}}]
+
+
+def test_env_list():
+    class Obj(dict):
+        @property
+        def current_env(self):
+            return "other"
+
+    assert build_env_list(Obj(), env="OTHER") == [
+        "default",
+        "dynaconf",
+        "other",
+        "global",
+    ]
diff --git a/tests/test_validators.py b/tests/test_validators.py
new file mode 100644
index 0000000..07f3ebe
--- /dev/null
+++ b/tests/test_validators.py
@@ -0,0 +1,877 @@
+from __future__ import annotations
+
+import os
+from types import MappingProxyType
+
+import pytest
+
+from dynaconf import Dynaconf
+from dynaconf import LazySettings
+from dynaconf import ValidationError
+from dynaconf import Validator
+from dynaconf.validator import ValidatorList
+
+
+TOML = """
+[default]
+EXAMPLE = true
+MYSQL_HOST = 'localhost'
+DEV_SERVERS = ['127.0.0.1', 'localhost', 'development.com']
+VERSION = 1
+AGE = 15
+NAME = 'BRUNO'
+PORT = 8001
+BASE_IMAGE = 'bla'
+PRESIDENT = 'Lula'
+PROJECT = 'hello_world'
+SALARY = 2000
+WORKS = 'validator'
+ZERO = 0
+FALSE = false
+
+[development]
+MYSQL_HOST = 'development.com'
+VERSION = 1
+AGE = 15
+NAME = 'MIKE'
+IMAGE_1 = 'aaa'
+IMAGE_2 = 'bbb'
+IMAGE_4 = 'a'
+IMAGE_5 = 'b'
+
+[production]
+MYSQL_HOST = 'production.com'
+VERSION = 1
+AGE = 15
+NAME = 'MIKE'
+IMAGE_4 = 'a'
+IMAGE_5 = 'b'
+
+[global]
+MYSQL_PASSWD = "SuperSecret"
+TESTVALUE = "value"
+"""
+
+YAML = """
+server:
+    hostname: "localhost"
+    port: 22
+    users:
+      - "Bruno"
+      - "Lula"
+app:
+    name: "testname"
+    path: "/tmp/app_startup"
+    args:
+        arg1: "a"
+        arg2: "b"
+        arg3: "c"
+
+hasemptyvalues:
+    key1:
+    key2:
+    key3: null
+    key4: "@empty"
+"""
+
+
+@pytest.fixture
+def yaml_validators_good():
+    return [
+        Validator(
+            "server.hostname", "server.port", "server.users", must_exist=True
+        ),
+        Validator(
+            "app.name",
+            "app.path",
+            "app.args.arg1",
+            "app.args.arg2",
+            "app.args.arg3",
+            must_exist=True,
+        ),
+    ]
+
+
+@pytest.fixture
+def yaml_validators_bad():
+    return [
+        Validator("missing.value", must_exist=True),
+        Validator("app.missing", must_exist=True),
+        Validator("app.args.missing", must_exist=True),
+    ]
+
+
+@pytest.fixture
+def yaml_validators_mixed(yaml_validators_good, yaml_validators_bad):
+    mixed = []
+    mixed.extend(yaml_validators_good)
+    mixed.extend(yaml_validators_bad)
+    return mixed
+
+
+def test_validators_on_init(tmpdir):
+    TOML = """
+    [default]
+    hostname = 'devserver.com'
+    username = 'admin'
+    """
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(
+        environments=True,
+        settings_file=str(tmpfile),
+        validators=(
+            Validator("hostname", eq="devserver.com"),
+            Validator("username", ne="admin"),
+        ),
+    )
+
+    with pytest.raises(ValidationError):
+        settings.HOSTNAME
+
+
+def test_validators_register(tmpdir):
+
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(
+        environments=True,
+        ENV_FOR_DYNACONF="EXAMPLE",
+        SETTINGS_FILE_FOR_DYNACONF=str(tmpfile),
+        silent=True,
+    )
+    settings.validators.register(
+        Validator("VERSION", "AGE", "NAME", must_exist=True),
+        Validator("AGE", lte=30, gte=10),
+        Validator("PROJECT", eq="hello_world"),
+        Validator("PRESIDENT", env="DEVELOPMENT", ne="Trump"),
+        Validator("SALARY", lt=1000000, gt=1000),
+        Validator("DEV_SERVERS", must_exist=True, is_type_of=(list, tuple)),
+        Validator("MYSQL_HOST", env="DEVELOPMENT", is_in=settings.DEV_SERVERS),
+        Validator(
+            "MYSQL_HOST", env="PRODUCTION", is_not_in=settings.DEV_SERVERS
+        ),
+        Validator("NAME", condition=lambda x: x in ("BRUNO", "MIKE")),
+        Validator(
+            "IMAGE_1",
+            "IMAGE_2",
+            env="development",
+            must_exist=True,
+            when=Validator(
+                "BASE_IMAGE", must_exist=True, env=settings.ENV_FOR_DYNACONF
+            ),
+        ),
+        Validator(
+            "IMAGE_4",
+            "IMAGE_5",
+            env=("development", "production"),
+            must_exist=True,
+            when=Validator(
+                "BASE_IMAGE", must_exist=False, env=settings.ENV_FOR_DYNACONF
+            ),
+        ),
+        Validator(
+            "PORT",
+            must_exist=True,
+            ne=8000,
+            when=Validator("MYSQL_HOST", eq="localhost"),
+        ),
+        #
+        Validator("ZERO", is_type_of=int, eq=0),
+        Validator("FALSE", is_type_of=bool, eq=False),
+        Validator("NAME", len_min=3, len_max=125),
+        Validator("DEV_SERVERS", cont="localhost"),
+        Validator("PORT", condition=lambda value: len(str(value)) == 4),
+        Validator("PROJECT", len_ne=0),
+    )
+
+    assert settings.validators.validate() is None
+
+    settings.validators.register(
+        Validator("TESTVALUEZZ", env="development"),
+        Validator("TESTVALUE", eq="hello_world"),
+    )
+
+    with pytest.raises(ValidationError):
+        settings.validators.validate()
+
+    with pytest.raises(TypeError):
+        Validator("A", condition=1)
+
+    with pytest.raises(TypeError):
+        Validator("A", when=1)
+
+
+def test_dotted_validators(settings):
+
+    settings.set(
+        "PARAMS",
+        {"PASSWORD": "secret", "SSL": {"CONTEXT": "SECURE", "ENABLED": True}},
+    )
+
+    settings.validators.register(
+        Validator("PARAMS", must_exist=True, is_type_of=dict),
+        Validator("PARAMS.PASSWORD", must_exist=True, is_type_of=str),
+        Validator("PARAMS.SSL", must_exist=True, is_type_of=dict),
+        Validator("PARAMS.SSL.ENABLED", must_exist=True, is_type_of=bool),
+        Validator("PARAMS.NONEXISTENT", must_exist=False, is_type_of=str),
+    )
+
+    assert settings.validators.validate() is None
+
+
+@pytest.mark.parametrize(
+    "validator_instance",
+    [
+        Validator("TESTVALUE", eq="hello_world"),
+        Validator("PROJECT", condition=lambda x: False, env="development"),
+        Validator("TESTVALUEZZ", must_exist=True),
+        Validator("TESTVALUEZZ", "PROJECT", must_exist=False),
+    ],
+)
+def test_validation_error(validator_instance, tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(
+        environments=True,
+        ENV_FOR_DYNACONF="EXAMPLE",
+        SETTINGS_FILE_FOR_DYNACONF=str(tmpfile),
+        silent=True,
+    )
+    settings.validators.register(validator_instance)
+    with pytest.raises(ValidationError):
+        settings.validators.validate()
+
+
+def test_no_reload_on_single_env(tmpdir, mocker):
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+
+    same_env_validator = Validator(
+        "VERSION", is_type_of=int, env="development"
+    )
+    other_env_validator = Validator("NAME", must_exist=True, env="production")
+
+    settings = LazySettings(
+        environments=True,
+        ENV_FOR_DYNACONF="DEVELOPMENt",
+        SETTINGS_FILE_FOR_DYNACONF=str(tmpfile),
+    )
+    using_env = mocker.patch.object(settings, "from_env")
+
+    settings.validators.register(same_env_validator)
+    settings.validators.validate()
+    using_env.assert_not_called()
+
+    settings.validators.register(other_env_validator)
+    settings.validators.validate()
+    using_env.assert_any_call("production")
+    assert using_env.call_count == 1
+
+
+@pytest.mark.parametrize(
+    "this_validator,another_validator",
+    [
+        (
+            Validator("VERSION", "AGE", "NAME", must_exist=True),
+            Validator("VERSION", "AGE", "NAME", must_exist=True),
+        ),
+        (
+            Validator("VERSION") | Validator("AGE"),
+            Validator("VERSION") | Validator("AGE"),
+        ),
+        (
+            Validator("VERSION") & Validator("AGE"),
+            Validator("VERSION") & Validator("AGE"),
+        ),
+    ],
+)
+def test_equality(this_validator, another_validator):
+    assert this_validator == another_validator
+    assert this_validator is not another_validator
+
+
+@pytest.mark.parametrize(
+    "this_validator,another_validator",
+    [
+        (
+            Validator(
+                "IMAGE_1", when=Validator("BASE_IMAGE", must_exist=True)
+            ),
+            Validator(
+                "IMAGE_1", when=Validator("MYSQL_HOST", must_exist=True)
+            ),
+        ),
+        (Validator("VERSION"), Validator("VERSION") & Validator("AGE")),
+        (Validator("VERSION"), Validator("VERSION") | Validator("AGE")),
+        (
+            Validator("VERSION") | Validator("AGE"),
+            Validator("VERSION") & Validator("AGE"),
+        ),
+        (
+            Validator("VERSION") | Validator("AGE"),
+            Validator("NAME") | Validator("BASE_IMAGE"),
+        ),
+    ],
+)
+def test_inequality(this_validator, another_validator):
+    assert this_validator != another_validator
+
+
+def test_ignoring_duplicate_validators(tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(
+        environments=True,
+        ENV_FOR_DYNACONF="EXAMPLE",
+        SETTINGS_FILE_FOR_DYNACONF=str(tmpfile),
+        silent=True,
+    )
+
+    validator1 = Validator("VERSION", "AGE", "NAME", must_exist=True)
+    settings.validators.register(
+        validator1, Validator("VERSION", "AGE", "NAME", must_exist=True)
+    )
+
+    assert len(settings.validators) == 1
+
+    settings.validators.register(validator1)
+
+    assert len(settings.validators) == 1
+
+
+def test_validator_equality_by_identity():
+    validator1 = Validator("FOO", must_exist=True)
+    validator2 = validator1
+    assert validator1 == validator2
+
+
+def test_validator_custom_message(tmpdir):
+    """Assert custom message is being processed by validator."""
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(
+        environments=True, SETTINGS_FILE_FOR_DYNACONF=str(tmpfile), silent=True
+    )
+
+    custom_msg = "You cannot set {name} to {value} in env {env}"
+    settings.validators.register(
+        Validator("MYSQL_HOST", eq="development.com", env="DEVELOPMENT"),
+        Validator("MYSQL_HOST", ne="development.com", env="PRODUCTION"),
+        Validator("VERSION", ne=1, messages={"operations": custom_msg}),
+    )
+
+    with pytest.raises(ValidationError) as error:
+        settings.validators.validate()
+
+    assert custom_msg.format(
+        name="VERSION", value="1", env="DEVELOPMENT"
+    ) in str(error)
+
+
+def test_validate_all(tmpdir):
+    """Assert custom message is being processed by validator."""
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(
+        environments=True, SETTINGS_FILE_FOR_DYNACONF=str(tmpfile), silent=True
+    )
+
+    custom_msg = "You cannot set {name} to {value} in env {env}"
+    settings.validators.register(
+        Validator("MYSQL_HOST", eq="development.com", env="DEVELOPMENT"),
+        Validator("MYSQL_HOST", ne="development.com", env="PRODUCTION"),
+        Validator("VERSION", ne=1, messages={"operations": custom_msg}),
+        Validator("BLABLABLA", must_exist=True),
+    )
+
+    with pytest.raises(ValidationError) as error:
+        settings.validators.validate_all()
+
+    assert (
+        custom_msg.format(name="VERSION", value="1", env="DEVELOPMENT")
+        in error.value.message
+    )
+    assert "BLABLABLA" in error.value.message
+
+    assert error.type == ValidationError
+    assert len(error.value.details) == 2
+
+
+def test_validator_subclass_messages(tmpdir):
+    """Assert message can be customized via class attributes"""
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+
+    settings = LazySettings(
+        environments=True, SETTINGS_FILE_FOR_DYNACONF=str(tmpfile), silent=True
+    )
+
+    class MyValidator(Validator):
+        default_messages = MappingProxyType(
+            {
+                "must_exist_true": "{name} should exist in {env}",
+                "must_exist_false": "{name} CANNOT BE THERE IN {env}",
+                "condition": (
+                    "{name} BROKE THE {function}({value}) IN env {env}"
+                ),
+                "operations": (
+                    "{name} SHOULD BE {operation} {op_value} "
+                    "BUT YOU HAVE {value} IN ENV {env}, PAY ATTENTION!"
+                ),
+            }
+        )
+
+    with pytest.raises(ValidationError) as error_custom_message:
+        custom_msg = "You cannot set {name} to {value} in env {env}"
+        MyValidator(
+            "VERSION", ne=1, messages={"operations": custom_msg}
+        ).validate(settings)
+
+    assert custom_msg.format(
+        name="VERSION", value="1", env="DEVELOPMENT"
+    ) in str(error_custom_message)
+
+    with pytest.raises(ValidationError) as error_operations:
+        MyValidator("VERSION", ne=1).validate(settings)
+
+    assert (
+        "VERSION SHOULD BE ne 1 "
+        "BUT YOU HAVE 1 IN ENV DEVELOPMENT, "
+        "PAY ATTENTION!"
+    ) in str(error_operations)
+
+    with pytest.raises(ValidationError) as error_conditions:
+        MyValidator("VERSION", condition=lambda value: False).validate(
+            settings
+        )
+
+    assert ("VERSION BROKE THE <lambda>(1) IN env DEVELOPMENT") in str(
+        error_conditions
+    )
+
+    with pytest.raises(ValidationError) as error_must_exist_false:
+        MyValidator("VERSION", must_exist=False).validate(settings)
+
+    assert ("VERSION CANNOT BE THERE IN DEVELOPMENT") in str(
+        error_must_exist_false
+    )
+
+    with pytest.raises(ValidationError) as error_must_exist_true:
+        MyValidator("BLARGVARGST_DONT_EXIST", must_exist=True).validate(
+            settings
+        )
+
+    assert ("BLARGVARGST_DONT_EXIST should exist in DEVELOPMENT") in str(
+        error_must_exist_true
+    )
+
+
+def test_positive_combined_validators(tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+    settings = LazySettings(
+        environments=True, SETTINGS_FILE_FOR_DYNACONF=str(tmpfile), silent=True
+    )
+    settings.validators.register(
+        Validator("VERSION", ne=1) | Validator("VERSION", ne=2),
+        Validator("VERSION", ne=4) & Validator("VERSION", ne=2),
+    )
+    settings.validators.validate()
+
+
+def test_negative_combined_or_validators(tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+    settings = LazySettings(
+        environments=True, SETTINGS_FILE_FOR_DYNACONF=str(tmpfile), silent=True
+    )
+    settings.validators.register(
+        Validator("VERSION", ne=1) | Validator("VERSION", ne=1),
+    )
+    with pytest.raises(ValidationError):
+        settings.validators.validate()
+
+
+def test_negative_combined_and_validators(tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+    settings = LazySettings(
+        environments=True, SETTINGS_FILE_FOR_DYNACONF=str(tmpfile), silent=True
+    )
+    settings.validators.register(
+        Validator("VERSION", ne=1) & Validator("VERSION", ne=1),
+    )
+    with pytest.raises(ValidationError):
+        settings.validators.validate()
+
+
+def test_envless_and_combined_validators(tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    TOML = """
+    value = true
+    version = 1
+    name = 'Bruno'
+    """
+    tmpfile.write(TOML)
+    settings = LazySettings(
+        SETTINGS_FILE_FOR_DYNACONF=str(tmpfile), silent=True
+    )
+    settings.validators.register(
+        Validator("VERSION", ne=1) & Validator("value", ne=True),
+    )
+    with pytest.raises(ValidationError):
+        settings.validators.validate()
+
+
+def test_cast_on_validate_transforms_value(tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    TOML = """
+    name = 'Bruno'
+    colors = ['red', 'green', 'blue']
+    """
+    tmpfile.write(TOML)
+    settings = LazySettings(
+        settings_file=str(tmpfile),
+        silent=True,
+        lowercase_read=True,
+        validators=[
+            # Order matters here
+            Validator("name", len_eq=5),
+            Validator("name", len_min=1),
+            Validator("name", len_max=5),
+            # This will cast the str to list
+            Validator("name", cast=list),
+            Validator("colors", len_eq=3),
+            Validator("colors", len_eq=3),
+            # this will cast the list to str
+            Validator("colors", len_eq=24, cast=str),
+        ],
+    )
+    assert settings.name == list("Bruno")
+    assert settings.colors == str(["red", "green", "blue"])
+
+
+def test_validator_can_provide_default(tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    TOML = """
+    name = 'Bruno'
+    colors = ['red', 'green', 'blue']
+    """
+    tmpfile.write(TOML)
+    settings = LazySettings(
+        settings_file=str(tmpfile),
+        validators=[
+            Validator("name", required=True),
+            Validator("FOO", default="BAR"),
+            Validator("COMPUTED", default=lambda st, va: "I am computed"),
+        ],
+    )
+    assert settings.name == "Bruno"
+    assert settings.colors == ["red", "green", "blue"]
+
+    assert settings.FOO == "BAR"
+    assert settings.COMPUTED == "I am computed"
+
+
+def test_validator_init_exclude(tmpdir, yaml_validators_mixed):
+    tmpfile = tmpdir.join("settings.yaml")
+    tmpfile.write(YAML)
+    settings = LazySettings(
+        settings_file=str(tmpfile),
+        validators=yaml_validators_mixed,
+        validate_exclude=["missing", "app.missing", "app.args.missing"],
+    )
+    assert settings.server.hostname == "localhost"
+
+
+def test_validator_init_only(tmpdir, yaml_validators_mixed):
+    tmpfile = tmpdir.join("settings.yaml")
+    tmpfile.write(YAML)
+    settings = LazySettings(
+        settings_file=str(tmpfile),
+        validators=yaml_validators_mixed,
+        validate_only=["server"],
+    )
+    assert settings.server.hostname == "localhost"
+
+
+def test_validator_init_mixed(tmpdir, yaml_validators_mixed):
+    tmpfile = tmpdir.join("settings.yaml")
+    tmpfile.write(YAML)
+    settings = LazySettings(
+        settings_file=str(tmpfile),
+        validators=yaml_validators_mixed,
+        validate_only=["server", "app"],
+        validate_exclude=["app.missing", "app.args.missing"],
+    )
+    assert settings.server.hostname == "localhost"
+
+
+def test_validator_only_post_register(
+    tmpdir, yaml_validators_good, yaml_validators_bad
+):
+    tmpfile = tmpdir.join("settings.yaml")
+    tmpfile.write(YAML)
+    settings = LazySettings(
+        settings_file=str(tmpfile),
+        validators=yaml_validators_good,
+        validate_only=["server"],
+    )
+    assert settings.server.hostname == "localhost"
+    settings.validators.register(*yaml_validators_bad)
+    # call validation only on the server section
+    settings.validators.validate(only=["server"])
+
+
+def test_validator_exclude_post_register(
+    tmpdir, yaml_validators_good, yaml_validators_bad
+):
+    tmpfile = tmpdir.join("settings.yaml")
+    tmpfile.write(YAML)
+    settings = LazySettings(
+        settings_file=str(tmpfile),
+        validators=yaml_validators_good,
+        validate_only=["server", "app.path"],
+    )
+    assert settings.server.hostname == "localhost"
+    settings.validators.register(*yaml_validators_bad)
+    # call validation only on the server section
+    settings.validators.validate(
+        exclude=["missing", "app.missing", "app.args.missing"]
+    )
+    settings.app.path = "/tmp/app_startup"
+
+
+def test_validator_only_current_env_valid(tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+    settings = LazySettings(
+        settings_file=str(tmpfile),
+        environments=True,
+        ENV_FOR_DYNACONF="DEVELOPMENT",
+    )
+    settings.validators.register(
+        Validator("IMAGE_1", env="production", must_exist=True)
+    )
+    settings.validators.validate(only_current_env=True)
+
+
+def test_raises_only_current_env_invalid(tmpdir):
+    tmpfile = tmpdir.join("settings.toml")
+    tmpfile.write(TOML)
+    settings = LazySettings(
+        settings_file=str(tmpfile),
+        environments=True,
+        ENV_FOR_DYNACONF="PRODUCTION",
+    )
+    settings.validators.register(
+        Validator("IMAGE_1", env="production", must_exist=True)
+    )
+
+    with pytest.raises(ValidationError):
+        settings.validators.validate(only_current_env=True)
+
+
+def test_raises_on_invalid_selective_args(tmpdir, yaml_validators_good):
+    settings = LazySettings(validators=yaml_validators_good, validate_only=int)
+    with pytest.raises(ValueError):
+        settings.validator_instance.validate()
+
+    settings = LazySettings(
+        validators=yaml_validators_good, validate_exclude=int
+    )
+    with pytest.raises(ValueError):
+        settings.validator_instance.validate()
+
+
+def test_validator_descriptions(tmpdir):
+    validators = ValidatorList(
+        LazySettings(),
+        validators=[
+            Validator("foo", description="foo"),
+            Validator("bar", description="bar"),
+            Validator("baz", "zaz", description="baz zaz"),
+            Validator("foo", description="another message"),
+            Validator("a", description="a") & Validator("b"),
+        ],
+    )
+
+    assert validators.descriptions() == {
+        "bar": ["bar"],
+        "baz": ["baz zaz"],
+        "zaz": ["baz zaz"],
+        "foo": ["foo", "another message"],
+        "a": ["a"],
+        "b": ["a"],
+    }
+
+
+def test_validator_descriptions_flat(tmpdir):
+    validators = ValidatorList(
+        LazySettings(),
+        validators=[
+            Validator("foo", description="foo"),
+            Validator("bar", description="bar"),
+            Validator("baz", "zaz", description="baz zaz"),
+            Validator("foo", description="another message"),
+            Validator("a", description="a") & Validator("b"),
+        ],
+    )
+
+    assert validators.descriptions(flat=True) == {
+        "bar": "bar",
+        "baz": "baz zaz",
+        "zaz": "baz zaz",
+        "foo": "foo",
+        "a": "a",
+        "b": "a",
+    }
+
+
+def test_toml_should_not_change_validator_type_with_is_type_set():
+    settings = Dynaconf(
+        validators=[Validator("TEST", is_type_of=str, default="+172800")]
+    )
+
+    assert settings.test == "+172800"
+
+
+def test_toml_should_not_change_validator_type_with_is_type_not_set_int():
+    settings = Dynaconf(
+        validators=[Validator("TEST", default="+172800")]
+        # The ways to force a string is
+        # passing is_type_of=str
+        # or default="@str +172800" or default="'+172800'"
+    )
+
+    assert settings.test == +172800
+
+
+def test_toml_should_not_change_validator_type_using_at_sign():
+    settings = Dynaconf(
+        validators=[Validator("TEST", is_type_of=str, default="@str +172800")]
+    )
+
+    assert settings.test == "+172800"
+
+
+def test_default_eq_env_lvl_1():
+    """Tests when the env value equals the default value."""
+    VAR_NAME = "test"
+    ENV = "DYNATESTRUN_TEST"
+    settings = Dynaconf(
+        environments=False,
+        envvar_prefix="DYNATESTRUN",
+        validators=[
+            Validator(
+                VAR_NAME,
+                default=True,
+                is_type_of=bool,
+            ),
+        ],
+    )
+    os.environ[ENV] = "true"
+    assert settings.test is True
+    del os.environ[ENV]
+
+
+def test_default_lvl_1():
+    """Tests if the default works properly without any nested level.
+
+    Uses different values for the default and the environment variable.
+    """
+    VAR_NAME = "test"
+    ENV = "DYNATESTRUN_TEST"
+    settings = Dynaconf(
+        environments=False,
+        envvar_prefix="DYNATESTRUN",
+        validators=[
+            Validator(
+                VAR_NAME,
+                default=True,
+                is_type_of=bool,
+            ),
+        ],
+    )
+    os.environ[ENV] = "false"
+    assert settings.test is False
+    del os.environ[ENV]
+
+
+def test_default_lvl_2():
+    """Tests if the default works properly with one nested level.
+
+    Uses different values for the default and the environment variable.
+    """
+    VAR_NAME = "nested.test"
+    ENV = "DYNATESTRUN_NESTED__TEST"
+    settings = Dynaconf(
+        environments=False,
+        envvar_prefix="DYNATESTRUN",
+        validators=[
+            Validator(
+                VAR_NAME,
+                default=True,
+                is_type_of=bool,
+            ),
+        ],
+    )
+    os.environ[ENV] = "false"
+    assert settings.nested.test is False
+    del os.environ[ENV]
+
+
+def test_use_default_value_when_yaml_is_empty_and_explicitly_marked(tmpdir):
+    tmpfile = tmpdir.join("settings.yaml")
+    tmpfile.write(YAML)
+    settings = Dynaconf(
+        settings_file=str(tmpfile),
+        validators=[
+            # Explicitly say thar default must be applied to None
+            Validator(
+                "hasemptyvalues.key1",
+                default="value1",
+                apply_default_on_none=True,
+            ),
+            # The following 2 defaults must be ignored
+            Validator("hasemptyvalues.key2", default="value2"),
+            Validator("hasemptyvalues.key3", default="value3"),
+            # This one must be set because on YAML key is set to `@empty`
+            Validator("hasemptyvalues.key4", default="value4"),
+        ],
+    )
+    assert settings.hasemptyvalues.key1 == "value1"
+    assert settings.hasemptyvalues.key2 is None
+    assert settings.hasemptyvalues.key3 is None
+    assert settings.hasemptyvalues.key4 == "value4"
+
+
+def test_ensure_cast_happens_after_must_exist(tmpdir):
+    """#823"""
+    from pathlib import Path
+
+    settings = Dynaconf(
+        validators=[Validator("java_bin", must_exist=True, cast=Path)]
+    )
+    # must raise ValidationError instead of Path error
+    with pytest.raises(ValidationError):
+        settings.validators.validate()
+
+
+def test_ensure_cast_works_for_non_default_values(tmpdir):
+    """#834"""
+
+    settings = Dynaconf(validators=[Validator("offset", default=1, cast=int)])
+
+    settings.offset = "24"
+
+    settings.validators.validate()
+
+    assert isinstance(settings.offset, int), type(settings.offset)
diff --git a/tests/test_validators_conditions.py b/tests/test_validators_conditions.py
new file mode 100644
index 0000000..ff48b8d
--- /dev/null
+++ b/tests/test_validators_conditions.py
@@ -0,0 +1,65 @@
+from __future__ import annotations
+
+import pytest
+
+from dynaconf import validator_conditions
+
+
+positive_conditions = [
+    ("eq", 1, 1),
+    ("ne", 1, 2),
+    ("gt", 4, 3),
+    ("lt", 3, 4),
+    ("gte", 5, 5),
+    ("lte", 5, 5),
+    ("identity", None, None),
+    ("is_type_of", 42, int),
+    ("is_in", 42, [42, 34]),
+    ("is_not_in", 42, [55, 34]),
+    ("cont", "This word(s) contains in text", "in"),
+    ("len_eq", "Length Equal", 12),
+    ("len_eq", [1, 2, 3], 3),
+    ("len_ne", "Length Not equal", 0),
+    ("len_ne", [], 1),
+    ("len_min", "Minimum length", 3),
+    ("len_min", [1, 2, 3, 4, 5], 3),
+    ("len_max", "Maximum length", 15),
+    ("len_max", [1, 2, 3, 4, 5], 5),
+    ("startswith", "codeshow", "code"),
+    ("endswith", "codeshow", "show"),
+]
+
+
+@pytest.mark.parametrize("data", positive_conditions)
+def test_conditions(data):
+    assert getattr(validator_conditions, data[0])(data[1], data[2])
+
+
+negative_conditions = [
+    ("eq", 1, 2),
+    ("ne", 1, 1),
+    ("gt", 4, 4),
+    ("lt", 3, 3),
+    ("gte", 5, 6),
+    ("lte", 5, 4),
+    ("identity", None, 1),
+    ("is_type_of", 42, str),
+    ("is_in", 42, [55, 34]),
+    ("is_not_in", 42, [42, 34]),
+    ("cont", "This word(s) contains in text", "out"),
+    ("len_eq", "Length Equal", 0),
+    ("len_eq", [1, 2, 3], 4),
+    ("len_ne", "Length Not equal", 16),
+    ("len_ne", [], 0),
+    ("len_min", "Minimum length", 15),
+    ("len_min", [1, 2, 3, 4, 5], 6),
+    ("len_max", "Maximum length", 3),
+    ("len_max", [1, 2, 3, 4, 5], 4),
+    ("startswith", "codeshow", "show"),
+    ("endswith", "codeshow", "code"),
+]
+
+
+@pytest.mark.parametrize("data", negative_conditions)
+def test_negative_conditions(data):
+    assert not getattr(validator_conditions, data[0])(data[1], data[2])
diff --git a/tests/test_vault.py b/tests/test_vault.py
new file mode 100644
index 0000000..ad9698c
--- /dev/null
+++ b/tests/test_vault.py
@@ -0,0 +1,109 @@
+from __future__ import annotations
+
+import os
+from time import sleep
+
+import pytest
+
+from dynaconf import LazySettings
+from dynaconf.loaders.vault_loader import list_envs
+from dynaconf.loaders.vault_loader import load
+from dynaconf.loaders.vault_loader import write
+
+
+def custom_checker(ip_address, port):
+    # This function should be check if the redis server is online and ready
+    # write(settings, {"SECRET": "redis_works"})
+    # return load(settings, key="SECRET")
+    return True
+
+
+@pytest.fixture(scope="module")
+def docker_vault(docker_services):
+    docker_services.start("vault")
+    public_port = docker_services.wait_for_service(
+        "vault", 8200, check_server=custom_checker
+    )
+    url = f"http://{docker_services.docker_ip}:{public_port}"
+
+    sleep(3)
+    return url
+
+
+@pytest.mark.integration
+def test_load_vault_not_configured():
+    with pytest.raises(AssertionError) as excinfo:
+        settings = LazySettings(environments=True)
+        load(settings, {"OTHER_SECRET": "vault_works"})
+    assert "Vault authentication error" in str(excinfo.value)
+
+
+@pytest.mark.integration
+def test_write_vault_not_configured():
+    with pytest.raises(RuntimeError) as excinfo:
+        settings = LazySettings(environments=True)
+        write(settings, {"OTHER_SECRET": "vault_works"})
+    assert "export VAULT_ENABLED_FOR_DYNACONF" in str(excinfo.value)
+
+
+@pytest.mark.integration
+def test_write_vault_without_data(docker_vault):
+    os.environ["VAULT_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["VAULT_TOKEN_FOR_DYNACONF"] = "myroot"
+    settings = LazySettings(environments=True)
+    with pytest.raises(AttributeError) as excinfo:
+        write(settings)
+    assert "Data must be provided" in str(excinfo.value)
+
+
+@pytest.mark.integration
+def test_list_envs_in_vault(docker_vault):
+    os.environ["VAULT_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["VAULT_TOKEN_FOR_DYNACONF"] = "myroot"
+    settings = LazySettings(environments=True)
+    envs = list_envs(settings, "test_list_envs_in_vault")
+    assert envs == []
+
+
+@pytest.mark.integration
+def test_write_to_vault(docker_vault):
+    os.environ["VAULT_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["VAULT_TOKEN_FOR_DYNACONF"] = "myroot"
+    settings = LazySettings(environments=True)
+    write(settings, {"SECRET": "vault_works_with_docker"})
+    load(settings, key="SECRET")
+    assert settings.get("SECRET") == "vault_works_with_docker"
+
+
+@pytest.mark.integration
+def test_load_from_vault_with_key(docker_vault):
+    os.environ["VAULT_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["VAULT_TOKEN_FOR_DYNACONF"] = "myroot"
+    settings = LazySettings(environments=True)
+    load(settings, key="SECRET")
+    assert settings.get("SECRET") == "vault_works_with_docker"
+
+
+@pytest.mark.integration
+def test_write_and_load_from_vault_without_key(docker_vault):
+    os.environ["VAULT_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["VAULT_TOKEN_FOR_DYNACONF"] = "myroot"
+    settings = LazySettings(environments=True)
+    write(settings, {"SECRET": "vault_works_perfectly"})
+    load(settings)
+    assert settings.get("SECRET") == "vault_works_perfectly"
+
+
+@pytest.mark.integration
+def test_read_from_vault_kv2_with_different_environments(docker_vault):
+    os.environ["VAULT_ENABLED_FOR_DYNACONF"] = "1"
+    os.environ["VAULT_KV_VERSION_FOR_DYNACONF"] = "2"
+    os.environ["VAULT_TOKEN_FOR_DYNACONF"] = "myroot"
+    settings = LazySettings(environments=["dev", "prod"])
+    for env in ["default", "dev", "prod"]:
+        with settings.using_env(env):
+            write(settings, {"SECRET": f"vault_works_in_{env}"})
+    load(settings)
+    assert settings.secret == "vault_works_in_default"
+    assert settings.from_env("dev").secret == "vault_works_in_dev"
+    assert settings.from_env("prod").secret == "vault_works_in_prod"
diff --git a/tests/test_yaml_loader.py b/tests/test_yaml_loader.py
new file mode 100644
index 0000000..1582bed
--- /dev/null
+++ b/tests/test_yaml_loader.py
@@ -0,0 +1,544 @@
+from __future__ import annotations
+
+import os
+
+import pytest
+
+from dynaconf import LazySettings
+from dynaconf.loaders.yaml_loader import load
+from dynaconf.strategies.filtering import PrefixFilter
+
+
+@pytest.fixture(scope="module")
+def settings():
+    return LazySettings(
+        environments=True,
+        ENV_FOR_DYNACONF="PRODUCTION",
+        # ROOT_PATH_FOR_DYNACONF=os.path.dirname(os.path.abspath(__file__)),
+    )
+
+
+YAML = """
+# the below is just to ensure `,` will not break string YAML
+a: 'a,b'
+default:
+  password: 99999
+  host: server.com
+  port: 8080
+  alist:
+    - item1
+    - item2
+    - 23
+  service:
+    url: service.com
+    port: 80
+    auth:
+      password: qwerty
+      test: 1234
+  spaced key: 1
+  spaced nested:
+    key: 1
+development:
+  password: 88888
+  host: devserver.com
+production:
+  password: 11111
+  host: prodserver.com
+global:
+  global_value: global
+
+"""
+
+YAML2 = """
+global:
+  # @float casting not needed, used only for testing
+  secret: '@float 42'
+  password: 123456
+  host: otheryaml.com
+"""
+
+YAMLS = [YAML, YAML2]
+
+
+def test_load_from_yaml(settings):
+    """Assert loads from YAML string"""
+    load(settings, filename=YAML)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PORT == 8080
+    assert settings.ALIST == ["item1", "item2", 23]
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    assert settings.spaced_key == 1
+    assert settings.spaced_nested.key == 1
+    assert settings.spaced_nested["key"] == 1
+    assert settings["spaced key"] == 1
+    assert settings["SPACED KEY"] == 1
+    load(settings, filename=YAML, env="DEVELOPMENT")
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=YAML)
+    assert settings.HOST == "prodserver.com"
+
+
+def test_load_from_multiple_yaml(settings):
+    """Assert loads from YAML string"""
+    load(settings, filename=YAMLS)
+    assert settings.HOST == "otheryaml.com"
+    assert settings.PASSWORD == 123456
+    assert settings.SECRET == 42.0
+    assert settings.PORT == 8080
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=YAMLS, env="DEVELOPMENT")
+    assert settings.PORT == 8080
+    assert settings.HOST == "otheryaml.com"
+    load(settings, filename=YAMLS)
+    assert settings.HOST == "otheryaml.com"
+    assert settings.PASSWORD == 123456
+    load(settings, filename=YAML, env="DEVELOPMENT")
+    assert settings.PORT == 8080
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=YAML)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PASSWORD == 11111
+
+
+def test_no_filename_is_none(settings):
+    """Assert if passed no filename return is None"""
+    assert load(settings) is None
+
+
+def test_key_error_on_invalid_env(settings):
+    """Assert error raised if env is not found in YAML"""
+    with pytest.raises(KeyError):
+        load(settings, filename=YAML, env="FOOBAR", silent=False)
+
+
+def test_no_key_error_on_invalid_env(settings):
+    """Assert error raised if env is not found in YAML"""
+    load(settings, filename=YAML, env="FOOBAR", silent=True)
+
+
+def test_load_single_key(settings):
+    """Test loading a single key"""
+    yaml = """
+    foo:
+       bar: blaz
+       zaz: naz
+    """
+    load(settings, filename=yaml, env="FOO", key="bar")
+    assert settings.BAR == "blaz"
+    assert settings.exists("BAR") is True
+    assert settings.exists("ZAZ") is False
+
+
+def test_extra_yaml(settings):
+    """Test loading extra yaml file"""
+    load(settings, filename=YAML)
+    yaml = """
+    example:
+       helloexample: world
+    """
+    settings.set("YAML", yaml)
+    settings.execute_loaders(env="EXAMPLE")
+    assert settings.HELLOEXAMPLE == "world"
+
+
+def test_empty_value(settings):
+    load(settings, filename="")
+
+
+def test_multiple_filenames(settings):
+    load(settings, filename="a.yaml,b.yml,c.yaml,d.yml")
+
+
+def test_cleaner(settings):
+    load(settings, filename=YAML)
+    assert settings.HOST == "prodserver.com"
+    assert settings.PORT == 8080
+    assert settings.ALIST == ["item1", "item2", 23]
+    assert settings.SERVICE["url"] == "service.com"
+    assert settings.SERVICE.url == "service.com"
+    assert settings.SERVICE.port == 80
+    assert settings.SERVICE.auth.password == "qwerty"
+    assert settings.SERVICE.auth.test == 1234
+    load(settings, filename=YAML, env="DEVELOPMENT")
+    assert settings.HOST == "devserver.com"
+    load(settings, filename=YAML)
+    assert settings.HOST == "prodserver.com"
+
+    settings.clean()
+    with pytest.raises(AttributeError):
+        assert settings.HOST == "prodserver.com"
+
+
+def test_using_env(tmpdir, settings):
+    load(settings, filename=YAML)
+    assert settings.HOST == "prodserver.com"
+
+    tmpfile = tmpdir.mkdir("sub").join("test_using_env.yaml")
+    tmpfile.write(YAML)
+    with settings.using_env("DEVELOPMENT", filename=str(tmpfile)):
+        assert settings.HOST == "devserver.com"
+    assert settings.HOST == "prodserver.com"
+
+
+def test_load_dunder(settings):
+    """Test load with dunder settings"""
+    yaml = """
+    foo:
+       bar: blaz
+       zaz: naz
+       colors__black__code: '#000000'
+       COLORS__black__name: Black
+    """
+    load(settings, filename=yaml, env="FOO")
+    assert settings.COLORS.black.code == "#000000"
+    assert settings.COLORS.black.name == "Black"
+
+
+def test_local_files(tmpdir):
+
+    settings_file_yaml = """
+    default:
+      name: Bruno
+      colors:
+        - green
+        - blue
+      data:
+        link: brunorocha.org
+      other:
+        foo: bar
+      music:
+        current:
+          volume: 10
+          title: The Beatles - Strawberry Fields
+    """
+    tmpdir.join("settings.yaml").write(settings_file_yaml)
+
+    local_file_yaml = """
+    default:
+      name: Bruno Rocha
+      colors:
+        - red
+        - dynaconf_merge
+      data:
+        city: Guarulhos
+        dynaconf_merge: true
+      other:
+        baz: zaz
+      music__current__volume: 100
+      music__current__title: Led Zeppelin - Immigrant Song
+    """
+    tmpdir.join("settings.local.yaml").write(local_file_yaml)
+
+    conf = LazySettings(environments=True, settings_file="settings.yaml")
+    assert conf.NAME == "Bruno Rocha"
+    assert set(conf.COLORS) == {"red", "green", "blue"}
+    assert conf.DATA.link == "brunorocha.org"
+    assert conf.DATA.city == "Guarulhos"
+    assert conf.OTHER == {"baz": "zaz"}
+    assert conf.MUSIC.current.volume == 100
+    assert conf.MUSIC.current.title == "Led Zeppelin - Immigrant Song"
+
+
+def test_explicit_local_files(tmpdir):
+
+    settings_file_yaml = """
+    default:
+      name: Bruno
+      colors:
+        - green
+        - blue
+      data:
+        link: brunorocha.org
+      other:
+        foo: bar
+      music:
+        current:
+          volume: 10
+          title: The Beatles - Strawberry Fields
+    """
+    tmpdir.join("foo.yaml").write(settings_file_yaml)
+
+    local_file_yaml = """
+    default:
+      name: Bruno Rocha
+      colors:
+        - red
+        - dynaconf_merge
+      data:
+        city: Guarulhos
+        dynaconf_merge: true
+      other:
+        baz: zaz
+      music__current__volume: 100
+      music__current__title: Led Zeppelin - Immigrant Song
+      music__current__even__inner__element: true
+    """
+    tmpdir.join("foo.local.yaml").write(local_file_yaml)
+
+    conf = LazySettings(
+        environments=True,
+        SETTINGS_FILE_FOR_DYNACONF=["foo.yaml", "foo.local.yaml"],
+    )
+
+    assert conf.NAME == "Bruno Rocha"
+    assert set(conf.COLORS) == {"red", "green", "blue"}
+    assert conf.DATA.link == "brunorocha.org"
+    assert conf.DATA.city == "Guarulhos"
+    assert conf.OTHER == {"baz": "zaz"}
+    assert conf.MUSIC.current.volume == 100
+    assert conf.MUSIC.current.title == "Led Zeppelin - Immigrant Song"
+    assert conf.get("music.current.even.inner.element") is True
+
+
+def test_envless():
+    settings = LazySettings()
+    _yaml = """
+    a: a,b
+    colors__white__code: "#FFFFFF"
+    COLORS__white__name: "white"
+    """
+    load(settings, filename=_yaml)
+    assert settings.a == "a,b"
+    assert settings.COLORS.white.code == "#FFFFFF"
+    assert settings.COLORS.white.name == "white"
+
+
+def test_prefix():
+    settings = LazySettings(filter_strategy=PrefixFilter("prefix"))
+    _yaml = """
+    prefix_a: a,b
+    prefix_colors__white__code: "#FFFFFF"
+    COLORS__white__name: "white"
+    """
+    load(settings, filename=_yaml)
+    assert settings.a == "a,b"
+    assert settings.COLORS.white.code == "#FFFFFF"
+    with pytest.raises(AttributeError):
+        settings.COLORS.white.name
+
+
+def test_empty_env():
+    settings = LazySettings(environments=True)
+    _yaml = """
+    default:
+        foo: bar
+    development:
+    """
+    load(settings, filename=_yaml)
+    assert settings.FOO == "bar"
+
+
+def test_empty_env_from_file(tmpdir):
+    """Assert empty env is not crashing on load."""
+    settings_file_yaml = """
+    default:
+        foo: bar
+    development: ~
+    """
+    tmpdir.join("settings.yaml").write(settings_file_yaml)
+    settings = LazySettings(environments=True, settings_file="settings.yaml")
+    settings.reload()
+    assert settings.FOO == "bar"
+
+
+def test_merge_unique_in_a_first_level(tmpdir):
+    """Assert merge unique in a first level."""
+    settings_file_yaml = """
+    default:
+        colors: "@merge_unique green,blue"
+        non_exist: "@merge_unique item1,item2"
+    """
+    tmpdir.join("settings.yaml").write(settings_file_yaml)
+    settings = LazySettings(
+        environments=True,
+        settings_file="settings.yaml",
+        COLORS=["red", "green"],
+    )
+    settings.reload()
+    assert settings.COLORS == ["red", "green", "blue"]
+    assert settings.NON_EXIST == ["item1", "item2"]
+
+
+def test_should_not_merge_if_merge_is_not_explicit_set(tmpdir):
+    """Should not merge if merge is not explicit set."""
+    settings_file_yaml = """
+    default:
+      SOME_KEY: "value"
+      SOME_LIST:
+        - "item_1"
+        - "item_2"
+        - "item_3"
+    other:
+      SOME_KEY: "new_value"
+      SOME_LIST:
+        - "item_4"
+        - "item_5"
+    """
+    tmpdir.join("settings.yaml").write(settings_file_yaml)
+    settings = LazySettings(
+        environments=True,
+        settings_files=["settings.yaml"],
+    )
+    settings.reload()
+    assert settings.SOME_KEY == "value"
+    assert settings.SOME_LIST == ["item_1", "item_2", "item_3"]
+
+    other_settings = settings.from_env("other")
+    assert other_settings.SOME_KEY == "new_value"
+    assert other_settings.SOME_LIST == ["item_4", "item_5"]
+
+
+def test_should_not_duplicate_with_global_merge(tmpdir):
+    """Assert merge unique in a first level. Issue #653"""
+    settings_file_yaml = """
+    default:
+      SOME_KEY: "value"
+      SOME_LIST:
+        - "item_1"
+        - "item_2"
+        - "item_3"
+    other:
+      SOME_KEY: "new_value"
+      SOME_LIST:
+        - "item_4"
+        - "item_5"
+    even_other:
+      SOME_KEY: "new_value_2"
+      SOME_LIST:
+        - "item_6"
+        - "item_7"
+    """
+    tmpdir.join("settings.yaml").write(settings_file_yaml)
+    settings = LazySettings(
+        environments=True, settings_files=["settings.yaml"], merge_enabled=True
+    )
+    # settings.reload()
+    assert settings.SOME_KEY == "value"
+    assert settings.SOME_LIST == ["item_1", "item_2", "item_3"]
+
+    other_settings = settings.from_env("other")
+    assert other_settings.SOME_KEY == "new_value"
+    assert other_settings.SOME_LIST == [
+        "item_1",
+        "item_2",
+        "item_3",
+        "item_4",
+        "item_5",
+    ]
+
+
+def test_should_duplicate_when_explicit_set(tmpdir):
+    """Issue #653"""
+    settings_file_yaml = """
+    default:
+      SCRIPTS:
+        - "script1.sh"
+        - "script2.sh"
+        - "script3.sh"
+    other:
+      SCRIPTS:
+        - "script4.sh"
+        - "script1.sh"
+        - "dynaconf_merge"
+    """
+    tmpdir.join("settings.yaml").write(settings_file_yaml)
+    settings = LazySettings(
+        environments=True, settings_files=["settings.yaml"]
+    )
+    assert settings.SCRIPTS == [
+        "script1.sh",
+        "script2.sh",
+        "script3.sh",
+    ]
+
+    other_settings = settings.from_env("other")
+    assert other_settings.SCRIPTS == [
+        "script1.sh",
+        "script2.sh",
+        "script3.sh",
+        "script4.sh",
+        "script1.sh",  # explicit wants to duplicate
+    ]
+
+
+def test_should_NOT_duplicate_when_explicit_set(tmpdir):
+    """Issue #653"""
+    settings_file_yaml = """
+    default:
+      SCRIPTS:
+        - "script1.sh"
+        - "script2.sh"
+        - "script3.sh"
+    other:
+      SCRIPTS:
+        - "script4.sh"
+        - "script1.sh"
+        - "dynaconf_merge_unique"  # NO DUPLICATE
+    """
+    tmpdir.join("settings.yaml").write(settings_file_yaml)
+    settings = LazySettings(
+        environments=True, settings_files=["settings.yaml"]
+    )
+    assert settings.SCRIPTS == [
+        "script1.sh",
+        "script2.sh",
+        "script3.sh",
+    ]
+
+    other_settings = settings.from_env("other")
+    assert other_settings.SCRIPTS == [
+        "script2.sh",
+        "script3.sh",
+        "script4.sh",
+        "script1.sh",
+        # merge_unique does not duplicate, but overrides the order
+    ]
+
+
+def test_empty_yaml_key_overriding(tmpdir):
+    new_key_value = "new_key_value"
+    os.environ["DYNACONF_LEVEL1__KEY"] = new_key_value
+    os.environ["DYNACONF_LEVEL1__KEY2"] = new_key_value
+    os.environ["DYNACONF_LEVEL1__key3"] = new_key_value
+    os.environ["DYNACONF_LEVEL1__KEY4"] = new_key_value
+    os.environ["DYNACONF_LEVEL1__KEY5"] = new_key_value
+
+    tmpdir.join("test.yml").write(
+        """
+        level1:
+          key: key_value
+          KEY2:
+          key3:
+          keY4:
+        """
+    )
+
+    for merge_state in (True, False):
+        _settings = LazySettings(
+            settings_files=["test.yml"], merge_enabled=merge_state
+        )
+        assert _settings.level1.key == new_key_value
+        assert _settings.level1.key2 == new_key_value
+        assert _settings.level1.key3 == new_key_value
+        assert _settings.level1.get("KEY4") == new_key_value
+        assert _settings.level1.get("key4") == new_key_value
+        assert _settings.level1.get("keY4") == new_key_value
+        assert _settings.level1.get("keY6", "foo") == "foo"
+        assert _settings.level1.get("KEY6", "bar") == "bar"
+        assert _settings.level1["Key4"] == new_key_value
+        assert _settings.level1.Key4 == new_key_value
+        assert _settings.level1.KEy4 == new_key_value
+        assert _settings.level1.KEY4 == new_key_value
+        assert _settings.level1.key4 == new_key_value
+        with pytest.raises(AttributeError):
+            _settings.level1.key6
+            _settings.level1.key7
+            _settings.level1.KEY8
diff --git a/vendor_licenses/box-LICENSE.txt b/vendor_licenses/box-LICENSE.txt
new file mode 100644
index 0000000..2d55592
--- /dev/null
+++ b/vendor_licenses/box-LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017-2022 Chris Griffith
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor_licenses/click-LICENSE.rst b/vendor_licenses/click-LICENSE.rst
new file mode 100644
index 0000000..d12a849
--- /dev/null
+++ b/vendor_licenses/click-LICENSE.rst
@@ -0,0 +1,28 @@
+Copyright 2014 Pallets
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1.  Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+2.  Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+3.  Neither the name of the copyright holder nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor_licenses/licenses.sh b/vendor_licenses/licenses.sh
new file mode 100755
index 0000000..43ee8af
--- /dev/null
+++ b/vendor_licenses/licenses.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/bash
+# SPDX-FileCopyrightText: 2022 Maxwell G <gotmax@e.email>
+# SPDX-License-Identifier: MIT
+
+set -euo pipefail
+ruamel_yaml_version=0.16.10
+
+rm -fv *-LICENSE.*
+wget https://github.com/cdgriffith/Box/raw/master/LICENSE -O box-LICENSE.txt
+wget https://github.com/uiri/toml/raw/master/LICENSE -O toml-LICENSE.txt
+wget https://github.com/hukkin/tomli/raw/master/LICENSE -O tomli-LICENSE.txt
+wget https://github.com/pallets/click/raw/main/LICENSE.rst -O click-LICENSE.rst
+wget https://github.com/theskumar/python-dotenv/raw/main/LICENSE -O python-dotenv-LICENSE.txt
+wget "https://files.pythonhosted.org/packages/source/r/ruamel.yaml/ruamel.yaml-${ruamel_yaml_version}.tar.gz" -O- | tar -xzvO "ruamel.yaml-${ruamel_yaml_version}/LICENSE" >ruamel.yaml-LICENSE.txt
diff --git a/vendor_licenses/python-dotenv-LICENSE.txt b/vendor_licenses/python-dotenv-LICENSE.txt
new file mode 100644
index 0000000..39372fe
--- /dev/null
+++ b/vendor_licenses/python-dotenv-LICENSE.txt
@@ -0,0 +1,87 @@
+python-dotenv
+Copyright (c) 2014, Saurabh Kumar
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of python-dotenv nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+django-dotenv-rw
+Copyright (c) 2013, Ted Tieken
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of django-dotenv nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Original django-dotenv
+Copyright (c) 2013, Jacob Kaplan-Moss
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of django-dotenv nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor_licenses/ruamel.yaml-LICENSE.txt b/vendor_licenses/ruamel.yaml-LICENSE.txt
new file mode 100644
index 0000000..5b863d3
--- /dev/null
+++ b/vendor_licenses/ruamel.yaml-LICENSE.txt
@@ -0,0 +1,21 @@
+ The MIT License (MIT)
+
+ Copyright (c) 2014-2020 Anthon van der Neut, Ruamel bvba
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
diff --git a/vendor_licenses/toml-LICENSE.txt b/vendor_licenses/toml-LICENSE.txt
new file mode 100644
index 0000000..576d83e
--- /dev/null
+++ b/vendor_licenses/toml-LICENSE.txt
@@ -0,0 +1,27 @@
+The MIT License
+
+Copyright 2013-2019 William Pearson
+Copyright 2015-2016 Julien Enselme
+Copyright 2016 Google Inc.
+Copyright 2017 Samuel Vasko
+Copyright 2017 Nate Prewitt
+Copyright 2017 Jack Evans
+Copyright 2019 Filippo Broggini
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor_licenses/tomli-LICENSE.txt b/vendor_licenses/tomli-LICENSE.txt
new file mode 100644
index 0000000..e859590
--- /dev/null
+++ b/vendor_licenses/tomli-LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Taneli Hukkinen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor_licenses/vendor_versions.txt b/vendor_licenses/vendor_versions.txt
new file mode 100644
index 0000000..65f74aa
--- /dev/null
+++ b/vendor_licenses/vendor_versions.txt
@@ -0,0 +1,6 @@
+python-box==4.2.3
+toml==0.10.8
+tomli==2.0.1
+click==7.1.x
+python-dotenv==0.13.0
+ruamel.yaml==0.16.10

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.12.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.12.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.12.egg-info/entry_points.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.12.egg-info/not-zip-safe
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.12.egg-info/requires.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.12.egg-info/top_level.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf/vendor/tomllib/__init__.py
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf/vendor/tomllib/_parser.py
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf/vendor/tomllib/_re.py
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf/vendor/tomllib/_types.py
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf/vendor/tomllib/_writer.py

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.7.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.7.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.7.egg-info/entry_points.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.7.egg-info/not-zip-safe
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.7.egg-info/requires.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/dynaconf-3.1.7.egg-info/top_level.txt

No differences were encountered in the control files

More details

Full run details