././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1631217935.1303446 dynaconf-3.1.7/0000755000175000017500000000000000000000000014720 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1600729042.0 dynaconf-3.1.7/3.x-release-notes.md0000644000175000017500000001215500000000000020422 0ustar00rochacbrunorochacbruno# Dynaconf 3.0.0 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). ## 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). - 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. - Added implementation for `__dir__` to allow auto complete for terminal and IDEs. - Add option to override mount point for vault server. - `LazySettings` is now aliased to `Dynaconf` - `Dynaconf` class now accepts a parameter `validators=[Validator, ...]` that will be immediately evaluated when passed. ## Breaking Changes > **NOTE 1** `from dynaconf import settings` will keep working until version `4.0.x` to allow users to migrate gradually without having breaking changes but it will raise some DeprecationWarnings. > **NOTE 2** If you are using `FLASK` or `DJANGO` plugins there will be no breaking change on the framework settings, **a.k.a your project will keep working fine!**. #### `dynaconf.settings` global settings instance is now deprecated. Users are now supposed to create their own instance of `settings` instead of using the deprecated `from dynaconf import settings`. **project/config.py** ```python from dynaconf import Dynaconf 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) ex: ```python settings = Dynaconf( settings_file=["settings.toml", ".secrets.toml"], envvar_prefix="MYPROJECT" ) ``` > With the above instance your `settings` will load data from those 2 `.toml` files and also environment variables prefixed with `MYPROOJECT` e.g: `export MYPROJECT_FOO=1` #### Dynaconf is now envless by default. Historically Dynaconf worked in a multi layered environments for loading data from files, so you were supposed to have a file like: ```toml [default] key = 'value' [production] key = 'value' ``` **Now starting on 3.0.0** the environments are disabled by default, so the same file can be crated as. ```toml key = 'value' ``` And you can still have the environments but only if you explicit specify it when creating your instance. To have the previous behavior supporting all environments from the first level of a file. ```python settings = Dynaconf( environments=True ) ``` or to strictly specify your environments. ```python settings = Dynaconf( environments=["default", "prodution", "testing", "xyz"], ) ``` Once it is defined all the other functionalities still works such as. ```bash export ENV_FOR_DYNACONF=production myprogram.py ``` #### Automatic load of `settings.*` files are disabled by default. Starting on 3.x Dynaconf will now only load files passed explicitly to **settings_file** option when creating the instance or specified as env var **SETTINGS_FILE_FOR_DYNACONF**. When creating the settings instance the file **paths** or **globs** should be specified unless you want only env vars and external loaders to be loaded. Single file ```py settings = Dynaconf( settings_file="settings.toml", ) ``` Or multiple files. ```py settings = Dynaconf( settings_file=["settings.toml", "path/*.yaml"], ) ``` Dynaconf will respect the exact order informed by you on the `settings_file` parameter. > **NOTE** the parameters `preload`, `includes` and `secret` continues to work in the same way as before. > **NOTE** the parameters `preload`, `includes` and `secret` continues to work in the same way as before. #### Load of dotenv `.env` is now disabled by default. Dynaconf will **NO MORE** automatically load the data from `.env` file and will do that only if `load_dotenv=True` is provided. ```py settings = Dynaconf( load_dotenv=True ) ``` BY default it keeps searching for files in the current `PROJECT_ROOT` named `.env` and the `dotenv_path` accepts a relative path such as `.env` or `path/to/.env` #### DEBUG Logging is now completely removed There is no more `logging` or `debug` messages being printed, so the variable `DEBUG_LEVEL` has no more effect. ## Coming in 3.1.x - Support for Pydantic BaseSettings for Validators. - Support for replacement of `toml` parser on envvars loader. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631213921.0 dynaconf-3.1.7/CHANGELOG.md0000644000175000017500000032302000000000000016531 0ustar00rochacbrunorochacbrunoChangelog ========= 3.1.6 (2021-09-09) ------------------ - 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) - Bump dev version. [Bruno Rocha] [skip ci] - Bye Azure (#657) [Bruno Rocha] - Move to Github Actions (#656) [Bruno Rocha] * Move to Github Actions - [ ] Codecov Fix #640 * Enabled Vault and REdis - Add support for dynaconf_hooks(post) issue #654 (#655) [Bruno Rocha] - Update FUNDING.yml. [Bruno Rocha] - Fix a typo in the docs. [Linus Torvalds] - Fix typo (#647) [Ambient Lighter] - Delete requirements.txt. [Bruno Rocha] - Fix #491 pytest django Fix #491 pytest and django (#646) [Bruno Rocha] - Fix #596 django override (#645) [Bruno Rocha] * Fix #596 django.test.override issue * Fix CI side effects - Remove dependabot (this project has no dependencies) [Bruno Rocha] - Update codaci badge (#636) [Bruno Rocha] - Add myoy and pre-commit to CI (#635) [Bruno Rocha] - Description and type annotation for validator (#634) [Bruno Rocha] - Add a warning if `--env` is passed to `init` (#629) [Bruno Rocha, Bruno Rocha, Robert Rosca] * Add a warning if `--env` is passed to `init` * Fix typo, `file` was doubled in init help * Update docstrings for CLI * Raise error if using `-i` with `init` subcommand * Update docs to match current behaviour * add test coverage - Add type annotations for dynaconf.utils (#450) [Bruno Rocha, Bruno Rocha, Martin Thoma] * Add type annotations for dynaconf.utils Make 'mypy .' succeed; to a big extend by ignoring errors * Manually format line length * Drop Python 3.6 * Coverage fix - Do not search anywhere if the absolute path to a file provided (#570) [Bruno Rocha, Tanya Tereshchenko] * Do not search anywhere if the absolute path to a file provided fixes #569 * Fix test coverage and added some comments. - Update FUNDING.yml. [Bruno Rocha] - Fix black issues (#631) [Bruno Rocha] - Feat: add filter strategy with PrefixFilter (#625) [Nicholas Dentandt] - Fix typo (#588) [Bruno Rocha, puntonim] - Added an example using FastAPI (#571) [Bruno Rocha, Yusuf Kaka] - Fix dict iterator methods for flask DynaconfConfig (#581) [Bruno Rocha, Frank Battaglia, FrankBattaglia] - Fix #595 namedtuples are no more converted to BoxList (#623) [Bruno Rocha] - Add support for Python 3.9 and remove Ubuntu 16.04 that is deprecated in Azure Pipelines (#618) [Kamil Gałuszka] - Upgrade to GitHub-native Dependabot (#574) [dependabot-preview[bot], dependabot-preview[bot]] - Update configuration.md (#554) [Bruno Rocha, Konstantin] Remove redundant `s` (spelling error) - Update configuration.md (#553) [Bruno Rocha, Konstantin] Change spelling error - HOTFIX: Add coverage for 2 lines on validators. [Bruno Rocha] - Add the ability for selective validation (#549) [Bruno Rocha, Jacob Callahan] This change introduces the ability to control which sections of a settings object are subject to validation. This is controlled primarily by two mechanisms. 1: When creating a settings object, new arguments `validate_only` and `validate_exclude` have been added which receive a list of settings paths. 2: When manually calling validate, new arguments `only` and `exclude` have been added. All of these allow for either a string or list of strings representing settings paths. For example: `settings.validators.validate(only=["settings.something", "settings.another"])` settings = Dynaconf(..., validate_exclude="settings.bad") Fixes #508 - Bump mkdocs-material from 7.0.5 to 7.0.6 (#552) [dependabot- preview[bot]] Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.0.5 to 7.0.6. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/7.0.5...7.0.6) - Removed release_notes from the docs. (#550) [Bruno Rocha] * removed release_notes from the docs. towncrier will be implemented soon * fix #551 - Demo link (#546) [Bruno Rocha] * Add demo link, add better docstring. > **DEMO:** You can see a working demo here: https://github.com/rochacbruno/learndynaconf * add reference to Rust hydroconf - Release version 3.1.4. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (3): Release version 3.1.3 HOTFIX for 501 (#540) HOTFIX for 462 related issue, `default` on .get should be parsed as Box (#541) dependabot-preview[bot] (2): Bump mkdocs-material from 6.1.6 to 7.0.4 (#537) Bump mkdocs-material from 7.0.4 to 7.0.5 (#539) 3.1.5 (2021-08-20) ------------------ - Release version 3.1.5. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (4): Fix #595 namedtuples are no more converted to BoxList (#623) fix #596 django override (#645) fix #491 pytest django Fix #491 pytest and django (#646) Delete requirements.txt FrankBattaglia (1): fix dict iterator methods for flask DynaconfConfig (#581) 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) - Delete requirements.txt. [Bruno Rocha] - Fix #491 pytest django Fix #491 pytest and django (#646) [Bruno Rocha] - Fix #596 django override (#645) [Bruno Rocha] * Fix #596 django.test.override issue * Fix CI side effects - Add a warning if `--env` is passed to `init` (#629) [Bruno Rocha, Bruno Rocha, Robert Rosca] * Add a warning if `--env` is passed to `init` * Fix typo, `file` was doubled in init help * Update docstrings for CLI * Raise error if using `-i` with `init` subcommand * Update docs to match current behaviour * add test coverage - Fix dict iterator methods for flask DynaconfConfig (#581) [Bruno Rocha, Frank Battaglia, FrankBattaglia] - Fix #595 namedtuples are no more converted to BoxList (#623) [Bruno Rocha] - Do not search anywhere if the absolute path to a file provided (#570) [Bruno Rocha, Tanya Tereshchenko] * Do not search anywhere if the absolute path to a file provided fixes #569 * Fix test coverage and added some comments. 3.1.4 (2021-03-08) ------------------ - Release version 3.1.4. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (3): Release version 3.1.3 HOTFIX for 501 (#540) HOTFIX for 462 related issue, `default` on .get should be parsed as Box (#541) dependabot-preview[bot] (2): Bump mkdocs-material from 6.1.6 to 7.0.4 (#537) Bump mkdocs-material from 7.0.4 to 7.0.5 (#539) - HOTFIX for 462 related issue, `default` on .get should be parsed as Box (#541) [Bruno Rocha] objects In order to keep the same method api, default values should be parsed and converted to Boxed objects. https://github.com/rochacbruno/dynaconf/issues/462 - HOTFIX for 501 (#540) [Bruno Rocha] Flask still missing __contains__ - Bump mkdocs-material from 7.0.4 to 7.0.5 (#539) [dependabot- preview[bot]] Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.0.4 to 7.0.5. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/7.0.4...7.0.5) - Bump mkdocs-material from 6.1.6 to 7.0.4 (#537) [dependabot- preview[bot]] Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 6.1.6 to 7.0.4. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/6.1.6...7.0.4) - Release version 3.1.3. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (4): Release version 3.1.3rc1 Fix #462 make DynaBox nested List to use DynaBox as default class (#533) Fix #478 Make alias for environment -> environments (#534) Test to ensure #467 is not an issue (#535) 3.1.3 (2021-03-04) ------------------ Fix ~~~ - Environment variables filtering #470 (#474) [Michal Odnous] Other ~~~~~ - Release version 3.1.3. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (4): Release version 3.1.3rc1 Fix #462 make DynaBox nested List to use DynaBox as default class (#533) Fix #478 Make alias for environment -> environments (#534) Test to ensure #467 is not an issue (#535) - Test to ensure #467 is not an issue (#535) [Bruno Rocha] Closes #467 - Fix #478 Make alias for environment -> environments (#534) [Bruno Rocha] This is a commom mistake to pass `environment` so it is alias. Fix #478 - Fix #462 make DynaBox nested List to use DynaBox as default class (#533) [Bruno Rocha] Fix #462 - Release version 3.1.3rc1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (11): Release version 3.1.2 Fix #445 casting on dottet get. (#446) Fix docs regarding --django argument on cli (#477) Fix #521 - FlaskDynaconf should raise KeyError for non existing keys (#522) Case insensitive envvar traversal (#524) Allow load_file to accept pathlib.Path (#525) Allow Title case lookup and validation. (#526) Fix #482 - formatter case insensitive (#527) Fix #449 - Django lazy templating Fix #449 (#528) Added a test to reproduce #492 (not able to reproduce) (#530) Fix #511 allow user to specify loaders argument to execute_loaders (#531) FrankBattaglia (1): Specify flask extension initializers by entry point object reference (#456) Ilito Torquato (3): fix merging hyperlink to fix #454 (#458) Changed enabled_core_loaders elements to be upper case to fix #455 (#457) Fix doc secrets from vault #403 (#459) Marcelo Lino (1): Add __contains__ to Dynaconf (#502) Michal Odnous (1): Fix: Environment variables filtering #470 (#474) dependabot-preview[bot] (5): Bump mkdocs-material from 6.0.2 to 6.1.0 (#453) Bump mkdocs-git-revision-date-localized-plugin from 0.5.2 to 0.7.3 (#463) Bump mkdocs-material from 6.1.0 to 6.1.5 (#473) Bump mkdocs-versioning from 0.2.1 to 0.3.1 (#475) Bump mkdocs-material from 6.1.5 to 6.1.6 (#476) mirrorrim (1): Fix reading secret from Vault kv v2 (#483) (#487) - Fix #511 allow user to specify loaders argument to execute_loaders (#531) [Bruno Rocha] Fix #511 ```py settings.execute_loaders(loaders=[dynaconf.loaders.env_loader]) ``` - Added a test to reproduce #492 (not able to reproduce) (#530) [Bruno Rocha] I can't reproduce the bug #492 but I added a test to ensure. - Fix #449 - Django lazy templating Fix #449 (#528) [Bruno Rocha] * Fix django laxy templates fix #449 * Delete unused files * Fix LOADERS enabling - Fix #482 - formatter case insensitive (#527) [Bruno Rocha] * Fix #482 - formatter using both upper and lowercase access Fix #482 * add more testes covering nested formatting - Allow Title case lookup and validation. (#526) [Bruno Rocha] Fix #486 - Allow load_file to accept pathlib.Path (#525) [Bruno Rocha] * Allow load_file to accept pathlib.Path Fix #494 * python 3.6 can't handle Pathlib base path addition to os.path - Case insensitive envvar traversal (#524) [Bruno Rocha] * Envvar traversal is now case insensitive - Fix #519 and fix #516 Fix #519 Fix #516 Now `export DYNACONF_FOO__bar__zaz` is the same as `DYNACONF_FOO__BAR__ZAZ` > first level prefix still needs to be uppercase! Added a warning about django to the docs. * Add functional test for issue #519 - Fix #521 - FlaskDynaconf should raise KeyError for non existing keys (#522) [Bruno Rocha] * Fix #521 - FlaskDynaconf should raise KeyError for non existing keys * Test coverage got dotted get - Add __contains__ to Dynaconf (#502) [Marcelo Lino, Marcelo Lino] * Add __contains__ to Dynaconf * Add contains assert for flask test * Remove duplicated contains from dynaconf - Fix reading secret from Vault kv v2 (#483) (#487) [Alexey Tylindus, mirrorrim] - Fix docs regarding --django argument on cli (#477) [Bruno Rocha] fix #465 fix #451 - Bump mkdocs-material from 6.1.5 to 6.1.6 (#476) [dependabot- preview[bot]] Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 6.1.5 to 6.1.6. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/6.1.5...6.1.6) - Bump mkdocs-versioning from 0.2.1 to 0.3.1 (#475) [dependabot- preview[bot]] Bumps [mkdocs-versioning](https://github.com/zayd62/mkdocs-versioning) from 0.2.1 to 0.3.1. - [Release notes](https://github.com/zayd62/mkdocs-versioning/releases) - [Commits](https://github.com/zayd62/mkdocs-versioning/compare/0.2.1...0.3.1) - Bump mkdocs-material from 6.1.0 to 6.1.5 (#473) [dependabot- preview[bot]] Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 6.1.0 to 6.1.5. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/6.1.0...6.1.5) - Bump mkdocs-git-revision-date-localized-plugin from 0.5.2 to 0.7.3 (#463) [dependabot-preview[bot]] Bumps [mkdocs-git-revision-date-localized-plugin](https://github.com/timvink/mkdocs-git-revision-date-localized-plugin) from 0.5.2 to 0.7.3. - [Release notes](https://github.com/timvink/mkdocs-git-revision-date-localized-plugin/releases) - [Commits](https://github.com/timvink/mkdocs-git-revision-date-localized-plugin/compare/v0.5.2...v0.7.3) - Fix doc secrets from vault #403 (#459) [Bruno Rocha, Ilito Torquato, Ilito Torquato] * Fix secrets`s doc at Using Vault Server session * Fix secrets`s doc at Using Vault Server session * Revert "Fix secrets`s doc at Using Vault Server session" This reverts commit c47cd986bf089b3528e5c0e7c5a914cb7c1e69c8. - Changed enabled_core_loaders elements to be upper case to fix #455 (#457) [Bruno Rocha, Ilito Torquato, Ilito Torquato] * Changed enabled_core_loaders elements to be upper case to fix #455 * Change map to list comprehension and create empty [] as default value * fix wrong identation - Fix merging hyperlink to fix #454 (#458) [Ilito Torquato, Ilito Torquato] - Specify flask extension initializers by entry point object reference (#456) [FrankBattaglia] - Bump mkdocs-material from 6.0.2 to 6.1.0 (#453) [dependabot- preview[bot]] Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 6.0.2 to 6.1.0. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/6.0.2...6.1.0) - Fix #445 casting on dottet get. (#446) [Bruno Rocha] * Fix #445 casting on dottet get. Fix the rebound of `cast` on dotted get. Fix #445 * better handling of casting data - Release version 3.1.2. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (13): Release version 3.1.1 Update diagram images Update docs/release_notes Fixing prospector warnings. (#425) Fix mkdocs config problem found in #423 Signed in for https://xscode.com/rochacbruno/dynaconf (#426) Remove links to outdated issues from guidelines Fix colors and KEyError handling on cli.py (#429) Fix #434 setenv failing to unset LazyValues (#437) Fix #432 no need for warning when env is missing on a file (#438) Add test to ensure fix #430 (#439) Close #284 not a bug (#440) Fix #443 object merge with same value on same level keys (#444) dependabot-preview[bot] (6): Bump mkdocs-material from 5.3.2 to 5.5.13 (#423) Bump pymdown-extensions from 7.1 to 8.0 (#422) Bump mkdocs-material-extensions from 1.0 to 1.0.1 (#427) Bump pymdown-extensions from 8.0 to 8.0.1 (#435) Bump mkdocs-material from 5.5.13 to 6.0.1 (#436) Bump mkdocs-material from 6.0.1 to 6.0.2 (#442) 3.1.2 (2020-10-08) ------------------ - Release version 3.1.2. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (13): Release version 3.1.1 Update diagram images Update docs/release_notes Fixing prospector warnings. (#425) Fix mkdocs config problem found in #423 Signed in for https://xscode.com/rochacbruno/dynaconf (#426) Remove links to outdated issues from guidelines Fix colors and KEyError handling on cli.py (#429) Fix #434 setenv failing to unset LazyValues (#437) Fix #432 no need for warning when env is missing on a file (#438) Add test to ensure fix #430 (#439) Close #284 not a bug (#440) Fix #443 object merge with same value on same level keys (#444) dependabot-preview[bot] (6): Bump mkdocs-material from 5.3.2 to 5.5.13 (#423) Bump pymdown-extensions from 7.1 to 8.0 (#422) Bump mkdocs-material-extensions from 1.0 to 1.0.1 (#427) Bump pymdown-extensions from 8.0 to 8.0.1 (#435) Bump mkdocs-material from 5.5.13 to 6.0.1 (#436) Bump mkdocs-material from 6.0.1 to 6.0.2 (#442) - Fix #443 object merge with same value on same level keys (#444) [Bruno Rocha] This solution is a temporary solution as it solves current problem, but there is still the case for `None` values. The best solution for this case would be wrapping all the values on assignment and give it a full path signature to compare. - Bump mkdocs-material from 6.0.1 to 6.0.2 (#442) [dependabot- preview[bot]] Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/6.0.1...6.0.2) - Close #284 not a bug (#440) [Bruno Rocha] 284 is not a bug but a missing of explicit merge tokens - Add test to ensure fix #430 (#439) [Bruno Rocha] I could not reproduce the problem resported on #430 considering it close #430 reopen as needed. - Fix #432 no need for warning when env is missing on a file (#438) [Bruno Rocha] When env is missing on a file ther eis no need to output a warning. All envs are optional on files. Fix #432 - Fix #434 setenv failing to unset LazyValues (#437) [Bruno Rocha] Fix #434 - Bump mkdocs-material from 5.5.13 to 6.0.1 (#436) [dependabot- preview[bot]] Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 5.5.13 to 6.0.1. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/5.5.13...6.0.1) - Bump pymdown-extensions from 8.0 to 8.0.1 (#435) [dependabot- preview[bot]] Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 8.0 to 8.0.1. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/8.0...8.0.1) - Fix colors and KEyError handling on cli.py (#429) [Bruno Rocha] - Remove links to outdated issues from guidelines. [Bruno Rocha] - Bump mkdocs-material-extensions from 1.0 to 1.0.1 (#427) [dependabot- preview[bot]] Bumps [mkdocs-material-extensions](https://github.com/facelessuser/mkdocs-material-extensions) from 1.0 to 1.0.1. - [Release notes](https://github.com/facelessuser/mkdocs-material-extensions/releases) - [Changelog](https://github.com/facelessuser/mkdocs-material-extensions/blob/master/changelog.md) - [Commits](https://github.com/facelessuser/mkdocs-material-extensions/compare/1.0...1.0.1) - Signed in for https://xscode.com/rochacbruno/dynaconf (#426) [Bruno Rocha] Offering paid support for dynaconf users. - Bump pymdown-extensions from 7.1 to 8.0 (#422) [dependabot- preview[bot]] Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 7.1 to 8.0. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/7.1...8.0) - Bump mkdocs-material from 5.3.2 to 5.5.13 (#423) [dependabot- preview[bot]] Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 5.3.2 to 5.5.13. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/5.3.2...5.5.13) - Fix mkdocs config problem found in #423. [Bruno Rocha] Fix #mkdocs-material/1941 - Fixing prospector warnings. (#425) [Bruno Rocha] * Fixing prospector warnings * Used vulture to detect and remove dead code - Update docs/release_notes. [Bruno Rocha] - Update diagram images. [Bruno Rocha] - Release version 3.1.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (2): Release version 3.1.1rc6 HOTFIX: Cli now accepts dotter keys 3.1.1 (2020-09-21) ------------------ - Release version 3.1.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (2): Release version 3.1.1rc6 HOTFIX: Cli now accepts dotter keys - HOTFIX: Cli now accepts dotter keys. [Bruno Rocha] - Release version 3.1.1rc6. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (2): Release version 3.1.1rc5 Do not include vendor_src on wheel target (#420) - Do not include vendor_src on wheel target (#420) [Bruno Rocha] - Release version 3.1.1rc5. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (3): Release version 3.1.1rc4 Small fix on release script Minification of vendored modules (#419) - Minification of vendored modules (#419) [Bruno Rocha] * Minified all the vendor folder saving 50% od disk space * Add vendor_src and minify script vendor_src is not included in the build, only the results of its minification - Small fix on release script. [Bruno Rocha] Correct path for mkdocs.yml - Release version 3.1.1rc4. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (3): Release version 3.1.1rc3 HOTFIX: Add missing instruction to release.sh Added full Dynaconf Diagram and few fizes. (#418) - Added full Dynaconf Diagram and few fizes. (#418) [Bruno Rocha] - HOTFIX: Add missing instruction to release.sh. [Bruno Rocha] - Release version 3.1.1rc3. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (5): Release version 3.1.1rc2 Fix set attribute directly and fresh vars (#412) 384 fix tail and dotted merge (#415) Fix #404 no more dup message on combined validators (#417) HOTFIX 414 update docs version on release Max Winterstein (1): Fix typo in release notes (#411) Mirek Długosz (1): Fix #407 - add proper equality test for CombinedValidator (#413) - HOTFIX 414 update docs version on release. [Bruno Rocha] Fix #414 - Fix #404 no more dup message on combined validators (#417) [Bruno Rocha] - 384 fix tail and dotted merge (#415) [Bruno Rocha] * attempt to fix tail call on object_merge Fix #384 * Fix list and dict merge issues - Fix typo in release notes (#411) [Bruno Rocha, Max Winterstein] - Fix #407 - add proper equality test for CombinedValidator (#413) [Mirek Długosz] * Fix #407 - add proper equality test for CombinedValidator * Update after review - Fix set attribute directly and fresh vars (#412) [Bruno Rocha] * Fix set attribute directly and fresh vars Fix #253 Fix #395 * No need to check for default_settings in setattr - Release version 3.1.1rc2. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (2): Release version 3.1.1rc1 HOTFIX: Logging instance has a `formatter` attribute (#410) - HOTFIX: Logging instance has a `formatter` attribute (#410) [Bruno Rocha] Dynaconf was trying to detect a lazy value by the existence of `formatter` attribute but in Django when the value is a logging it has `.formatter` attribute. - Release version 3.1.1rc1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (10): Release version 3.1.0 Create FUNDING.yml Fix #391 make box_settings optional, change vendoring strategy (#398) HOTFIX: Add missing vendor.txt Allow nested Lazy Values (#405) Makes PEP8 more strictly and remove unused variables (#408) Merge branch 'master' into vault boto is optional Merge branch 'vault' into master Included example of custom SOPS loader to the docs Christoph Schmatzler (1): Fix typo in Validation docs (#394) Gabriel Simonetto (1): Fix #399 - Update documentation link (#401) Jiranun Jiratrakanvong (1): Add auth username and password for redis settings (#378) Martijn Pieters (1): Correct typos in documentation and README (#400) Mirek Długosz (1): Test all names in Validator("foo", "bar", must_exist=False) (#406) Nikolai Bessonov (1): fix a typo (#393) Peng Yin (5): Read all secrets under a vault path Add option to auth vault with iam role Fix format Fix test for versioned kv engine in latest vault Merge branch 'master' into vault whg517 (1): docs: Fixed filename error in the case of the index page (#396) - Included example of custom SOPS loader to the docs. [Bruno Rocha] - Add auth username and password for redis settings (#378) [Bruno Rocha, Jiranun Jiratrakanvong, Jiranun Jiratrakanvong] - Merge branch 'vault' into master. [Bruno Rocha] - Boto is optional. [Bruno Rocha] - Merge branch 'master' into vault. [Bruno Rocha] - Fix a typo (#393) [Bruno Rocha, Nikolai Bessonov] - Fix typo in Validation docs (#394) [Bruno Rocha, Christoph Schmatzler] - Correct typos in documentation and README (#400) [Bruno Rocha, Martijn Pieters] * Correct minor documentation typo in the Dynamic Variables section. * Fix typos throughout the docs - Docs: Fixed filename error in the case of the index page (#396) [Bruno Rocha, whg517] - Fix #399 - Update documentation link (#401) [Bruno Rocha, Gabriel Simonetto] - Makes PEP8 more strictly and remove unused variables (#408) [Bruno Rocha] - Test all names in Validator("foo", "bar", must_exist=False) (#406) [Mirek Długosz] `Validator(must_exist=False)` incorrectly checked first name only. Given settings.yaml: bar: some_value `Validator("foo", "bar", must_exist=False)` would **not** raise ValidationError - it would return after checking that first name indeed is not defined. - Allow nested Lazy Values (#405) [Bruno Rocha] Fix #392 Fix #402 - Merge branch 'master' into vault. [Peng Yin] - HOTFIX: Add missing vendor.txt. [Bruno Rocha] - Fix #391 make box_settings optional, change vendoring strategy (#398) [Bruno Rocha] - Revert DynaBox box_settings to be optional - Change vendoring strategy - instead of hacking sys.modules, using abs paths - Pin to Box 4.2.2 without conflicting with system installed box - Added a Django example on tests to fix @daviddavis reported issue - Fix test for versioned kv engine in latest vault. [Peng Yin] - Fix format. [Peng Yin] - Add option to auth vault with iam role. [Peng Yin] - Read all secrets under a vault path. [Peng Yin] - Create FUNDING.yml. [Bruno Rocha] - Release version 3.1.0. [Bruno Rocha] Shortlog of commits since last release: Andreas Poehlmann (1): Allow importing SEARCHTREE before settings are configured (#383) Bruno Rocha (10): Release version 3.0.0 Hot fix removing unused imports Merge branch 'master' of github.com:rochacbruno/dynaconf Removing invalid links, adding allert on old docs fix #369 and fix #371 (#372) Fix #359 lazy template substitution on nested keys (#375) Flask fizes and other issues included. (#376) Fix #379 dict like iteration (#385) Fix #377 allow computed values (#386) Fix #388 URL reference for custom loaders (#389) Fix #382 add is_overriden method (#390) John Vandenberg (1): Allow testing against local redis server (#387) Piotr Baniukiewicz (1): Fix validation of optional fields (#370) 3.1.0 (2020-08-14) ------------------ - Release version 3.1.0. [Bruno Rocha] Shortlog of commits since last release: Andreas Poehlmann (1): Allow importing SEARCHTREE before settings are configured (#383) Bruno Rocha (10): Release version 3.0.0 Hot fix removing unused imports Merge branch 'master' of github.com:rochacbruno/dynaconf Removing invalid links, adding allert on old docs fix #369 and fix #371 (#372) Fix #359 lazy template substitution on nested keys (#375) Flask fizes and other issues included. (#376) Fix #379 dict like iteration (#385) Fix #377 allow computed values (#386) Fix #388 URL reference for custom loaders (#389) Fix #382 add is_overriden method (#390) John Vandenberg (1): Allow testing against local redis server (#387) Piotr Baniukiewicz (1): Fix validation of optional fields (#370) - Allow importing SEARCHTREE before settings are configured (#383) [Andreas Poehlmann] - Allow testing against local redis server (#387) [John Vandenberg] - Fix #382 add is_overriden method (#390) [Bruno Rocha] Fix #382 add is_overriden method for DJDT - Fix #388 URL reference for custom loaders (#389) [Bruno Rocha] Fix #388 URL reference for custom loaders - Fix #377 allow computed values (#386) [Bruno Rocha] This fixes #377 by allowing Validator to provide default values. - Fix #379 dict like iteration (#385) [Bruno Rocha] * Fix #379 add missing __iter__ and items * Fix docs - Flask fizes and other issues included. (#376) [Bruno Rocha] Fix #323 Fix #325 Fix #327 Fix #341 Exemples added: example/issues/323_DEFAULT_VALUES_RESOLUTION/ example/issues/325_flask_dot_env/ example/issues/327_flask_extensions_warning/ example/issues/341_box_it_up/ - Fix #359 lazy template substitution on nested keys (#375) [Bruno Rocha] - Removing invalid links, adding allert on old docs fix #369 and fix #371 (#372) [Bruno Rocha] - Merge branch 'master' of github.com:rochacbruno/dynaconf. [Bruno Rocha] - Fix validation of optional fields (#370) [Bruno Rocha Co-authored-by: Bruno Rocha , Piotr Baniukiewicz] * Fix validation of optional fields * More concise code - Hot fix removing unused imports. [Bruno Rocha] - Release version 3.0.0. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (5): Release version 3.0.0rc2 Improvements on CLI and init command (#363) Writing new docs page 1 (#364) Add netlify (#366) Add netlify runtime file... 3.0.0 (2020-06-29) ------------------ - Release version 3.0.0. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (5): Release version 3.0.0rc2 Improvements on CLI and init command (#363) Writing new docs page 1 (#364) Add netlify (#366) Add netlify runtime file... - Add netlify runtime file... [Bruno Rocha] - Add netlify (#366) [Bruno Rocha] - Writing new docs page 1 (#364) [Bruno Rocha] * porting docs to mkdocs * Docs First Page * New docs ok - Improvements on CLI and init command (#363) [Bruno Rocha] - Release version 3.0.0rc2. [Bruno Rocha] Shortlog of commits since last release: Bernardo Gomes (2): Adding f string (#319) Added little information about how dev into this project. (#321) Bruno Rocha (18): Release version 3.0.0rc1 Better exception handling on env_loader (#316) Add support for config aliases (#332) Add ENVLESS_MODE (#337) Fix #272 allow access of lowercase keys (#338) Fix #298 allow auto complete for editors and console (#339) Vendoring dependencies Fix #301 (#345) Clean tox installation for local testing (#346) Validator improvements on conditions (#353) Add note about quoting in env vars (#347) DEPRECATED global settings object. DEPRECATED global settings object. (#356) Lowecase read allowed by default (#357) Merge branch 'master' of github.com:rochacbruno/dynaconf envless by default - breaking change ⚠️ (#358) dotenv is no more loaded by default (#360) No more loading of `settings.*` by default (#361) NO more logger and debug messages (#362) Douglas Maciel d'Auriol Souza (1): Insert news validator conditions: (len_eq, len_ne, len_min, len_max, contd) (#328) Jeff Wayne (1): s/DYNACONF_ENV/ENV_FOR_DYNACONF (#335) Marcos Benevides (1): Fix minor typo in Flask extension docs (#318) Nicholas Nadeau, Ph.D., P.Eng (1): Fixed comma typo (#334) sfunkhouser (1): Add option to override default mount_point for vault (#349) - NO more logger and debug messages (#362) [Bruno Rocha] * logger and DEBUG_LEVEL has gone. * Add logger as a backwards compat method - No more loading of `settings.*` by default (#361) [Bruno Rocha] - Dotenv is no more loaded by default (#360) [Bruno Rocha] - Envless by default - breaking change ⚠️ (#358) [Bruno Rocha] * ⚠️ Turning the default to be the envless mode (this is breaking change) ⚠️ ⚠️ THIS IS BREAKING CHANGE ⚠️ * envless by default is done * Fix redis and vault tests * CLI default to global instance with warnings - Merge branch 'master' of github.com:rochacbruno/dynaconf. [Bruno Rocha] - Lowecase read allowed by default (#357) [Bruno Rocha] * DEPRECATED global settings object. No more `from dynaconf import settings` * Lower case first level keys are now allowed by default - DEPRECATED global settings object. (#356) [Bruno Rocha] No more `from dynaconf import settings` - DEPRECATED global settings object. [Bruno Rocha] No more `from dynaconf import settings` - Add note about quoting in env vars (#347) [Bruno Rocha] - Validator improvements on conditions (#353) [Bruno Rocha] * Validators improvements * add cast argument to validators - Add option to override default mount_point for vault (#349) [sfunkhouser] - Clean tox installation for local testing (#346) [Bruno Rocha] - Vendoring dependencies Fix #301 (#345) [Bruno Rocha] - Fix #298 allow auto complete for editors and console (#339) [Bruno Rocha] implemented `__dir__` on Settings and Dynabox - Fix #272 allow access of lowercase keys (#338) [Bruno Rocha] - `settings.lowercase_key` is allowed - `settings.dynaconf` is a proxy to internal methods - `settings.__reserved_attributes` validates key names - `LazySettings __init__ parameters can receive lower case configs` - Add ENVLESS_MODE (#337) [Bruno Rocha] - S/DYNACONF_ENV/ENV_FOR_DYNACONF (#335) [Jeff Wayne] - Fixed comma typo (#334) [Nicholas Nadeau, Ph.D., P.Eng] - Add support for config aliases (#332) [Bruno Rocha] All _FOR_DYNACONF can now be aliased when passing to LazySettings. - Insert news validator conditions: (len_eq, len_ne, len_min, len_max, contd) (#328) [Bruno Rocha, Douglas Maciel d'Auriol Souza] * Insert news validator conditions: len_eq, len_ne, len_min, len_max, contd * Insert news validator conditions: len_eq, len_ne, len_min, len_max, contd * Update validator_conditions.py * Update test_validators_conditions.py * Checked: Flake8 * Black sugest * Change of the term contd to cont, in order to avoid false interpretation. - Better exception handling on env_loader (#316) [Bruno Rocha] - Added little information about how dev into this project. (#321) [Bernardo Gomes] - Adding f string (#319) [Bernardo Gomes] * First test to change to f-string * second change to f-string * Removed 95% of .format( * Removed % from code. * forget format. * Fixing flaked reports. * Fixing flaked reports-v2. * make run-pre-commit command executed. * Little bugfix f of f-string inside of the string. - Fix minor typo in Flask extension docs (#318) [Marcos Benevides] - Release version 3.0.0rc1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (8): Release version 2.2.3 Changed text format and fixed tests Merge branch '304-ShowDataTypeListCli' Fix issue #305 - printing and exporting LazyFormat (#312) Fix #288 - Nullable values (#300) Default to ruamel.yaml when it is available. (#313) Fix #306 - does not defaults to merge, deprecated reset - [Breaking Change] (#315) HOTFIX - tox.ini drops 3.5 Tiago Cordeiro (1): Added OSX builds to the Azure Pipeline (#307) Vicente Marçal (1): Changed CLI list to show data type of the envvars to fix #304 dependabot-preview[bot] (1): Unpinning python-box, removing box_it_up and default_box arguments (#279) - HOTFIX - tox.ini drops 3.5. [Bruno Rocha] - Fix #306 - does not defaults to merge, deprecated reset - [Breaking Change] (#315) [Bruno Rocha] - Don't default to `merge` for `__` variables - Made `@merge` more explicit and smart - Deprecated `@reset` - Unpinning python-box, removing box_it_up and default_box arguments (#279) [Bruno Rocha, dependabot-preview[bot]] - Default to ruamel.yaml when it is available. (#313) [Bruno Rocha] - Fix #288 - Nullable values (#300) [Bruno Rocha] * Attempt to fix #288 (needs more debugging) * Fixing bug on DynaBox.get - Fix issue #305 - printing and exporting LazyFormat (#312) [Bruno Rocha] - Merge branch '304-ShowDataTypeListCli' [Bruno Rocha] - Changed text format and fixed tests. [Bruno Rocha] - Changed CLI list to show data type of the envvars to fix #304. [Vicente Marçal] - Added OSX builds to the Azure Pipeline (#307) [Tiago Cordeiro] * Added OSX builds to the Azure Pipeline * Added OSX builds to the Azure Pipeline * skip docker tests on macOS - Release version 2.2.3. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (7): Release version 2.2.2 Fix #273 add Flask load extensions method. add t.me badge fix #262 Fix #145 allow lazy format using os.environ and settings values. Overriding strategy test Fix #203 document the usage with pytest (with examples) unpin dependencies Hildeberto (2): Fix pre-commit to run python3 rather than python3.7 Merge pull request #281 from hilam/fix_pre_commit JSP (1): fix object_merge issue #285 with meta value dependabot-preview[bot] (2): Update python-dotenv requirement from <=0.10.3 to <0.10.6 Update python-dotenv requirement from <0.10.6 to <0.11.1 2.2.3 (2020-02-28) ------------------ - Release version 2.2.3. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (7): Release version 2.2.2 Fix #273 add Flask load extensions method. add t.me badge fix #262 Fix #145 allow lazy format using os.environ and settings values. Overriding strategy test Fix #203 document the usage with pytest (with examples) unpin dependencies Hildeberto (2): Fix pre-commit to run python3 rather than python3.7 Merge pull request #281 from hilam/fix_pre_commit JSP (1): fix object_merge issue #285 with meta value dependabot-preview[bot] (2): Update python-dotenv requirement from <=0.10.3 to <0.10.6 Update python-dotenv requirement from <0.10.6 to <0.11.1 - Unpin dependencies. [Bruno Rocha] - Update python-dotenv requirement from <0.10.6 to <0.11.1. [dependabot- preview[bot]] Updates the requirements on [python-dotenv](https://github.com/theskumar/python-dotenv) to permit the latest version. - [Release notes](https://github.com/theskumar/python-dotenv/releases) - [Changelog](https://github.com/theskumar/python-dotenv/blob/master/CHANGELOG.md) - [Commits](https://github.com/theskumar/python-dotenv/compare/v0.1.1...v0.11.0) - Fix #203 document the usage with pytest (with examples) [Bruno Rocha] - Overriding strategy test. [Bruno Rocha] - Fix #145 allow lazy format using os.environ and settings values. [Bruno Rocha] - Add t.me badge fix #262. [Bruno Rocha] - Fix #273 add Flask load extensions method. [Bruno Rocha] - This commit adds a new method `load_extensions` to `FlaskDynaconf` class. - Update python-dotenv requirement from <=0.10.3 to <0.10.6. [dependabot-preview[bot]] Updates the requirements on [python-dotenv](https://github.com/theskumar/python-dotenv) to permit the latest version. - [Release notes](https://github.com/theskumar/python-dotenv/releases) - [Changelog](https://github.com/theskumar/python-dotenv/blob/master/CHANGELOG.md) - [Commits](https://github.com/theskumar/python-dotenv/compare/v0.1.1...v0.10.5) - Fix object_merge issue #285 with meta value. [JSP] - Merge pull request #281 from hilam/fix_pre_commit. [Hildeberto] Fix pre-commit to run python3 rather than python3.7 - Fix pre-commit to run python3 rather than python3.7. [Hildeberto] - Release version 2.2.2. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (3): Release version 2.2.1 Fix #258 custom message for validators Pin python-box version because of a breaking release Hildeberto (1): Close #178. Included integration tests redis/vault 2.2.2 (2019-12-26) ------------------ - Release version 2.2.2. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (3): Release version 2.2.1 Fix #258 custom message for validators Pin python-box version because of a breaking release Hildeberto (1): Close #178. Included integration tests redis/vault - Pin python-box version because of a breaking release. [Bruno Rocha] The release of python-box https://github.com/cdgriffith/Box/pull/116 is a breaking change. So pinning this until this project addapts. Also pinning other direct deps. - Fix #258 custom message for validators. [Bruno Rocha] - Close #178. Included integration tests redis/vault. [Hildeberto] - Release version 2.2.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (4): Release version 2.2.0 Fix #251 recursive call was using mutable memoized data (#254) Fix #266 created new variable FORCE_ENV to override ENV_FOR_DYNACONF Fix coverage for validators David Moreau Simard (1): Add ara as a user of dynaconf (#252) Emmanuel Nosa Evbuomwan (1): Update sensitive_secrets.md Hildeberto (1): Adjust remote upstream URL Jan Willhaus (1): Add support for detecting duplicate validators being added (and ignore them) (#256) Oliver Lehmann (5): fix: env_loader.write: quote_mode for non-string values : added line break fix str comparison changing quote logic fix open error @py3.5 2.2.1 (2019-12-06) ------------------ Fix ~~~ - Env_loader.write: quote_mode for non-string values. [Oliver Lehmann] Other ~~~~~ - Release version 2.2.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (4): Release version 2.2.0 Fix #251 recursive call was using mutable memoized data (#254) Fix #266 created new variable FORCE_ENV to override ENV_FOR_DYNACONF Fix coverage for validators David Moreau Simard (1): Add ara as a user of dynaconf (#252) Emmanuel Nosa Evbuomwan (1): Update sensitive_secrets.md Hildeberto (1): Adjust remote upstream URL Jan Willhaus (1): Add support for detecting duplicate validators being added (and ignore them) (#256) Oliver Lehmann (5): fix: env_loader.write: quote_mode for non-string values : added line break fix str comparison changing quote logic fix open error @py3.5 - Fix coverage for validators. [Bruno Rocha] - Fix #266 created new variable FORCE_ENV to override ENV_FOR_DYNACONF. [Bruno Rocha] - Adjust remote upstream URL. [Hildeberto] - Update sensitive_secrets.md. [Emmanuel Nosa Evbuomwan] Updated the file reference from `settings`.toml{json|py|ini|yaml} to the convention used thus far; `secrets`.toml{json|py|ini|yaml}. This can help alleviate the slightest chance of the information becoming misleading or confusing. This can also be ignored if Dynaconf can be set to search for secrets in files other than `secrets.` - Fix open error @py3.5. [Oliver Lehmann] - Changing quote logic. [Oliver Lehmann] - Fix str comparison. [Oliver Lehmann] - : added line break. [Oliver Lehmann] - Add support for detecting duplicate validators being added (and ignore them) (#256) [Jan Willhaus] - Fix #251 recursive call was using mutable memoized data (#254) [Bruno Rocha] replaced with recursive passing of parent data. NOTE to SELF: Never! use a mutable memoized data Always use `==` to compare when you dont know the types - Add ara as a user of dynaconf (#252) [David Moreau Simard] - Release version 2.2.0. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (5): Release version 2.1.1 Fix #236 added .local. files loading and module impersonation docs (#239) Replace key.upper with `upperfy` function that keeps `__` attributes (#240) Fix #241 new merge standards (#243) Add support for PRELOAD_ setting. (#244) Kedar Kulkarni (1): Fixing how filename.local.* files are loaded (#238) paskozdilar (1): fix crash on empty settings (#242) 2.2.0 (2019-10-09) ------------------ - Release version 2.2.0. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (5): Release version 2.1.1 Fix #236 added .local. files loading and module impersonation docs (#239) Replace key.upper with `upperfy` function that keeps `__` attributes (#240) Fix #241 new merge standards (#243) Add support for PRELOAD_ setting. (#244) Kedar Kulkarni (1): Fixing how filename.local.* files are loaded (#238) paskozdilar (1): fix crash on empty settings (#242) - Add support for PRELOAD_ setting. (#244) [Bruno Rocha] - Fix #241 new merge standards (#243) [Bruno Rocha] Adds dynaconf_merge and @merge for better merge standards. ref #241 - Fix crash on empty settings (#242) [paskozdilar] * fix crash on empty settings * add test for empty environment * fix PEP 8 issue (expected 2 blank lines, found 1) - Replace key.upper with `upperfy` function that keeps `__` attributes (#240) [Bruno Rocha] - Fix #236 added .local. files loading and module impersonation docs (#239) [Bruno Rocha] also MERGE_ENABLED is no more deprecated. - Fixing how filename.local.* files are loaded (#238) [Kedar Kulkarni] - Release version 2.1.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (7): Release version 2.1.0 Improve validators to use `from_env` method (#225) Add info about dunder envvars on django.md docs guide (#226) Fix #228 add `ignore` argument to Django explicit mode. (#229) Improvement to close #230 - do not throw error for base envs. (#231) dynaconf init will not write all possible envs, only [default] (#233) When both enabled, Vault has the priority over Redis for overriding (#234) Dave Barnow (1): Fix typo in CLI init (#227) Kedar Kulkarni (1): Fixing self._root_path to fall back to os.getcwd() only when `settings.load_file` is called directly or from includes (#232) 2.1.1 (2019-09-16) ------------------ - Release version 2.1.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (7): Release version 2.1.0 Improve validators to use `from_env` method (#225) Add info about dunder envvars on django.md docs guide (#226) Fix #228 add `ignore` argument to Django explicit mode. (#229) Improvement to close #230 - do not throw error for base envs. (#231) dynaconf init will not write all possible envs, only [default] (#233) When both enabled, Vault has the priority over Redis for overriding (#234) Dave Barnow (1): Fix typo in CLI init (#227) Kedar Kulkarni (1): Fixing self._root_path to fall back to os.getcwd() only when `settings.load_file` is called directly or from includes (#232) - When both enabled, Vault has the priority over Redis for overriding (#234) [Bruno Rocha] - Dynaconf init will not write all possible envs, only [default] (#233) [Bruno Rocha] - Fixing self._root_path to fall back to os.getcwd() only when `settings.load_file` is called directly or from includes (#232) [Kedar Kulkarni] - Improvement to close #230 - do not throw error for base envs. (#231) [Bruno Rocha] - Fix #228 add `ignore` argument to Django explicit mode. (#229) [Bruno Rocha] - Fix typo in CLI init (#227) [Dave Barnow] - Add info about dunder envvars on django.md docs guide (#226) [Bruno Rocha] - Improve validators to use `from_env` method (#225) [Bruno Rocha] - Release version 2.1.0. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (8): Release version 2.0.4 Merge branch 'dgarcia360-master' Fix #197 add support for DOTTED__ENV__VARS (#215) Add support to export merged env to filesystem via cli. (#217) Adds `from_env` method and change `_store` to be a `DynaBox` (#219) hotfix: next release will be 2.1.0 because new features added. (#220) Fix `make test_examples` to use better assertions, redis and vault loader now respects `envs` (#222) fix #221 removed JSON,YAML,INI,TOML cosntants from default_settings (#223) Kedar Kulkarni (1): Add `list_envs` function to vault loader and now envs can have `_` on its name. Pavel Alimpiev (1): Fix typo in documentation for a Validator class (#213) dgarcia360 (3): Updated configuration options table to csv table Added responsive table fix Fix format 2.1.0 (2019-09-05) ------------------ - Release version 2.1.0. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (8): Release version 2.0.4 Merge branch 'dgarcia360-master' Fix #197 add support for DOTTED__ENV__VARS (#215) Add support to export merged env to filesystem via cli. (#217) Adds `from_env` method and change `_store` to be a `DynaBox` (#219) hotfix: next release will be 2.1.0 because new features added. (#220) Fix `make test_examples` to use better assertions, redis and vault loader now respects `envs` (#222) fix #221 removed JSON,YAML,INI,TOML cosntants from default_settings (#223) Kedar Kulkarni (1): Add `list_envs` function to vault loader and now envs can have `_` on its name. Pavel Alimpiev (1): Fix typo in documentation for a Validator class (#213) dgarcia360 (3): Updated configuration options table to csv table Added responsive table fix Fix format - Fix #221 removed JSON,YAML,INI,TOML cosntants from default_settings (#223) [Bruno Rocha] Default settings should hold only constants ending in _FOR_DYNACONF - Fix `make test_examples` to use better assertions, redis and vault loader now respects `envs` (#222) [Bruno Rocha] - Hotfix: next release will be 2.1.0 because new features added. (#220) [Bruno Rocha] - Adds `from_env` method and change `_store` to be a `DynaBox` (#219) [Bruno Rocha] - Add `list_envs` function to vault loader and now envs can have `_` on its name. [Kedar Kulkarni] * Adding new feature to address issue #211 `list_envs ` function on vault loader * Removing restriction with env cannot contain underscore chars - Add support to export merged env to filesystem via cli. (#217) [Bruno Rocha] fix #200 ```bash dynaconf list -o path/to/file.yaml --output-flat ``` - Fix #197 add support for DOTTED__ENV__VARS (#215) [Bruno Rocha] * Fix #197 add support for DOTTED__ENV__VARS * Full support for `__` - @reset and @del markers - Merge branch 'dgarcia360-master' [Bruno Rocha] - Fix format. [dgarcia360] - Added responsive table fix. [dgarcia360] - Updated configuration options table to csv table. [dgarcia360] - Fix typo in documentation for a Validator class (#213) [Pavel Alimpiev] - Release version 2.0.4. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (2): Release version 2.0.3 Fix #207 allow python module path name for includes (#209) Michał Bartoszkiewicz (1): Update usage.md (#208) Pavel Alimpiev (2): Refactor Vault integration (#202) Update configuration.md (#205) Tanveer Alam (2): Update usage.md (#196) Update usage.md (#195) 2.0.4 (2019-08-22) ------------------ - Release version 2.0.4. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (2): Release version 2.0.3 Fix #207 allow python module path name for includes (#209) Michał Bartoszkiewicz (1): Update usage.md (#208) Pavel Alimpiev (2): Refactor Vault integration (#202) Update configuration.md (#205) Tanveer Alam (2): Update usage.md (#196) Update usage.md (#195) - Fix #207 allow python module path name for includes (#209) [Bruno Rocha] - Update usage.md (#208) [Michał Bartoszkiewicz] Change 'FLask' to 'Flask' - Update configuration.md (#205) [Pavel Alimpiev] - Refactor Vault integration (#202) [Pavel Alimpiev] * Add AppRole based authorization for Vault loader * Fix default value for VAULT_PATH_FOR_DYNACONF, Update docs * HVAC automatically adds /secret/ prefix on read and write access * /dynaconf was never added to the VAULT_PATH_FOR_DYNACONF value * Docs was inconsistent with the actual code base * Fix inconsistency in the docs * Remove VAULT_SESSION_FOR_DYNACONF config variable. * HVAC's session argument must be a fully initialized Session object, that means - it's very complicated to setup Vault client with this argument, via default instruments (.toml, .env, etc) * Users can still setup this argument by setting up VAULT_FOR_DYNACONF directly * Update documentation for VAULT_* configuration * Fix code style - Update usage.md (#195) [Tanveer Alam] - Update usage.md (#196) [Tanveer Alam] - Release version 2.0.3. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (2): Release version 2.0.2 Fix #194 flask.app.config __setitem__ (#199) Jan Willhaus (1): Catch BoxKeyError when contents are TOML parsable but not keyable (#192) Raoul Snyman (1): Use the Key Value API rather than the old 'read' and 'write' methods (#198) 2.0.3 (2019-06-27) ------------------ - Release version 2.0.3. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (2): Release version 2.0.2 Fix #194 flask.app.config __setitem__ (#199) Jan Willhaus (1): Catch BoxKeyError when contents are TOML parsable but not keyable (#192) Raoul Snyman (1): Use the Key Value API rather than the old 'read' and 'write' methods (#198) - Fix #194 flask.app.config __setitem__ (#199) [Bruno Rocha] Flask.config was not proxying __setitem__ atribute so this change adds a call to __setitem__ on contrib/flask_dynaconf - Use the Key Value API rather than the old 'read' and 'write' methods (#198) [Raoul Snyman] - Catch BoxKeyError when contents are TOML parsable but not keyable (#192) [Jan Willhaus] - Release version 2.0.2. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (8): Release version 2.0.1 Add note to release script Adhering to Github Community Standards (#175) removed pytest-xdist (#181) Add example and test for issue #182 (#183) Fix #179 dynaconf cli shows only user defined vars unless -a used (#188) Fix #184 - workdir should walk to root in ipython REPL (#190) Fix #189 added `settings.as_dict()` and `dynaconf list -o file.json` (#191) Jan Willhaus (4): Fix `False` not being an acceptable env (#176) Fix base loader when having no ENVVAR_PREFIX_ (Addresses #177) (#185) Hide DeprecationWarning from Pytest when testing for them (#186) Replace logging.basicConfig with handler on logger (#187) 2.0.2 (2019-04-29) ------------------ - Release version 2.0.2. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (8): Release version 2.0.1 Add note to release script Adhering to Github Community Standards (#175) removed pytest-xdist (#181) Add example and test for issue #182 (#183) Fix #179 dynaconf cli shows only user defined vars unless -a used (#188) Fix #184 - workdir should walk to root in ipython REPL (#190) Fix #189 added `settings.as_dict()` and `dynaconf list -o file.json` (#191) Jan Willhaus (4): Fix `False` not being an acceptable env (#176) Fix base loader when having no ENVVAR_PREFIX_ (Addresses #177) (#185) Hide DeprecationWarning from Pytest when testing for them (#186) Replace logging.basicConfig with handler on logger (#187) - Fix #189 added `settings.as_dict()` and `dynaconf list -o file.json` (#191) [Bruno Rocha] - Fix #184 - workdir should walk to root in ipython REPL (#190) [Bruno Rocha] - Fix #179 dynaconf cli shows only user defined vars unless -a used (#188) [Bruno Rocha] Command `dynaconf list` will show only user defined vars IF `--all|-a` is passed then it includes internal variables. - Replace logging.basicConfig with handler on logger (#187) [Jan Willhaus] - Hide DeprecationWarning from Pytest when testing for them (#186) [Jan Willhaus] * Hide DeprecationWarnings from Pytest when testing for them * Use parametrized test instead of repeating code - Fix base loader when having no ENVVAR_PREFIX_ (Addresses #177) (#185) [Jan Willhaus] * Fix `False` not being an acceptable env * Additional testcase for prefix being false from envvar * Fix mistaken reference to ENVVAR_PREFIX * Fix typo - Add example and test for issue #182 (#183) [Bruno Rocha] * Add working example for issue 182 * Option 2 added * Allowed `settings.load_file` programmatically - Removed pytest-xdist (#181) [Bruno Rocha] Now tests run in a separate tmpdir so xdist is not needed anymore - Fix `False` not being an acceptable env (#176) [Jan Willhaus] * Fix `False` not being an acceptable env * Additional testcase for prefix being false from envvar * unset envvar_prefix after test - Adhering to Github Community Standards (#175) [Bruno Rocha] - Add note to release script. [Bruno Rocha] - Release version 2.0.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (17): Release version 2.0.0 Added Django explicit mode to docs (#149) HOTIX: Django doc Logger is now cached (removed logging import time overhead) Update issue templates Adjusts issue templates Fix Typo in issue template fix #160 - invoking directory should not be search breaking point. Add explicit call to main() on cli.py (#165) Generate coverage.xml file (#167) Fix #166 renamed GLOBAL_ENV_ to ENVVAR_PREFIX_ (#168) Fix #169 renamed SETTINGS_MODULE_ to SETTINGS_FILE_ (#170) HOTFIX config.md on docs [skip ci] (#171) Fix some open file descriptors on exampls and tests (#172) Fix #151 setup pre-commit and black (#173) Add CONTRIBUTING.md, conrtib isntructions and Black badge (#174) Fix release script David Moreau Simard (1): Fix typos in bash export examples Jan Willhaus (2): Skip reloading envs for validators that only apply to current_env (#162) Fix #163 Allow disabling env prefix (#164) 2.0.1 (2019-04-22) ------------------ - Release version 2.0.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (17): Release version 2.0.0 Added Django explicit mode to docs (#149) HOTIX: Django doc Logger is now cached (removed logging import time overhead) Update issue templates Adjusts issue templates Fix Typo in issue template fix #160 - invoking directory should not be search breaking point. Add explicit call to main() on cli.py (#165) Generate coverage.xml file (#167) Fix #166 renamed GLOBAL_ENV_ to ENVVAR_PREFIX_ (#168) Fix #169 renamed SETTINGS_MODULE_ to SETTINGS_FILE_ (#170) HOTFIX config.md on docs [skip ci] (#171) Fix some open file descriptors on exampls and tests (#172) Fix #151 setup pre-commit and black (#173) Add CONTRIBUTING.md, conrtib isntructions and Black badge (#174) Fix release script David Moreau Simard (1): Fix typos in bash export examples Jan Willhaus (2): Skip reloading envs for validators that only apply to current_env (#162) Fix #163 Allow disabling env prefix (#164) - Fix release script. [Bruno Rocha] - Add CONTRIBUTING.md, conrtib isntructions and Black badge (#174) [Bruno Rocha] - Fix #151 setup pre-commit and black (#173) [Bruno Rocha] * Add pre-commit to makefile * Fix #151 setup pre-commit and black - Fix some open file descriptors on exampls and tests (#172) [Bruno Rocha] - HOTFIX config.md on docs [skip ci] (#171) [Bruno Rocha] - Fix #169 renamed SETTINGS_MODULE_ to SETTINGS_FILE_ (#170) [Bruno Rocha] Backwards compatibility maintained! - Fix #166 renamed GLOBAL_ENV_ to ENVVAR_PREFIX_ (#168) [Bruno Rocha] * Fix #166 renamed GLOBAL_ENV_ to ENVVAR_PREFIX_ See #166 * Added django compat example - Generate coverage.xml file (#167) [Bruno Rocha] - Add explicit call to main() on cli.py (#165) [Bruno Rocha] To use click-web tool the module should be able to be explicitly called. `python -m dynaconf.cli` - Fix #163 Allow disabling env prefix (#164) [Jan Willhaus, janw * Update docs for use of False instead of none] * Allow setting GLOBAL_ENV to "" or NoneType to remove prefix * Allow for underscore-only prefix with empty string GLOBAL_ENV * Test cases for the different GLOBAL_ENV settings * Update docs, add usage example * Apply suggestions from code review - Skip reloading envs for validators that only apply to current_env (#162) [Jan Willhaus] * Simplify control flow for single-env use-cases * Ensure uppercase env/current_env * Add test not reloading env with validation in same env * Pep8 compliance * Change mock call assertions for support in Py3.5 - Fix #160 - invoking directory should not be search breaking point. [Bruno Rocha] Search should stop at breaking point only if ROOT_PATH is defined - Fix Typo in issue template. [Bruno Rocha] - Adjusts issue templates. [Bruno Rocha] - Update issue templates. [Bruno Rocha] - Logger is now cached (removed logging import time overhead) [Bruno Rocha] Debugged using: `python3.7 -X importtime -c 'import app'` and `python3.7 -X importtime -c 'import dynaconf'` Found that the tries to import `logzero` were consuming 0.1us (not so much, but we dont want it) removed logzero, cached logger using lru_cache (that means that if loglevel changes, log changes) - imporved docs and badges. - Fix typos in bash export examples. [David Moreau Simard] - HOTIX: Django doc. [Bruno Rocha] - Added Django explicit mode to docs (#149) [Bruno Rocha] - Release version 2.0.0. [Bruno Rocha] Shortlog of commits since last release: Aaron DeVore (1): GH-111: Fix MERGE_ENABLED merging settings with themselves Bruno Rocha (21): Merge branch 'jperras-merge-multiple-settings-files' Merge branch 'master' of github.com:rochacbruno/dynaconf Fix #106 make PROJECT_ROOT_FOR_DYNACONF to work with custom paths Update dynaconf/utils/boxing.py Update dynaconf/utils/boxing.py Add release script and CHANGELOG in place of history. Release version 1.2.0 Tox is now part of pre-publish command Drop Python 3.4 Release version 1.2.1 add top contributors Fix #129 on settings file, single keys should be case insensitive. Fix #125 settings_module not being set on .configure() Fix #127 add configurable yaml loader method, default to full_load Fix #122 allow disable of core loaders, added examples. Fix #117 add support for extra secrets file (like for jenkins CI) Fix #110 add docs for dynaconf_include Add dynaconf_include examples Set up CI with Azure Pipelines (#142) Add dynaconf_merge fucntionality for dict and list settings. (#139) Preparing for 2.0.0 Byungjin Park (1): Fix typo Jaepil Koh (1): Update django.md Joel Perras (3): Allow dotted-path based setting of configuration key/value pairs. Handle nested includes in settings files. Remove extraneous lines. Mantas (3): Add INSTANCE_FOR_DYNACONF and --instance Remove mocker fixture Python 3.4 has different error message Matthias (1): Fix small typo in README.md Pete Savage (1): Fix exponential slow down when loader is run multiple times Raoul Snyman (1): Add environments into the path in Vault so that the same Vault server can be used for multiple environments mspinelli (2): fixed infinite recursion caused by copy() add tests for dynabox fix 2.0.0 (2019-04-09) ------------------ - Release version 2.0.0. [Bruno Rocha] Shortlog of commits since last release: Aaron DeVore (1): GH-111: Fix MERGE_ENABLED merging settings with themselves Bruno Rocha (21): Merge branch 'jperras-merge-multiple-settings-files' Merge branch 'master' of github.com:rochacbruno/dynaconf Fix #106 make PROJECT_ROOT_FOR_DYNACONF to work with custom paths Update dynaconf/utils/boxing.py Update dynaconf/utils/boxing.py Add release script and CHANGELOG in place of history. Release version 1.2.0 Tox is now part of pre-publish command Drop Python 3.4 Release version 1.2.1 add top contributors Fix #129 on settings file, single keys should be case insensitive. Fix #125 settings_module not being set on .configure() Fix #127 add configurable yaml loader method, default to full_load Fix #122 allow disable of core loaders, added examples. Fix #117 add support for extra secrets file (like for jenkins CI) Fix #110 add docs for dynaconf_include Add dynaconf_include examples Set up CI with Azure Pipelines (#142) Add dynaconf_merge fucntionality for dict and list settings. (#139) Preparing for 2.0.0 Byungjin Park (1): Fix typo Jaepil Koh (1): Update django.md Joel Perras (3): Allow dotted-path based setting of configuration key/value pairs. Handle nested includes in settings files. Remove extraneous lines. Mantas (3): Add INSTANCE_FOR_DYNACONF and --instance Remove mocker fixture Python 3.4 has different error message Matthias (1): Fix small typo in README.md Pete Savage (1): Fix exponential slow down when loader is run multiple times Raoul Snyman (1): Add environments into the path in Vault so that the same Vault server can be used for multiple environments mspinelli (2): fixed infinite recursion caused by copy() add tests for dynabox fix - Preparing for 2.0.0. [Bruno Rocha] Dynaconf 2.0.0 - Fix #129 get_fresh should be case insensitive - Fix #125 .configure was not loading `settings_module` passed as argument - Fix #127 fix YAML warnings and default to full_load - Allow disable of core loaders #122 - Added support for Jenkins secrets file #117 - Added more examples for includes #110 - Moved to Azure Pipelines CI #142 - Added 100% test coverage on windows (Unit & Functional tests) - Deprecated MERGE_ENABLED in favor of local dynaconf_merge - Fix #74 - Better File Searching (now building a reasonable Search Tree) - Now it finds settings when invoking from out of Script folder - Fixed test environment (each test now run in a separate tmpdir) - Added a check to avoid Circular references when starting settings inside settings - Added Django Extension v2 with better syntax and a lot od `inspect` instrospetion - Updated documentation about new features - Added a not that YAML is the recommended format for Django - Added support for Django Standalone Script - Added support for Django unit testing - Fix #148 `env` was not being passed to custom loaders - Fix #144 removed `six` as it is a Py3.4+ only project - Added Backwards compatibility for users using old django Extension - start_dotenv is now Lazy (only when settings._setup is called) - Added new _FOR_DYNACONF config options ENV_SWITCHER, SKIP_FILES, INCLUDES & SECRETS - Renamed config PROJECT_ROOT -> ROOT_PATH - Add dynaconf_merge fucntionality for dict and list settings. (#139) [Bruno Rocha] If your settings has existing variables of types `list` ot `dict` and you want to `merge` instead of `override` then the `dynaconf_merge` and `dynaconf_merge_unique` stanzas can mark that variable as a candidate for merging. For **dict** value: Your main settings file (e.g `settings.toml`) has an existing `DATABASE` dict setting on `[default]` env. Now you want to contribute to the same `DATABASE` key by addind new keys, so you can use `dynaconf_merge` at the end of your dict: In specific `[envs]` ```toml [default] database = {host="server.com", user="default"} [development] database = {user="dev_user", dynaconf_merge=true} [production] database = {user="prod_user", dynaconf_merge=true} ``` In an environment variable: ```bash export DYNACONF_DATABASE='{password=1234, dynaconf_merge=true}' ``` Or in an additional file (e.g `settings.yaml, .secrets.yaml, etc`): ```yaml default: database: password: 1234 dynaconf_merge: true ``` The `dynaconf_merge` token will mark that object to be merged with existing values (of course `dynaconf_merge` key will not be added to the final settings it is jsut a mark) The end result will be on `[development]` env: ```python settings.DATABASE == {'host': 'server.com', 'user': 'dev_user', 'password': 1234} ``` The same can be applied to **lists**: `settings.toml` ```toml [default] plugins = ["core"] [development] plugins = ["debug_toolbar", "dynaconf_merge"] ``` And in environment variable ```bash export DYNACONF_PLUGINS='["ci_plugin", "dynaconf_merge"]' ``` Then the end result on `[development]` is: ```python settings.PLUGINS == ["ci_plugin", "debug_toolbar", "core"] ``` The `dynaconf_merge_unique` is the token for when you want to avoid duplications in a list. Example: ```toml [default] scripts = ['install.sh', 'deploy.sh'] [development] scripts = ['dev.sh', 'test.sh', 'deploy.sh', 'dynaconf_merge_unique'] ``` ```bash export DYNACONF_SCRIPTS='["deploy.sh", "run.sh", "dynaconf_merge_unique"]' ``` The end result for `[development]` will be: ```python settings.SCRIPTS == ['install.sh', 'dev.sh', 'test.sh', 'deploy.sh', 'run.sh'] ``` > Note that `deploy.sh` is set 3 times but it is not repeated in the final settings. The **dynaconf_merge** functionality works only for the first level keys, it will not merge subdicts or nested lists (yet). - Set up CI with Azure Pipelines (#142) [Bruno Rocha] - setup azure pipelines ci - remove travis - fix windows support - Add dynaconf_include examples. [Bruno Rocha] - Fix #110 add docs for dynaconf_include. [Bruno Rocha] fix #110 - Fix #117 add support for extra secrets file (like for jenkins CI) [Bruno Rocha] Now it is possible to export SECRETS_FOR_DYNACONF and have this extra point loaded, like in a Jenkins CI you can specify on job. ```yaml secret_file: variable: SECRETS_FOR_DYNACONF credentials: type: specific_credentials value: /path/to/secrets_file.toml{json,ini,yaml,py} ``` That variable can also be a list of paths. - Fix #122 allow disable of core loaders, added examples. [Bruno Rocha] - Fix #127 add configurable yaml loader method, default to full_load. [Bruno Rocha] - Fix #125 settings_module not being set on .configure() [Bruno Rocha] - Fix #129 on settings file, single keys should be case insensitive. [Bruno Rocha] - GH-111: Fix MERGE_ENABLED merging settings with themselves. [Aaron DeVore] - Add top contributors. [Bruno Rocha] - Release version 1.2.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (9): Merge branch 'jperras-merge-multiple-settings-files' Merge branch 'master' of github.com:rochacbruno/dynaconf Fix #106 make PROJECT_ROOT_FOR_DYNACONF to work with custom paths Update dynaconf/utils/boxing.py Update dynaconf/utils/boxing.py Add release script and CHANGELOG in place of history. Release version 1.2.0 Tox is now part of pre-publish command Drop Python 3.4 Byungjin Park (1): Fix typo Jaepil Koh (1): Update django.md Joel Perras (3): Allow dotted-path based setting of configuration key/value pairs. Handle nested includes in settings files. Remove extraneous lines. Mantas (3): Add INSTANCE_FOR_DYNACONF and --instance Remove mocker fixture Python 3.4 has different error message Matthias (1): Fix small typo in README.md Pete Savage (1): Fix exponential slow down when loader is run multiple times Raoul Snyman (1): Add environments into the path in Vault so that the same Vault server can be used for multiple environments mspinelli (2): fixed infinite recursion caused by copy() add tests for dynabox fix 1.2.1 (2019-03-11) ------------------ - Release version 1.2.1. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (9): Merge branch 'jperras-merge-multiple-settings-files' Merge branch 'master' of github.com:rochacbruno/dynaconf Fix #106 make PROJECT_ROOT_FOR_DYNACONF to work with custom paths Update dynaconf/utils/boxing.py Update dynaconf/utils/boxing.py Add release script and CHANGELOG in place of history. Release version 1.2.0 Tox is now part of pre-publish command Drop Python 3.4 Byungjin Park (1): Fix typo Jaepil Koh (1): Update django.md Joel Perras (3): Allow dotted-path based setting of configuration key/value pairs. Handle nested includes in settings files. Remove extraneous lines. Mantas (3): Add INSTANCE_FOR_DYNACONF and --instance Remove mocker fixture Python 3.4 has different error message Matthias (1): Fix small typo in README.md Pete Savage (1): Fix exponential slow down when loader is run multiple times Raoul Snyman (1): Add environments into the path in Vault so that the same Vault server can be used for multiple environments mspinelli (2): fixed infinite recursion caused by copy() add tests for dynabox fix - Fix exponential slow down when loader is run multiple times. [Pete Savage] * When using context managers, the loader is invoked each time. This was slowing down in an exponential manner each time the it was run. The eventual cause of this was down to an attribute being used as a list. The object merge dutifully tried to expand this item out again and again even in the case that the list was a single item, resulting in [item], becoming [item, item]. The next time the merge was run, this process was run again, but for each item in the list. In this particular instance the list was identical, it meant that the list grew exponentially. * This fix is a short optimization that checks to see if the old list is identical to the new list. In which case, there is no merge to complete so we simply return. - Add environments into the path in Vault so that the same Vault server can be used for multiple environments. [Raoul Snyman] - Fix typo. [Byungjin Park] - Drop Python 3.4. [Bruno Rocha] - Tox is now part of pre-publish command. [Bruno Rocha] - Release version 1.2.0. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (6): Merge branch 'jperras-merge-multiple-settings-files' Merge branch 'master' of github.com:rochacbruno/dynaconf Fix #106 make PROJECT_ROOT_FOR_DYNACONF to work with custom paths Update dynaconf/utils/boxing.py Update dynaconf/utils/boxing.py Add release script and CHANGELOG in place of history. Jaepil Koh (1): Update django.md Joel Perras (3): Allow dotted-path based setting of configuration key/value pairs. Handle nested includes in settings files. Remove extraneous lines. Mantas (3): Add INSTANCE_FOR_DYNACONF and --instance Remove mocker fixture Python 3.4 has different error message Matthias (1): Fix small typo in README.md mspinelli (2): fixed infinite recursion caused by copy() add tests for dynabox fix 1.2.0 (2018-11-30) ------------------ - Release version 1.2.0. [Bruno Rocha] Shortlog of commits since last release: Bruno Rocha (6): Merge branch 'jperras-merge-multiple-settings-files' Merge branch 'master' of github.com:rochacbruno/dynaconf Fix #106 make PROJECT_ROOT_FOR_DYNACONF to work with custom paths Update dynaconf/utils/boxing.py Update dynaconf/utils/boxing.py Add release script and CHANGELOG in place of history. Jaepil Koh (1): Update django.md Joel Perras (3): Allow dotted-path based setting of configuration key/value pairs. Handle nested includes in settings files. Remove extraneous lines. Mantas (3): Add INSTANCE_FOR_DYNACONF and --instance Remove mocker fixture Python 3.4 has different error message Matthias (1): Fix small typo in README.md mspinelli (2): fixed infinite recursion caused by copy() add tests for dynabox fix - Add release script and CHANGELOG in place of history. [Bruno Rocha] - Add tests for dynabox fix. [mspinelli] - Update dynaconf/utils/boxing.py. [Bruno Rocha, mspinelli] - Update dynaconf/utils/boxing.py. [Bruno Rocha, mspinelli] - Fixed infinite recursion caused by copy() [mspinelli] - Fix #106 make PROJECT_ROOT_FOR_DYNACONF to work with custom paths. [Bruno Rocha] Added example/project_root and entry on Makefile:test_examples - Update django.md. [Jaepil Koh] Typo! - Fix small typo in README.md. [Matthias] - Merge branch 'master' of github.com:rochacbruno/dynaconf. [Bruno Rocha] - Python 3.4 has different error message. [Mantas] - Remove mocker fixture. [Mantas] Left this accidentaly. https://travis-ci.org/rochacbruno/dynaconf/jobs/452612532 - Add INSTANCE_FOR_DYNACONF and --instance. [Mantas] There parameters allows dynaconf to use different LazySettings instance if project uses one. Also did some other fixes along the way: - Added `catch_exceptions=False` to `CliRunner.invoke` in order to prevent click from swallowing errors silently. This uncovered other errors in init and validate cli commands. - Removed module level code execution from cli module. Module level code execution makes it really difficult to test code. Now cli does not rely on global state and can be tested properly. - Removed a code snipper from LazySettings which modified global default_settings values. This means, that each LazySettings constructor call has side effects. - `dynaconf validate` command tests were useless because they didn't test anything and I found, that `dynaconf validate` command don't even work and raises ValidationError if there are any validation errors. Changed that to cli friendly error message. - Merge branch 'jperras-merge-multiple-settings-files' [Bruno Rocha] - Remove extraneous lines. [Joel Perras] - Handle nested includes in settings files. [Joel Perras] A settings file can include a `dynaconf_include` stanza, whose exact syntax will depend on the type of settings file (json, yaml, toml, etc) being used: ```toml [default] dynaconf_include = ["/absolute/path/to/plugin1.toml", "relative/path/to/plugin2.toml"] DEBUG = false SERVER = "www.example.com" ``` When loaded, the files located at the (relative or absolute) paths in the `dynaconf_include` key will be parsed, in order, and override any base settings that may exist in your current configuration. The paths can be relative to the base `settings.(toml|yaml|json|ini|py)` file, or can be absolute paths. The idea here is that plugins or extensions for whatever framework or architecture you are using can provide their own configuration values when necessary. It is also possible to specify glob-based patterns: ```toml [default] dynaconf_include = ["configurations/*.toml"] DEBUG = false SERVER = "www.example.com" ``` Currently, only a single level of includes is permitted to keep things simple and straightforward. - Allow dotted-path based setting of configuration key/value pairs. [Joel Perras] You can set a value with an arbitrary number of nested keys, separated by dots: ```python settings.set('nested_1.nested_2.nested_3.nested_4', 'secret') ``` And accessing the keys/values with dotted-path lookup behaves as expected: ```python print(settings.NESTED_1.NESTED_2.NESTED_3.to_dict()) ``` If for some reason you didn't want to have a key parsed into nested structures delimited by dots and just wanted a key of "foo.bar", you can disable the parsing with: ```python settings.set('nested_1.nested_2.nested_3.nested_4', 'secret', dotted_lookup=False) ``` And accessing keys that don't exist will raise `KeyError`: ```python settings.NESTED_1.NESTED_5 ``` 1.1.0 (2018-10-26) ------------------ - Released 1.1.0. [Bruno Rocha] - Added `MERGE_ENABLED_FOR_DYNACONF` with ability to merge nested dictionaries instead of replacing PR #88 - Support for dot notation to access nested dictionaries like `settings['KEY.OTHER.NESTED.DEEPER']` PR #93 - Support dotted notation for validators PR #98 - Fixed a bug in SETTINGS_MODULE cleanup when `.setenv` method was called PR #97 - Added Python 3.7 to test matrix PR #99 - Fixing new flake8 warnings. [Bruno Rocha] - Update py.test command in tox to allow passing positional arguments. [Joel Perras] The basic, default functionality of running `tox` remains unchanged. You are now, however, able to pass positional arguments to `py.test` at invocation time. For example: ```bash tox -- -x --pdb tests/test_basic.py ``` Which will pass all input after the `--` separator (which is used to signify the end of possible options to `tox`) down to the `py.test` command in the `{posargs}` location, as defined in `tox.ini`. - Enable Python 3.7 env for tox testing. [Joel Perras] - Enable python 3.7 in TravisCI config. [Joel Perras] - Updates Missing singleton with __eq__ dunder. (#98) [Joël Perras] Adds some additional tests for the `Missing` class and singleton instance usage to ensure it returns equality only for comparisons to itself and not `None`, or `False`, or `True`. - Merge branch 'jperras-dotted-validators' [Bruno Rocha] - Updates Missing singleton with __eq__ dunder. [Joel Perras] Adds some additional tests for the `Missing` class and singleton instance usage to ensure it returns equality only for comparisons to itself and not `None`, or `False`, or `True`. - Implements dotted-path validator name declarations. [Joel Perras] One is now able to write: ```python settings.validators.register( Validator('REDIS', must_exist=True, is_type_of=dict), Validator('REDIS.HOST', must_exist=True, is_type_of=str), Validator('REDIS.PORT', must_exist=True, is_type_of=int), ) ``` Which will validate the dotted attributes as nested structures. For example, in yaml: ```yaml DEFAULT: REDIS: HOST: localhost PORT: 1234 ``` This necessitated a slight but non-negligible change in the implementation of `Settings.exists()`, which previously did a shallow check of loaded data. It has now been updated to perform a `Settings.get()` of the key in question, and compares that to a newly defined sentinel value to ensure `None` values do not cause a false negative result. New tests and assertions have been added to cover the new functionality. Docs have been updated to show an example of the nested validator name definition in action. Closes rochacbruno/dynaconf#85. - Fix #94 setenv cleans SETTINGS_MODULE attribute. [Bruno Rocha] - Merge branch 'jperras-dot-traversal-access' [Bruno Rocha] - Merge branch 'dot-traversal-access' of https://github.com/jperras/dynaconf into jperras-dot-traversal-access. [Bruno Rocha] - Allow dot-traversal access to nested dictionaries. [Joel Perras] A simple memoized recursion has been added to `get()` if the key contains at least one dot. The caller can choose to opt-out of this behaviour by specifying the `dotted_lookup` argument: ```python settings('AUTH.USERNAME', dotted_lookup=False) ``` While the performance impact of this has not been quantified, the net impact in any real-world application should be minimal due to typical nesting levels, and the fact that we overwrite the memoized portion of the dotted-key lookup on each iteration. - Avoids regressions [✓] - Can be opted-out on a per-call basis [✓] - Minimal performance impact [✓] - Documented [✓] - Tested [✓] - Examples added [✓] Closes rochacbruno/dynaconf#84 - Merge branch 'rsnyman-merge-settings' [Bruno Rocha] - Add example for merge_configs. [Bruno Rocha] - Add setting merging. [Raoul Snyman] - Addd the ability to merge nested structures instead of completely overwriting them - Use monkeypatch to stop one test from interferring with another - Updated documentation 1.0.6 (2018-09-13) ------------------ - Release 1.0.6. [Bruno Rocha] Fixed issue #81 - added ENCODING_FOR_DYNACONF to handle different settings files encodings specially on Windows - Add ENCODING_FOR_DYNACONF to handle different file encoding Fix #81. [Bruno Rocha] By default ENCODING_FOR_DYNACONF is utf-8 (recommended to always write settings files in utf-8) If you need to change the format of settings file set the variable: ``` export ENCODING_FOR_DYNACONF="cp1252" ``` 1.0.5 (2018-09-07) ------------------ - Bump dev version. [Bruno Rocha] - Added few more enhancements to django and flask extensions + docs. [Bruno Rocha] - Bump dev version. [Bruno Rocha] 1.0.4 (2018-09-07) ------------------ - Fix the definition of Django prefixed variable. [Bruno Rocha] - Merge pull request #78 from mattkatz/patch-1. [Bruno Rocha] small corrections for usage.md - Small corrections for usage.md. [Matt Katz] This library is great, just a correction in the docs. There must be AT LEAST one default section. Changed **ATTENTION** to **ATTENTION**: to match with the style of **NOTE:** - Merge pull request #75 from yoyonel/master. [Bruno Rocha] Fix in 'dynaconf/base.py' for __getitem__ method - Bump version. [latty] - [Fix] in 'dynaconf/base.py' for __getitem__ method, change (fix) the condition to raise a exception. Update unit tests. Bump version. [latty] - Release 1.0.3. [Bruno Rocha] - Excluded example and tests from realease dist - removed root logger configuration 1.0.3 (2018-06-26) ------------------ - Merge pull request #72 from chobeat/issue_71. [Bruno Rocha] Removed root config - Removed root config. [Simone Robutti] - Merge pull request #70 from allan-silva/master. [Bruno Rocha] Exclude example and tests folders from setup (twitter help wanted) - Exclude example and tests folders from setup (twitter help wanted) [allan.silva] - Merge pull request #67 from cassiobotaro/patch-1. [Bruno Rocha] Incorrect help - Fix docs. [cassiobotaro] - Incorrect help. [Cássio Botaro] For while is impossible to use --to as argument. - Merge pull request #66 from gpkc/patch-1. [Bruno Rocha] Fixing typos - Merge pull request #1 from gpkc/patch-2. [Guilherme Caminha] Update README.md - Update README.md. [Guilherme Caminha] - Update usage.md. [Guilherme Caminha] - Adjust logs to include python module names. [Bruno Rocha] - Fix sphinx aafig syntax for python 3.x. [Bruno Rocha] 1.0.2 (2018-05-31) ------------------ - Merge pull request #65 from rochacbruno/testing_bare_install. [Bruno Rocha] Add install test stage - Add -y. [Bruno Rocha] - Add install test stage. [Bruno Rocha] - Fix loader import error and improved logs. [Bruno Rocha] - Clean up [skip ci] [Bruno Rocha] - Fix URL generation in markdown for sphinx [skip ci] [Bruno Rocha] - Merge pull request #64 from rochacbruno/improve_docs. [Bruno Rocha] Improved documentation - Improved documentation. [Bruno Rocha] - [skip ci] [Bruno Rocha] 1.0.1 (2018-05-30) ------------------ - Merge pull request #63 from rochacbruno/adds_more_python_versions. [Bruno Rocha] Adds more python versions - Cover. [Bruno Rocha] - Cover. [Bruno Rocha] - Skip 3.7-dev. [Bruno Rocha] - More trabis build stages. [Bruno Rocha] - Add missing .env. [Bruno Rocha] - Fix #60 CLI validator command. [Bruno Rocha] - Fix #59 cli commands working for Flask and Django apps. [Bruno Rocha] - Fixes to support Python 3.4, 3.5 and 3.6 Fix #62. [Bruno Rocha] - Strict use of _FOR_DYNACONF envvars. [Bruno Rocha] - Aafigure. [Bruno Rocha] - Pinned docutils. [Bruno Rocha] - Rtfd fix. [Bruno Rocha] - Add rtfd yml. [Bruno Rocha] - Added init file to docs. [Bruno Rocha] - Add import path. [Bruno Rocha] - Docs. [Bruno Rocha] - Finished README with all the new implementations. [Bruno Rocha] 1.0.0 (2018-05-28) ------------------ - Merge pull request #56 from rochacbruno/all_the_namespace_changed_to_env. [Bruno Rocha] Major Breaking Refactor related to #54 - Travis fix 2. [Bruno Rocha] - Travis global fix. [Bruno Rocha] - Travis fix for new style toml envvars. [Bruno Rocha] - Deprecated `@type` casting in favor of TOML syntax, rewriting readme. [Bruno Rocha] - Add `settings.flag` [Bruno Rocha] - Using `dynaconf write` in test_redis|vault. [Bruno Rocha] - Added `dynaconf --docs` [Bruno Rocha] - Added `dynaconf --version` [Bruno Rocha] - Removed transformators. [Bruno Rocha] - 100% coverage for validators. [Bruno Rocha] - Increase cli test coverage. [Bruno Rocha] - Dynaconf variables in blue and user variables in green. [Bruno Rocha] - Added `dynaconf list` and `dynaconf write` subcommands. [Bruno Rocha] - More cli commands lsit and write. [Bruno Rocha] - Added more tests for cli and py loader. [Bruno Rocha] - Replaced coveralls with codecov #57. [Bruno Rocha] - Modularized the loaders, added `dynaconf init` command. [Bruno Rocha] - As environment variable the only prefix allowed is the GLOBAL_ENV.. default to DYNACONF_ [Bruno Rocha] - Added more examples/tests and test_cli. [Bruno Rocha] - Removed cleaners. [Bruno Rocha] - Major Breaking Refactor related to #54. [Bruno Rocha] 0.7.6 (2018-05-21) ------------------ - Merge pull request #52 from rochacbruno/fix_namespace_in_django. [Bruno Rocha] Fix namespace swithc in django apps - Add missing .env. [Bruno Rocha] - Fix namespace swithc in django apps. [Bruno Rocha] 0.7.5 (2018-05-20) ------------------ - Merge pull request #51 from rochacbruno/added_django_extension. [Bruno Rocha] Added django extension - 0.7.5 release with Django extension (experimental) [Bruno Rocha] - Dont commit dbs. [Bruno Rocha] - Added Django extension tests and example app. [Bruno Rocha] - Added Django extension. [Bruno Rocha] 0.7.4 (2018-05-19) ------------------ - Merge pull request #50 from rochacbruno/074. [Bruno Rocha] Fix precedence of namespace in loaders - Fix precedence of namespace in loaders. [Bruno Rocha] - Merge pull request #49 from thekashifmalik/patch-1. [Bruno Rocha] Fix typo in README. - Fix typo in README. [Kashif Malik] - HOTFIX: redis config. [Bruno Rocha] - Merge pull request #48 from rochacbruno/redis_tests. [Bruno Rocha] Added tests for Redis loader - Added tests for Redis loader. [Bruno Rocha] - Merge pull request #47 from rochacbruno/vault_tests. [Bruno Rocha] Added test for vaultproject - Fix deadlock in vault writer. [Bruno Rocha] - Added test for vaultproject. [Bruno Rocha] 0.7.3 (2018-05-13) ------------------ - Merge pull request #45 from rochacbruno/vault_loader. [Bruno Rocha] Added support for vaultproject (hashi corp) loader - Added README section. [Bruno Rocha] - Added note to readme. [Bruno Rocha] - Added tests. [Bruno Rocha] - Fixing for python-box 3.2.0. [Bruno Rocha] - Added config AUTO_CAST_FOR_DYNACONF=off|0|disabled|false Suggested by @danilobellini. [Bruno Rocha] - Fixed env variable for debug level in README.md. [Simone Robutti] - Implementation of Vault loader. [Bruno Rocha] - Vaultproject loader implementation. [Bruno Rocha] - Merge pull request #46 from rochacbruno/disable_cast. [Bruno Rocha] Added config AUTO_CAST_FOR_DYNACONF=off|0|disabled|false - Added note to readme. [Bruno Rocha] - Added tests. [Bruno Rocha] - Fixing for python-box 3.2.0. [Bruno Rocha] - Added config AUTO_CAST_FOR_DYNACONF=off|0|disabled|false Suggested by @danilobellini. [Bruno Rocha] - Merge pull request #44 from chobeat/patch-1. [Bruno Rocha] Fixed env variable for debug level in README.md - Fixed env variable for debug level in README.md. [Simone Robutti] 0.7.2 (2018-05-07) ------------------ - Added test for compat. [Bruno Rocha] - Added SETTINGS_MODULE to SETTINGS_MODULE_FOR_DYNACONF in compat. [Bruno Rocha] - Added backwards compatibility for old style kwargs. [Bruno Rocha] - Merge pull request #30 from vladcalin/add-docs. [Bruno Rocha] Add docs skeleton with autogenerated module docs - Add docs skeleton with autogenerated module docs. [Vlad Calin] 0.7.0 (2018-05-07) ------------------ - README updates [ci skip] [Bruno Rocha] - Added support for `.secrets` files. [Bruno Rocha] - Merge pull request #43 from rochacbruno/test_coverage. [Bruno Rocha] Adjusting ENVVARS names and better test coverage - Travis testing. [Bruno Rocha] - Adjust travis.yml for muultiple jobs. [Bruno Rocha] - Never cleans default keys. [Bruno Rocha] - Refactoring for better test cov. [Bruno Rocha] - Adjusting ENVVARS names and better test coverage. [Bruno Rocha] 0.6.0 (2018-05-04) ------------------ - Release of 0.6.0. [Bruno Rocha] - Merge pull request #42 from rochacbruno/fix41. [Bruno Rocha] Fix #41 - Fix #41. [Bruno Rocha] - Merge pull request #40 from rochacbruno/inifiles. [Bruno Rocha] ini and json files + parseconf recursive and find_file function - Ini and json files + parseconf recursive and find_file function. [Bruno Rocha] - Added support for .ini and .json files - parse conf is now recursive to parse dict inner data - Cloned find_file function from dotenv - Merge pull request #38 from rochacbruno/flask_dot_env. [Bruno Rocha] Added Flask 1.0 dotenv support - IMplemented TOML loader. [Bruno Rocha] - Adjusted MARKDOWN. [Bruno Rocha] - Added Flask 1.0 dotenv support. [Bruno Rocha] 0.5.2 (2017-10-03) ------------------ - Small fix on 0.5.2 :hamster: [Bruno Rocha] - 0.5.1 with YAML hotfixes and allowing multiple yaml files. [Bruno Rocha] 0.5.0 (2017-09-26) ------------------ - Drop 3.4 and 3.5. [Bruno Rocha] - Silent errors on YAML missing namespace by default. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Merge branch 'Sytten-expand-yaml-config' [Bruno Rocha] - Specialized Box as Dynabox to allow upper and lower case access. [Bruno Rocha] - Use box. [Emile Fugulin] - Add expanded object for yaml. [Emile Fugulin] 0.4.5 (2017-05-30) ------------------ - Update README.md. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Merge pull request #20 from douglas/master. [Bruno Rocha] Upgrade dynaconf to 0.4.5 =) - Upgrade dynaconf to 0.4.5 =) [Douglas Soares de Andrade] - Improves the way Tox installs the projects dependencies. [Douglas Soares de Andrade] - Make tests directory a package. [Douglas Soares de Andrade] - So we can use the syntax from dynaconf import … - Make it clear where we are getting LazySettings from. [Douglas Soares de Andrade] - Add m2r and Flask to Pipenv. [Douglas Soares de Andrade] - Removing pdbpp as it breaks with Python 3.3. [Douglas Soares de Andrade] - Update readme. [Bruno Rocha] - Update README. [Bruno Rocha] 0.4.4 (2017-03-21) ------------------ - HOTFIX: Flask templates always expects `None` for KeyError or AttrError. [Bruno Rocha] - Bump version. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Added FlaskDynaconf to readme. [Bruno Rocha] - Merge pull request #16 from rochacbruno/added_flaskdynaconf. [Bruno Rocha] Added FlaskDynaconf - Added FlaskDynaconf. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Merge pull request #15 from douglas/master. [Bruno Rocha] Make the project work both on Python2 and Python3 - PEP8/Pylint and fixes equality operators. [Douglas Soares de Andrade] - Remove unused code. [Douglas Soares de Andrade] - PEP8 and Pylint fixes. [Douglas Soares de Andrade] - Remove pypy3 as it does not work. [Douglas Soares de Andrade] - Adding pypy and pypy3 to Travis. [Douglas Soares de Andrade] - Oops, need to rename _super to super. [Douglas Soares de Andrade] - Fix the import according to pep8. [Douglas Soares de Andrade] - Remove this to see if it is still an issue. [Douglas Soares de Andrade] - Adding Python 2.7. [Douglas Soares de Andrade] - Adding the editorconfig file. [Douglas Soares de Andrade] - Add Pipfile.lock to .gitignore. [Douglas Soares de Andrade] - Small Refactory. [Douglas Soares de Andrade] - Adding object to the Settings classe to make it work with Python2 - Small Refactory. [Douglas Soares de Andrade] - Reordering the imports according to pylint and flake8 - Adding object to the classes to make them work with Python2 - Small Refactory. [Douglas Soares de Andrade] - Fixing the __init__ signature to make it compatible with python2 and python3 - Adding object to the class to make Python2 work - Adding the Pipenv file. [Douglas Soares de Andrade] - To allow us to use: https://github.com/kennethreitz/pipenv - Adding Tox to helps us test the library. [Douglas Soares de Andrade] - Fix #14 casting bool for booleans tks to @dbstraffin. [Bruno Rocha] - Fix yaml cleaner, renamed `defined` to `must_exist` in validator. [Bruno Rocha] - Added validators. [Bruno Rocha] 0.4.1 (2017-02-12) ------------------ - Bump 0.4.1. [Bruno Rocha] - Merge pull request #13 from rochacbruno/add_yaml_support. [Bruno Rocha] Added YAML support - Added YAML support. [Bruno Rocha] - Force pip upgrade in travis. [Bruno Rocha] - Drop support to Python 2.x - #MoveToPython3 Now! [Bruno Rocha] - Add 'decode_responses': True note. [Bruno Rocha] - Fix travis error. [Bruno Rocha] - Python 3 support. [Bruno Rocha] - Update README.md. [Bruno Rocha] 0.3.0 (2016-01-14) ------------------ - Fix error when envvar key has leading or trailing spaces. [Bruno Rocha] - Pip released. [Bruno Rocha] - Pypi is in troublr to release. [Bruno Rocha] - Bump. [Bruno Rocha] - If 'settings.py' is found on PROJECT_ROOT it is read. [Bruno Rocha] - Make release. [Bruno Rocha] - Path_for returns rooted path if starts with / [Bruno Rocha] - Added settings.path_for. [Bruno Rocha] - Ignore functional styling smells. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Travis envvars matrix. [Bruno Rocha] - Update .travis.yml. [Bruno Rocha] - Starting to write tests :) [Bruno Rocha] - Simplified objects, removed UserSettings, removed exceptions. [Bruno Rocha] 0.2.7 (2015-12-23) ------------------ - Removed six and used obj.set. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Added png. [Bruno Rocha] - Redis loader uses hash. [Bruno Rocha] - Using HASH to store data, added always_fresh vars and context thanks to @dmoliveira and @ederfmartins. [Bruno Rocha] - Added settings_module as cached property. [Bruno Rocha] - Added delete function to redis_writer. [Bruno Rocha] - Added note about get_fresh in readme. [Bruno Rocha] - Better namespace management, get_fresh(key) to access redis. [Bruno Rocha] - Now it can be used programatically. [Bruno Rocha] 0.2.1 (2015-12-20) ------------------ - Added redis_writer. [Bruno Rocha] - Update readme. [Bruno Rocha] 0.2.0 (2015-12-20) ------------------ - Can also load from arbitraty filepath. [Bruno Rocha] - Renamed var, added loaders, bump version. [Bruno Rocha] 0.1.2 (2015-08-20) ------------------ - Format on readme. [Bruno Rocha] - More casting options. [Bruno Rocha] - Fix #1 multiple namespaces. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Update README.md. [Bruno Rocha] - Added default. [Bruno Rocha] - Initial commit. [Bruno Rocha] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1600871681.0 dynaconf-3.1.7/CONTRIBUTING.md0000644000175000017500000001310700000000000017153 0ustar00rochacbrunorochacbruno# Contributing When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. Please note we have a code of conduct, please follow it in all your interactions with the project. This Diagram can help you understand visually what happens on Dynaconf: https://viewer.diagrams.net/?highlight=0000ff&edit=_blank&layers=1&nav=1&title=Dynaconf#Uhttps%3A%2F%2Fdrive.google.com%2Fuc%3Fid%3D11krXcDr67FGci_f36FZO-hiL08z4FuL9%26export%3Ddownload ## Pull Request Process 1. Ensure your local environment is set. 1. Clone your own fork of this repo 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) 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! ### Common Workflow: ```bash # clone your fork of this repo git clone git@github.com:{$USER}/dynaconf.git # Add the upstream remote git remote add upstream https://github.com/rochacbruno/dynaconf.git # Activate your Python Environment python3.7 -m venv venv source venv/bin/activate # Install dynaconf for development make all # Checkout to a working branch git checkout -b my_feature # Open your favorite editor (VSCode for example) code . # After editing please rebase with upstream 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. # Then ensure everything is ok make all # Now commit your changes 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. ``` ### Run integration tests * "make all" do not run integration tests for Redis and Vault. * If you want to run integration tests, make sure you have docker installed ```bash # To install docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh # To permit your user run docker commands without sudo sudo usermod -aG docker {$USER} # Run complete integration tests make test_integration # or Run functional example tests individually make test_redis make test_vault ``` ## Code of Conduct ### Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ### Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ### Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ### Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ### Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at `rochacbruno [at] gmail [dot] com`. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ### Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1590127290.0 dynaconf-3.1.7/LICENSE0000644000175000017500000000206600000000000015731 0ustar00rochacbrunorochacbrunoThe MIT License (MIT) Copyright (c) 2015 Bruno Rocha 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. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1600729046.0 dynaconf-3.1.7/MANIFEST.in0000644000175000017500000000015600000000000016460 0ustar00rochacbrunorochacbrunoinclude *.md include *.png include LICENSE include VERSION include dynaconf/VERSION prune dynaconf/vendor_src ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1631217935.1303446 dynaconf-3.1.7/PKG-INFO0000644000175000017500000001661000000000000016021 0ustar00rochacbrunorochacbrunoMetadata-Version: 2.1 Name: dynaconf Version: 3.1.7 Summary: The dynamic configurator for your Python Project Home-page: https://github.com/rochacbruno/dynaconf Author: Bruno Rocha Author-email: rochacbruno@gmail.com License: MIT Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Framework :: Django Classifier: Framework :: Flask Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English 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: Topic :: Utilities Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.7 Description-Content-Type: text/markdown Provides-Extra: redis Provides-Extra: vault Provides-Extra: yaml Provides-Extra: toml Provides-Extra: ini Provides-Extra: configobj Provides-Extra: all License-File: LICENSE [![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&utm_medium=referral&utm_content=rochacbruno/dynaconf&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) [![Foo](https://xscode.com/assets/promo-banner.svg)](https://xscode.com/rochacbruno/dynaconf) ## Features - Inspired by the [12-factor application guide](https://12factor.net/config) - Settings management (default values, validation, parsing, templating) - Protection of sensitive information (passwords/tokens) - Multiple file formats `toml|yaml|json|ini|py` and also customizable loaders. - Full support for environment variables to override existing settings (dotenv support included). - Optional layered system for multi environments `[default, development, testing, production]` - Built-in support for Hashicorp Vault and Redis as settings and secrets storage. - Built-in extensions for **Django** and **Flask** web frameworks. - 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 $ pip install dynaconf ``` #### Initialize Dynaconf on project root directory ```plain $ cd path/to/your/project/ $ dynaconf init -f toml ⚙️ Configuring your Dynaconf environment ------------------------------------------ 🐍 The file `config.py` was generated. 🎛️ settings.toml created to hold your settings. 🔑 .secrets.toml created to hold your secrets. 🙈 the .secrets.* is also included in `.gitignore` beware to not push your secrets to a public repo. 🎉 Dynaconf is configured! read more on https://dynaconf.com ``` > **TIP:** You can select `toml|yaml|json|ini|py` on `dynaconf init -f ` **toml** is the default and also the most recommended format for configuration. #### Dynaconf init creates the following files ```plain . ├── 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) ``` On the file `config.py` Dynaconf init generates the following boilerpate ```py from dynaconf import Dynaconf settings = Dynaconf( envvar_prefix="DYNACONF", # export envvars with `export DYNACONF_FOO=bar`. settings_files=['settings.yaml', '.secrets.yaml'], # Load files in the given order. ) ``` > **TIP:** You can create the files yourself instead of using the `init` command as shown above and you can give any name you want instead of the default `config.py` (the file must be in your importable python path) - See more options that you can pass to `Dynaconf` class initializer on https://dynaconf.com #### Using Dynaconf Put your settings on `settings.{toml|yaml|ini|json|py}` ```toml username = "admin" port = 5555 database = {name='mydb', schema='main'} ``` Put sensitive information on `.secrets.{toml|yaml|ini|json|py}` ```toml password = "secret123" ``` > **IMPORTANT:** `dynaconf init` command puts the `.secrets.*` in your `.gitignore` to avoid it to be exposed on public repos but it is your responsibility to keep it safe in your local environment, also the recommendation for production environments is to use the built-in support for Hashicorp Vault service for password and tokens. Optionally you can now use environment variables to override values per execution or per environment. ```bash # override `port` from settings.toml file and automatically casts as `int` value. export DYNACONF_PORT=9900 ``` On your code import the `settings` object ```py from path.to.project.config import settings # Reading the settings settings.username == "admin" # dot notation with multi nesting support settings.PORT == 9900 # case insensitive settings['password'] == "secret123" # dict like access settings.get("nonexisting", "default value") # Default values just like a dict settings.databases.name == "mydb" # Nested key traversing settings['databases.schema'] == "main" # Nested key traversing ``` ## More - Settings Schema Validation - Custom Settings Loaders - Vault Services - Template substitutions - etc... 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) ## more If you are looking for something similar to Dynaconf to use in your Rust projects: https://github.com/rubik/hydroconf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631213309.0 dynaconf-3.1.7/README.md0000644000175000017500000001426000000000000016202 0ustar00rochacbrunorochacbruno[![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&utm_medium=referral&utm_content=rochacbruno/dynaconf&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) [![Foo](https://xscode.com/assets/promo-banner.svg)](https://xscode.com/rochacbruno/dynaconf) ## Features - Inspired by the [12-factor application guide](https://12factor.net/config) - Settings management (default values, validation, parsing, templating) - Protection of sensitive information (passwords/tokens) - Multiple file formats `toml|yaml|json|ini|py` and also customizable loaders. - Full support for environment variables to override existing settings (dotenv support included). - Optional layered system for multi environments `[default, development, testing, production]` - Built-in support for Hashicorp Vault and Redis as settings and secrets storage. - Built-in extensions for **Django** and **Flask** web frameworks. - 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 $ pip install dynaconf ``` #### Initialize Dynaconf on project root directory ```plain $ cd path/to/your/project/ $ dynaconf init -f toml ⚙️ Configuring your Dynaconf environment ------------------------------------------ 🐍 The file `config.py` was generated. 🎛️ settings.toml created to hold your settings. 🔑 .secrets.toml created to hold your secrets. 🙈 the .secrets.* is also included in `.gitignore` beware to not push your secrets to a public repo. 🎉 Dynaconf is configured! read more on https://dynaconf.com ``` > **TIP:** You can select `toml|yaml|json|ini|py` on `dynaconf init -f ` **toml** is the default and also the most recommended format for configuration. #### Dynaconf init creates the following files ```plain . ├── 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) ``` On the file `config.py` Dynaconf init generates the following boilerpate ```py from dynaconf import Dynaconf settings = Dynaconf( envvar_prefix="DYNACONF", # export envvars with `export DYNACONF_FOO=bar`. settings_files=['settings.yaml', '.secrets.yaml'], # Load files in the given order. ) ``` > **TIP:** You can create the files yourself instead of using the `init` command as shown above and you can give any name you want instead of the default `config.py` (the file must be in your importable python path) - See more options that you can pass to `Dynaconf` class initializer on https://dynaconf.com #### Using Dynaconf Put your settings on `settings.{toml|yaml|ini|json|py}` ```toml username = "admin" port = 5555 database = {name='mydb', schema='main'} ``` Put sensitive information on `.secrets.{toml|yaml|ini|json|py}` ```toml password = "secret123" ``` > **IMPORTANT:** `dynaconf init` command puts the `.secrets.*` in your `.gitignore` to avoid it to be exposed on public repos but it is your responsibility to keep it safe in your local environment, also the recommendation for production environments is to use the built-in support for Hashicorp Vault service for password and tokens. Optionally you can now use environment variables to override values per execution or per environment. ```bash # override `port` from settings.toml file and automatically casts as `int` value. export DYNACONF_PORT=9900 ``` On your code import the `settings` object ```py from path.to.project.config import settings # Reading the settings settings.username == "admin" # dot notation with multi nesting support settings.PORT == 9900 # case insensitive settings['password'] == "secret123" # dict like access settings.get("nonexisting", "default value") # Default values just like a dict settings.databases.name == "mydb" # Nested key traversing settings['databases.schema'] == "main" # Nested key traversing ``` ## More - Settings Schema Validation - Custom Settings Loaders - Vault Services - Template substitutions - etc... 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) ## more If you are looking for something similar to Dynaconf to use in your Rust projects: https://github.com/rubik/hydroconf ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1631217935.113678 dynaconf-3.1.7/dynaconf/0000755000175000017500000000000000000000000016521 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631217934.0 dynaconf-3.1.7/dynaconf/VERSION0000644000175000017500000000000600000000000017565 0ustar00rochacbrunorochacbruno3.1.7 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629424230.0 dynaconf-3.1.7/dynaconf/__init__.py0000644000175000017500000000151100000000000020630 0ustar00rochacbrunorochacbrunofrom dynaconf.base import LazySettings # noqa from dynaconf.constants import DEFAULT_SETTINGS_FILES from dynaconf.contrib import DjangoDynaconf # noqa from dynaconf.contrib import FlaskDynaconf # noqa from dynaconf.validator import ValidationError # noqa from dynaconf.validator import Validator # noqa settings = LazySettings( # This global `settings` is deprecated from v3.0.0+ # kept here for backwards compatibility # To Be Removed in 4.0.x warn_dynaconf_global_settings=True, environments=True, lowercase_read=False, load_dotenv=True, default_settings_paths=DEFAULT_SETTINGS_FILES, ) # This is the new recommended base class alias Dynaconf = LazySettings # noqa __all__ = [ "Dynaconf", "LazySettings", "Validator", "FlaskDynaconf", "ValidationError", "DjangoDynaconf", ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631213309.0 dynaconf-3.1.7/dynaconf/base.py0000644000175000017500000012214100000000000020006 0ustar00rochacbrunorochacbrunoimport copy import glob import importlib import inspect import os import warnings from collections import defaultdict from contextlib import contextmanager from contextlib import suppress from pathlib import Path from dynaconf import default_settings from dynaconf.loaders import default_loader from dynaconf.loaders import enable_external_loaders from dynaconf.loaders import env_loader from dynaconf.loaders import execute_hooks from dynaconf.loaders import py_loader from dynaconf.loaders import settings_loader from dynaconf.loaders import yaml_loader from dynaconf.utils import BANNER from dynaconf.utils import compat_kwargs from dynaconf.utils import ensure_a_list from dynaconf.utils import missing from dynaconf.utils import object_merge from dynaconf.utils import recursively_evaluate_lazy_format from dynaconf.utils import RENAMED_VARS from dynaconf.utils import upperfy from dynaconf.utils.boxing import DynaBox from dynaconf.utils.files import find_file from dynaconf.utils.functional import empty from dynaconf.utils.functional import LazyObject from dynaconf.utils.parse_conf import converters from dynaconf.utils.parse_conf import get_converter from dynaconf.utils.parse_conf import parse_conf_data from dynaconf.utils.parse_conf import true_values from dynaconf.validator import ValidatorList from dynaconf.vendor.box.box_list import BoxList class LazySettings(LazyObject): """Loads settings lazily from multiple sources:: settings = Dynaconf( settings_files=["settings.toml"], # path/glob environments=True, # activate layered environments envvar_prefix="MYAPP", # `export MYAPP_FOO=bar` env_switcher="MYAPP_MODE", # `export MYAPP_MODE=production` load_dotenv=True, # read a .env file ) More options available on https://www.dynaconf.com/configuration/ """ def __init__(self, wrapped=None, **kwargs): """ handle initialization for the customization cases :param wrapped: a deepcopy of this object will be wrapped (issue #596) :param kwargs: values that overrides default_settings """ self._warn_dynaconf_global_settings = kwargs.pop( "warn_dynaconf_global_settings", None ) # in 3.0.0 global settings is deprecated self.__resolve_config_aliases(kwargs) compat_kwargs(kwargs) self._kwargs = kwargs super(LazySettings, self).__init__() if wrapped: if self._django_override: # This fixes django issue #596 self._wrapped = copy.deepcopy(wrapped) else: self._wrapped = wrapped def __resolve_config_aliases(self, kwargs): """takes aliases for _FOR_DYNACONF configurations e.g: ROOT_PATH='/' is transformed into `ROOT_PATH_FOR_DYNACONF` """ mispells = { "settings_files": "settings_file", "SETTINGS_FILES": "SETTINGS_FILE", "environment": "environments", "ENVIRONMENT": "ENVIRONMENTS", } for mispell, correct in mispells.items(): if mispell in kwargs: kwargs[correct] = kwargs.pop(mispell) for_dynaconf_keys = { key for key in UPPER_DEFAULT_SETTINGS if key.endswith("_FOR_DYNACONF") } aliases = { key.upper() for key in kwargs if f"{key.upper()}_FOR_DYNACONF" in for_dynaconf_keys } for alias in aliases: value = kwargs.pop(alias, empty) if value is empty: value = kwargs.pop(alias.lower()) kwargs[f"{alias}_FOR_DYNACONF"] = value def __getattr__(self, name): """Allow getting keys from self.store using dot notation""" if self._wrapped is empty: self._setup() if name in self._wrapped._deleted: # noqa raise AttributeError( f"Attribute {name} was deleted, " "or belongs to different env" ) if name not in RESERVED_ATTRS: lowercase_mode = self._kwargs.get( "LOWERCASE_READ_FOR_DYNACONF", default_settings.LOWERCASE_READ_FOR_DYNACONF, ) if lowercase_mode is True: name = name.upper() if ( name.isupper() and ( self._wrapped._fresh or name in self._wrapped.FRESH_VARS_FOR_DYNACONF ) and name not in UPPER_DEFAULT_SETTINGS ): return self._wrapped.get_fresh(name) value = getattr(self._wrapped, name) if name not in RESERVED_ATTRS: return recursively_evaluate_lazy_format(value, self) return value def __call__(self, *args, **kwargs): """Allow direct call of settings('val') in place of settings.get('val') """ return self.get(*args, **kwargs) def _setup(self): """Initial setup, run once.""" if self._warn_dynaconf_global_settings: warnings.warn( "Usage of `from dynaconf import settings` is now " "DEPRECATED in 3.0.0+. You are encouraged to change it to " "your own instance e.g: `settings = Dynaconf(*options)`", DeprecationWarning, ) default_settings.reload(self._kwargs.get("load_dotenv")) environment_variable = self._kwargs.get( "ENVVAR_FOR_DYNACONF", default_settings.ENVVAR_FOR_DYNACONF ) settings_module = os.environ.get(environment_variable) self._wrapped = Settings( settings_module=settings_module, **self._kwargs ) def configure(self, settings_module=None, **kwargs): """ Allows user to reconfigure settings object passing a new settings module or separated kwargs :param settings_module: defines the setttings file :param kwargs: override default settings """ default_settings.reload(self._kwargs.get("load_dotenv")) environment_var = self._kwargs.get( "ENVVAR_FOR_DYNACONF", default_settings.ENVVAR_FOR_DYNACONF ) settings_module = settings_module or os.environ.get(environment_var) compat_kwargs(kwargs) kwargs.update(self._kwargs) self._wrapped = Settings(settings_module=settings_module, **kwargs) @property def configured(self): """If wrapped is configured""" return self._wrapped is not empty class Settings: """ Common logic for settings whether set by a module or by the user. """ dynaconf_banner = BANNER _store = DynaBox() def __init__(self, settings_module=None, **kwargs): # pragma: no cover """Execute loaders and custom initialization :param settings_module: defines the setttings file :param kwargs: override default settings """ self._fresh = False self._loaded_envs = [] self._loaded_hooks = defaultdict(dict) self._loaded_py_modules = [] self._loaded_files = [] self._deleted = set() self._store = DynaBox(box_settings=self) self._env_cache = {} self._loaded_by_loaders = {} self._loaders = [] self._defaults = DynaBox(box_settings=self) self.environ = os.environ self.SETTINGS_MODULE = None self.filter_strategy = kwargs.get("filter_strategy", None) self._not_installed_warnings = [] self._validate_only = kwargs.pop("validate_only", None) self._validate_exclude = kwargs.pop("validate_exclude", None) self.validators = ValidatorList( self, validators=kwargs.pop("validators", None) ) compat_kwargs(kwargs) if settings_module: self.set("SETTINGS_FILE_FOR_DYNACONF", settings_module) for key, value in kwargs.items(): 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 ) def __call__(self, *args, **kwargs): """Allow direct call of `settings('val')` in place of `settings.get('val')` """ return self.get(*args, **kwargs) def __setattr__(self, name, value): """Allow `settings.FOO = 'value'` while keeping internal attrs.""" if name in RESERVED_ATTRS: super(Settings, self).__setattr__(name, value) else: self.set(name, value) def __delattr__(self, name): """stores reference in `_deleted` for proper error management""" self._deleted.add(name) if hasattr(self, name): super(Settings, self).__delattr__(name) def __contains__(self, item): """Respond to `item in settings`""" return item.upper() in self.store or item.lower() in self.store def __getattribute__(self, name): if name not in RESERVED_ATTRS and name not in UPPER_DEFAULT_SETTINGS: with suppress(KeyError): # self._store has Lazy values already evaluated if ( name.islower() and self._store.get("LOWERCASE_READ_FOR_DYNACONF", empty) is False ): # only matches exact casing, first levels always upper return self._store.to_dict()[name] # perform lookups for upper, and casefold return self._store[name] # in case of RESERVED_ATTRS or KeyError above, keep default behaviour return super().__getattribute__(name) def __getitem__(self, item): """Allow getting variables as dict keys `settings['KEY']`""" value = self.get(item, default=empty) if value is empty: raise KeyError(f"{item} does not exist") return value def __setitem__(self, key, value): """Allow `settings['KEY'] = 'value'`""" self.set(key, value) @property def store(self): """Gets internal storage""" return self._store def __dir__(self): """Enable auto-complete for code editors""" return ( RESERVED_ATTRS + [k.lower() for k in self.keys()] + list(self.keys()) ) def __iter__(self): """Redirects to store object""" yield from self._store def items(self): """Redirects to store object""" return self._store.items() def keys(self): """Redirects to store object""" return self.store.keys() def values(self): """Redirects to store object""" return self.store.values() def setdefault(self, item, default): """Returns value if exists or set it as the given default""" value = self.get(item, empty) if value is empty and default is not empty: self.set( item, default, loader_identifier="setdefault", tomlfy=True, dotted_lookup=True, ) return default return value def as_dict(self, env=None, internal=False): """Returns a dictionary with set key and values. :param env: Str env name, default self.current_env `DEVELOPMENT` :param internal: bool - should include dynaconf internal vars? """ ctx_mgr = suppress() if env is None else self.using_env(env) with ctx_mgr: data = self.store.to_dict().copy() # if not internal remove internal settings if not internal: for name in UPPER_DEFAULT_SETTINGS: data.pop(name, None) return data to_dict = as_dict # backwards compatibility def _dotted_get( self, dotted_key, default=None, parent=None, cast=None, **kwargs ): """ Perform dotted key lookups and keep track of where we are. :param key: The name of the setting value, will always be upper case :param default: In case of not found it will be returned :param parent: Is there a pre-loaded parent in a nested data? """ split_key = dotted_key.split(".") name, keys = split_key[0], split_key[1:] result = self.get(name, default=default, parent=parent, **kwargs) # If we've reached the end, or parent key not found, then return result if not keys or result == default: if cast and cast in converters: return get_converter(cast, result, box_settings=self) elif cast is True: return parse_conf_data(result, tomlfy=True, box_settings=self) return result # If we've still got key elements to traverse, let's do that. return self._dotted_get( ".".join(keys), default=default, parent=result, cast=cast, **kwargs ) def get( self, key, default=None, cast=None, fresh=False, dotted_lookup=True, parent=None, ): """ Get a value from settings store, this is the prefered way to access:: >>> from dynaconf import settings >>> settings.get('KEY') :param key: The name of the setting value, will always be upper case :param default: In case of not found it will be returned :param cast: Should cast in to @int, @float, @bool or @json ? :param fresh: Should reload from loaders store before access? :param dotted_lookup: Should perform dotted-path lookup? :param parent: Is there a pre-loaded parent in a nested data? :return: The value if found, default or None """ nested_sep = self._store.get("NESTED_SEPARATOR_FOR_DYNACONF") if nested_sep and nested_sep in key: # turn FOO__bar__ZAZ in `FOO.bar.ZAZ` key = key.replace(nested_sep, ".") if "." in key and dotted_lookup: return self._dotted_get( dotted_key=key, default=default, cast=cast, fresh=fresh, parent=parent, ) if default is not None: # default values should behave exactly Dynaconf parsed values if isinstance(default, list): default = BoxList(default) elif isinstance(default, dict): default = DynaBox(default) key = upperfy(key) if key in self._deleted: return default if ( fresh or self._fresh or key in getattr(self, "FRESH_VARS_FOR_DYNACONF", ()) ) and key not in UPPER_DEFAULT_SETTINGS: self.unset(key) self.execute_loaders(key=key) data = (parent or self.store).get(key, default) if cast: data = get_converter(cast, data, box_settings=self) return data def exists(self, key, fresh=False): """Check if key exists :param key: the name of setting variable :param fresh: if key should be taken from source direclty :return: Boolean """ key = upperfy(key) if key in self._deleted: return False return self.get(key, fresh=fresh, default=missing) is not missing def get_fresh(self, key, default=None, cast=None): """This is a shortcut to `get(key, fresh=True)`. always reload from loaders store before getting the var. :param key: The name of the setting value, will always be upper case :param default: In case of not found it will be returned :param cast: Should cast in to @int, @float, @bool or @json ? :return: The value if found, default or None """ return self.get(key, default=default, cast=cast, fresh=True) def get_environ(self, key, default=None, cast=None): """Get value from environment variable using os.environ.get :param key: The name of the setting value, will always be upper case :param default: In case of not found it will be returned :param cast: Should cast in to @int, @float, @bool or @json ? or cast must be true to use cast inference :return: The value if found, default or None """ key = upperfy(key) data = self.environ.get(key, default) if data: if cast in converters: data = get_converter(cast, data, box_settings=self) elif cast is True: data = parse_conf_data(data, tomlfy=True, box_settings=self) return data def exists_in_environ(self, key): """Return True if env variable is exported""" return upperfy(key) in self.environ def as_bool(self, key): """Partial method for get with bool cast""" return self.get(key, cast="@bool") def as_int(self, key): """Partial method for get with int cast""" return self.get(key, cast="@int") def as_float(self, key): """Partial method for get with float cast""" return self.get(key, cast="@float") def as_json(self, key): """Partial method for get with json cast""" return self.get(key, cast="@json") @property def loaded_envs(self): """Get or create internal loaded envs list""" if not self._loaded_envs: self._loaded_envs = [] return self._loaded_envs @loaded_envs.setter def loaded_envs(self, value): """Setter for env list""" self._loaded_envs = value # compat loaded_namespaces = loaded_envs @property def loaded_by_loaders(self): """Gets the internal mapping of LOADER -> values""" return self._loaded_by_loaders def from_env(self, env="", keep=False, **kwargs): """Return a new isolated settings object pointing to specified env. Example of settings.toml:: [development] message = 'This is in dev' [other] message = 'this is in other env' Program:: >>> from dynaconf import settings >>> print(settings.MESSAGE) 'This is in dev' >>> print(settings.from_env('other').MESSAGE) 'This is in other env' # The existing settings object remains the same. >>> print(settings.MESSAGE) 'This is in dev' Arguments: env {str} -- Env to load (development, production, custom) Keyword Arguments: keep {bool} -- Keep pre-existing values (default: {False}) kwargs {dict} -- Passed directly to new instance. """ cache_key = f"{env}_{keep}_{kwargs}" if cache_key in self._env_cache: return self._env_cache[cache_key] new_data = { key: self.get(key) for key in UPPER_DEFAULT_SETTINGS if key not in RENAMED_VARS } if self.filter_strategy: # Retain the filtering strategy when switching environments new_data["filter_strategy"] = self.filter_strategy # This is here for backwards compatibility # To be removed on 4.x.x default_settings_paths = self.get("default_settings_paths") if default_settings_paths: # pragma: no cover new_data["default_settings_paths"] = default_settings_paths if keep: # keep existing values from current env new_data.update( { key: value for key, value in self.store.to_dict().copy().items() if key.isupper() and key not in RENAMED_VARS } ) new_data.update(kwargs) new_data["FORCE_ENV_FOR_DYNACONF"] = env new_settings = LazySettings(**new_data) self._env_cache[cache_key] = new_settings return new_settings @contextmanager def using_env(self, env, clean=True, silent=True, filename=None): """ This context manager allows the contextual use of a different env Example of settings.toml:: [development] message = 'This is in dev' [other] message = 'this is in other env' Program:: >>> from dynaconf import settings >>> print settings.MESSAGE 'This is in dev' >>> with settings.using_env('OTHER'): ... print settings.MESSAGE 'this is in other env' :param env: Upper case name of env without any _ :param clean: If preloaded vars should be cleaned :param silent: Silence errors :param filename: Custom filename to load (optional) :return: context """ try: self.setenv(env, clean=clean, silent=silent, filename=filename) yield finally: if env.lower() != self.ENV_FOR_DYNACONF.lower(): del self.loaded_envs[-1] self.setenv(self.current_env, clean=clean, filename=filename) # compat using_namespace = using_env @contextmanager def fresh(self): """ this context manager force the load of a key direct from the store:: $ export DYNACONF_VALUE='Original' >>> from dynaconf import settings >>> print settings.VALUE 'Original' $ export DYNACONF_VALUE='Changed Value' >>> print settings.VALUE # will not be reloaded from env vars 'Original >>> with settings.fresh(): # inside this context all is reloaded ... print settings.VALUE 'Changed Value' an alternative is using `settings.get_fresh(key)` :return: context """ self._fresh = True yield self._fresh = False @property def current_env(self): """Return the current active env""" if self.ENVIRONMENTS_FOR_DYNACONF is False: return "main" if self.FORCE_ENV_FOR_DYNACONF is not None: return self.FORCE_ENV_FOR_DYNACONF try: return self.loaded_envs[-1] except IndexError: return self.ENV_FOR_DYNACONF # compat current_namespace = current_env @property def settings_module(self): """Gets SETTINGS_MODULE variable""" settings_module = parse_conf_data( os.environ.get( self.ENVVAR_FOR_DYNACONF, self.SETTINGS_FILE_FOR_DYNACONF ), tomlfy=True, box_settings=self, ) if settings_module != getattr(self, "SETTINGS_MODULE", None): self.set("SETTINGS_MODULE", settings_module) # This is for backewards compatibility, to be removed on 4.x.x if not self.SETTINGS_MODULE and self.get("default_settings_paths"): self.SETTINGS_MODULE = self.get("default_settings_paths") return self.SETTINGS_MODULE # Backwards compatibility see #169 settings_file = settings_module def setenv(self, env=None, clean=True, silent=True, filename=None): """Used to interactively change the env Example of settings.toml:: [development] message = 'This is in dev' [other] message = 'this is in other env' Program:: >>> from dynaconf import settings >>> print settings.MESSAGE 'This is in dev' >>> with settings.using_env('OTHER'): ... print settings.MESSAGE 'this is in other env' :param env: Upper case name of env without any _ :param clean: If preloaded vars should be cleaned :param silent: Silence errors :param filename: Custom filename to load (optional) :return: context """ env = env or self.ENV_FOR_DYNACONF if not isinstance(env, str): raise AttributeError("env should be a string") env = env.upper() if env != self.ENV_FOR_DYNACONF: self.loaded_envs.append(env) else: self.loaded_envs = [] if clean: self.clean(env=env) self.execute_loaders(env=env, silent=silent, filename=filename) # compat namespace = setenv def clean(self, *args, **kwargs): """Clean all loaded values to reload when switching envs""" for key in list(self.store.keys()): self.unset(key) def unset(self, key, force=False): """Unset on all references :param key: The key to be unset :param force: Bypass default checks and force unset """ key = upperfy(key.strip()) if ( key not in UPPER_DEFAULT_SETTINGS and key not in self._defaults or force ): with suppress(KeyError, AttributeError): # AttributeError can happen when a LazyValue consumes # a previously deleted key delattr(self, key) del self.store[key] def unset_all(self, keys, force=False): # pragma: no cover """Unset based on a list of keys :param keys: a list of keys :param force: Bypass default checks and force unset """ for key in keys: self.unset(key, force=force) def _dotted_set(self, dotted_key, value, tomlfy=False, **kwargs): """Sets dotted keys as nested dictionaries. Dotted set will always reassign the value, to merge use `@merge` token Arguments: dotted_key {str} -- A traversal name e.g: foo.bar.zaz value {Any} -- The value to set to the nested value. Keyword Arguments: tomlfy {bool} -- Perform toml parsing (default: {False}) """ split_keys = dotted_key.split(".") existing_data = self.get(split_keys[0], {}) new_data = tree = DynaBox(box_settings=self) for k in split_keys[:-1]: tree = tree.setdefault(k, {}) value = parse_conf_data(value, tomlfy=tomlfy, box_settings=self) tree[split_keys[-1]] = value if existing_data: new_data = object_merge( old=DynaBox({split_keys[0]: existing_data}), new=new_data, full_path=split_keys, ) self.update(data=new_data, tomlfy=tomlfy, **kwargs) def set( self, key, value, loader_identifier=None, tomlfy=False, dotted_lookup=True, is_secret="DeprecatedArgument", # noqa merge=False, ): """Set a value storing references for the loader :param key: The key to store :param value: The value to store :param loader_identifier: Optional loader name e.g: toml, yaml etc. :param tomlfy: Bool define if value is parsed by toml (defaults False) :param merge: Bool define if existing nested data will be merged. """ nested_sep = self.get("NESTED_SEPARATOR_FOR_DYNACONF") if nested_sep and nested_sep in key: # turn FOO__bar__ZAZ in `FOO.bar.ZAZ` key = key.replace(nested_sep, ".") if "." in key and dotted_lookup is True: return self._dotted_set( key, value, loader_identifier=loader_identifier, tomlfy=tomlfy ) value = parse_conf_data(value, tomlfy=tomlfy, box_settings=self) key = upperfy(key.strip()) existing = getattr(self, key, None) if getattr(value, "_dynaconf_del", None): # just in case someone use a `@del` in a first level var. self.unset(key, force=True) return 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", False): # just in case someone use a `@merge` in a first level var if existing: value = object_merge(existing, value.unwrap()) else: value = value.unwrap() if existing is not None and existing != value: # `dynaconf_merge` used in file root `merge=True` if merge: value = object_merge(existing, value) else: # `dynaconf_merge` may be used within the key structure value = self._merge_before_set(existing, value) if isinstance(value, dict): value = DynaBox(value, box_settings=self) self.store[key] = value self._deleted.discard(key) super(Settings, self).__setattr__(key, value) # set loader identifiers so cleaners know which keys to clean if loader_identifier and loader_identifier in self.loaded_by_loaders: self.loaded_by_loaders[loader_identifier][key] = value elif loader_identifier: self.loaded_by_loaders[loader_identifier] = {key: value} elif loader_identifier is None: # if .set is called without loader identifier it becomes # a default value and goes away only when explicitly unset self._defaults[key] = value def update( self, data=None, loader_identifier=None, tomlfy=False, merge=False, is_secret="DeprecatedArgument", # noqa **kwargs, ): """ Update values in the current settings object without saving in stores:: >>> from dynaconf import settings >>> print settings.NAME 'Bruno' >>> settings.update({'NAME': 'John'}, other_value=1) >>> print settings.NAME 'John' >>> print settings.OTHER_VALUE 1 :param data: Data to be updated :param loader_identifier: Only to be used by custom loaders :param tomlfy: Bool define if value is parsed by toml (defaults False) :param merge: Bool define if existing nested data will be merged. :param kwargs: extra values to update :return: None """ data = data or {} data.update(kwargs) for key, value in data.items(): self.set( key, value, loader_identifier=loader_identifier, tomlfy=tomlfy, merge=merge, ) def _merge_before_set(self, existing, value): """Merge the new value being set with the existing value before set""" global_merge = getattr(self, "MERGE_ENABLED_FOR_DYNACONF", False) if isinstance(value, dict): local_merge = value.pop( "dynaconf_merge", value.pop("dynaconf_merge_unique", None) ) if local_merge not in (True, False, None) and not value: # In case `dynaconf_merge:` holds value not boolean - ref #241 value = local_merge if global_merge or local_merge: value = object_merge(existing, value) if isinstance(value, (list, tuple)): local_merge = ( "dynaconf_merge" in value or "dynaconf_merge_unique" in value ) if global_merge or local_merge: value = list(value) unique = False if local_merge: try: value.remove("dynaconf_merge") except ValueError: # EAFP value.remove("dynaconf_merge_unique") unique = True value = object_merge(existing, value, unique=unique) return value @property def loaders(self): # pragma: no cover """Return available loaders""" if self.LOADERS_FOR_DYNACONF in (None, 0, "0", "false", False): return [] if not self._loaders: self._loaders = self.LOADERS_FOR_DYNACONF return [importlib.import_module(loader) for loader in self._loaders] def reload(self, env=None, silent=None): # pragma: no cover """Clean end Execute all loaders""" self.clean() self.execute_loaders(env, silent) def execute_loaders( self, env=None, silent=None, key=None, filename=None, loaders=None ): """Execute all internal and registered loaders :param env: The environment to load :param silent: If loading erros is silenced :param key: if provided load a single key :param filename: optional custom filename to load :param loaders: optional list of loader modules """ if key is None: default_loader(self, self._defaults) env = (env or self.current_env).upper() silent = silent or self.SILENT_ERRORS_FOR_DYNACONF if loaders is None: self.pre_load(env, silent=silent, key=key) settings_loader( self, env=env, silent=silent, key=key, filename=filename ) self.load_extra_yaml(env, silent, key) # DEPRECATED enable_external_loaders(self) loaders = self.loaders for loader in loaders: 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) def pre_load(self, env, silent, key): """Do we have any file to pre-load before main settings file?""" preloads = self.get("PRELOAD_FOR_DYNACONF", []) if preloads: self.load_file(path=preloads, env=env, silent=silent, key=key) def load_includes(self, env, silent, key): """Do we have any nested includes we need to process?""" includes = self.get("DYNACONF_INCLUDE", []) includes.extend(ensure_a_list(self.get("INCLUDES_FOR_DYNACONF"))) if includes: self.load_file(path=includes, env=env, silent=silent, key=key) # ensure env vars are the last thing loaded after all includes last_loader = self.loaders and self.loaders[-1] if last_loader and last_loader == env_loader: last_loader.load(self, env, silent, key) def load_file(self, path=None, env=None, silent=True, key=None): """Programmatically load files from ``path``. :param path: A single filename or a file list :param env: Which env to load from file (default current_env) :param silent: Should raise errors? :param key: Load a single key? """ env = (env or self.current_env).upper() files = ensure_a_list(path) if files: already_loaded = set() for _filename in files: if py_loader.try_to_load_from_py_module_name( obj=self, name=_filename, silent=True ): # if it was possible to load from module name # continue the loop. continue # python 3.6 does not resolve Pathlib basedirs # issue #494 root_dir = str(self._root_path or os.getcwd()) 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) ) paths = [ p for p in sorted(glob.glob(filepath)) if ".local." not in p ] 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 continue settings_loader( obj=self, env=env, silent=silent, key=key, filename=path, ) already_loaded.add(path) @property def _root_path(self): """ROOT_PATH_FOR_DYNACONF or the path of first loaded file or '.'""" if self.ROOT_PATH_FOR_DYNACONF is not None: return self.ROOT_PATH_FOR_DYNACONF if self._loaded_files: # called once root_path = os.path.dirname(self._loaded_files[0]) self.set("ROOT_PATH_FOR_DYNACONF", root_path) return root_path def load_extra_yaml(self, env, silent, key): """This is deprecated, kept for compat .. deprecated:: 1.0.0 Use multiple settings or INCLUDES_FOR_DYNACONF files instead. """ if self.get("YAML") is not None: warnings.warn( "The use of YAML var is deprecated, please define multiple " "filepaths instead: " "e.g: SETTINGS_FILE_FOR_DYNACONF = " "'settings.py,settings.yaml,settings.toml' or " "INCLUDES_FOR_DYNACONF=['path.toml', 'folder/*']" ) yaml_loader.load( self, env=env, filename=self.find_file(self.get("YAML")), silent=silent, key=key, ) def path_for(self, *args): """Path containing _root_path""" if args and args[0].startswith(os.path.sep): return os.path.join(*args) return os.path.join(self._root_path or os.getcwd(), *args) def find_file(self, *args, **kwargs): kwargs.setdefault("project_root", self._root_path) kwargs.setdefault( "skip_files", self.get("SKIP_FILES_FOR_DYNACONF", []) ) return find_file(*args, **kwargs) def flag(self, key, env=None): """Feature flagging system write flags to redis $ dynaconf write redis -s DASHBOARD=1 -e premiumuser meaning: Any premium user has DASHBOARD feature enabled In your program do:: # premium user has access to dashboard? >>> if settings.flag('dashboard', 'premiumuser'): ... activate_dashboard() The value is ensured to be loaded fresh from redis server It also works with file settings but the recommended is redis as the data can be loaded once it is updated. :param key: The flag name :param env: The env to look for """ env = env or self.ENVVAR_PREFIX_FOR_DYNACONF or "DYNACONF" with self.using_env(env): value = self.get_fresh(key) return value is True or value in true_values def populate_obj(self, obj, keys=None, ignore=None): """Given the `obj` populate it using self.store items. :param obj: An object to be populated, a class instance. :param keys: A list of keys to be included. :param ignore: A list of keys to be excluded. """ keys = keys or self.keys() for key in keys: key = upperfy(key) if ignore and key in ignore: continue value = self.get(key, empty) if value is not empty: setattr(obj, key, value) def dynaconf_clone(self): """Clone the current settings object.""" return copy.deepcopy(self) @property def dynaconf(self): """A proxy to access internal methods and attributes Starting in 3.0.0 Dynaconf now allows first level lower case keys that are not reserved keyword, so this is a proxy to internal methods and attrs. """ class AttrProxy(object): def __init__(self, obj): self.obj = obj def __getattr__(self, name): return getattr(self.obj, f"dynaconf_{name}") return AttrProxy(self) @property def logger(self): # pragma: no cover """backwards compatibility with pre 3.0 loaders In dynaconf 3.0.0 logger and debug messages has been removed. """ warnings.warn( "logger and DEBUG messages has been removed on dynaconf 3.0.0" ) import logging # noqa return logging.getLogger("dynaconf") def is_overridden(self, setting): # noqa """This is to provide Django DJDT support: issue 382""" return False """Upper case default settings""" UPPER_DEFAULT_SETTINGS = [k for k in dir(default_settings) if k.isupper()] """Attributes created on Settings before 3.0.0""" RESERVED_ATTRS = ( [ item[0] for item in inspect.getmembers(LazySettings) if not item[0].startswith("__") ] + [ item[0] for item in inspect.getmembers(Settings) if not item[0].startswith("__") ] + [ "_defaults", "_deleted", "_env_cache", "_fresh", "_kwargs", "_loaded_by_loaders", "_loaded_envs", "_loaded_hooks", "_loaded_py_modules", "_loaded_files", "_loaders", "_not_installed_warnings", "_store", "_warn_dynaconf_global_settings", "environ", "SETTINGS_MODULE", "filter_strategy", "validators", "_validate_only", "_validate_exclude", ] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807352.0 dynaconf-3.1.7/dynaconf/cli.py0000644000175000017500000005123100000000000017644 0ustar00rochacbrunorochacbrunoimport importlib import io import os import pprint import sys import warnings import webbrowser from contextlib import suppress from pathlib import Path from dynaconf import constants from dynaconf import default_settings from dynaconf import LazySettings from dynaconf import loaders from dynaconf import settings as legacy_settings from dynaconf.loaders.py_loader import get_module 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.validator import ValidationError from dynaconf.validator import Validator from dynaconf.vendor import click from dynaconf.vendor import toml CWD = Path.cwd() EXTS = ["ini", "toml", "yaml", "json", "py", "env"] WRITERS = ["ini", "toml", "yaml", "json", "py", "redis", "vault", "env"] ENC = default_settings.ENCODING_FOR_DYNACONF def set_settings(ctx, instance=None): """Pick correct settings instance and set it to a global variable.""" global settings settings = None if instance is not None: if ctx.invoked_subcommand in ["init"]: raise click.UsageError( "-i/--instance option is not allowed for `init` command" ) sys.path.insert(0, ".") settings = import_settings(instance) elif "FLASK_APP" in os.environ: # pragma: no cover with suppress(ImportError, click.UsageError): from flask.cli import ScriptInfo # noqa flask_app = ScriptInfo().load_app() settings = flask_app.config click.echo( click.style( "Flask app detected", fg="white", bg="bright_black" ) ) elif "DJANGO_SETTINGS_MODULE" in os.environ: # pragma: no cover sys.path.insert(0, os.path.abspath(os.getcwd())) try: # Django extension v2 from django.conf import settings # noqa settings.DYNACONF.configure() except AttributeError: settings = LazySettings() if settings is not None: click.echo( click.style( "Django app detected", fg="white", bg="bright_black" ) ) if settings is None: if instance is None and "--help" not in click.get_os_args(): if ctx.invoked_subcommand and ctx.invoked_subcommand not in [ "init", ]: warnings.warn( "Starting on 3.x the param --instance/-i is now required. " "try passing it `dynaconf -i path.to.settings ` " "Example `dynaconf -i config.settings list` " ) settings = legacy_settings else: settings = LazySettings(create_new_settings=True) else: settings = LazySettings() def import_settings(dotted_path): """Import settings instance from python dotted path. Last item in dotted path must be settings instace. Example: import_settings('path.to.settings') """ if "." in dotted_path: module, name = dotted_path.rsplit(".", 1) else: raise click.UsageError( f"invalid path to settings instance: {dotted_path}" ) try: module = importlib.import_module(module) except ImportError as e: raise click.UsageError(e) try: return getattr(module, name) except AttributeError as e: raise click.UsageError(e) def split_vars(_vars): """Splits values like foo=bar=zaz in {'foo': 'bar=zaz'}""" return ( { upperfy(k.strip()): parse_conf_data( v.strip(), tomlfy=True, box_settings=settings ) for k, _, v in [item.partition("=") for item in _vars] } if _vars else {} ) def read_file_in_root_directory(*names, **kwargs): """Read a file on root dir.""" return read_file( os.path.join(os.path.dirname(__file__), *names), encoding=kwargs.get("encoding", "utf-8"), ) def print_version(ctx, param, value): if not value or ctx.resilient_parsing: return click.echo(read_file_in_root_directory("VERSION")) ctx.exit() def open_docs(ctx, param, value): # pragma: no cover if not value or ctx.resilient_parsing: return url = "https://dynaconf.com/" webbrowser.open(url, new=2) click.echo(f"{url} opened in browser") ctx.exit() def show_banner(ctx, param, value): """Shows dynaconf awesome banner""" if not value or ctx.resilient_parsing: return set_settings(ctx) click.echo(settings.dynaconf_banner) click.echo("Learn more at: http://github.com/rochacbruno/dynaconf") ctx.exit() @click.group() @click.option( "--version", is_flag=True, callback=print_version, expose_value=False, is_eager=True, help="Show dynaconf version", ) @click.option( "--docs", is_flag=True, callback=open_docs, expose_value=False, is_eager=True, help="Open documentation in browser", ) @click.option( "--banner", is_flag=True, callback=show_banner, expose_value=False, is_eager=True, help="Show awesome banner", ) @click.option( "--instance", "-i", default=None, envvar="INSTANCE_FOR_DYNACONF", help="Custom instance of LazySettings", ) @click.pass_context def main(ctx, instance): """Dynaconf - Command Line Interface\n Documentation: https://dynaconf.com/ """ set_settings(ctx, instance) @main.command() @click.option( "--format", "fileformat", "-f", default="toml", type=click.Choice(EXTS) ) @click.option( "--path", "-p", default=CWD, help="defaults to current directory" ) @click.option( "--env", "-e", default=None, help="deprecated command (kept for compatibility but unused)", ) @click.option( "--vars", "_vars", "-v", multiple=True, default=None, help=( "extra values to write to settings file " "e.g: `dynaconf init -v NAME=foo -v X=2`" ), ) @click.option( "--secrets", "_secrets", "-s", multiple=True, default=None, help=( "secret key values to be written in .secrets " "e.g: `dynaconf init -s TOKEN=kdslmflds" ), ) @click.option("--wg/--no-wg", default=True) @click.option("-y", default=False, is_flag=True) @click.option("--django", default=os.environ.get("DJANGO_SETTINGS_MODULE")) @click.pass_context def init(ctx, fileformat, path, env, _vars, _secrets, wg, y, django): """Inits a dynaconf project By default it creates a settings.toml and a .secrets.toml for [default|development|staging|testing|production|global] envs. The format of the files can be changed passing --format=yaml|json|ini|py. This command must run on the project's root folder or you must pass --path=/myproject/root/folder. The --env/-e is deprecated (kept for compatibility but unused) """ click.echo("⚙️ Configuring your Dynaconf environment") click.echo("-" * 42) path = Path(path) if env is not None: click.secho( "⚠️ The --env/-e option is deprecated (kept for\n" " compatibility but unused)\n", fg="red", bold=True, # stderr=True, ) if settings.get("create_new_settings") is True: filename = Path("config.py") if not filename.exists(): with open(filename, "w") as new_settings: new_settings.write( constants.INSTANCE_TEMPLATE.format( settings_files=[ f"settings.{fileformat}", f".secrets.{fileformat}", ] ) ) click.echo( "🐍 The file `config.py` was generated.\n" " on your code now use `from config import settings`.\n" " (you must have `config` importable in your PYTHONPATH).\n" ) else: click.echo( f"⁉️ You already have a {filename} so it is not going to be\n" " generated for you, you will need to create your own \n" " settings instance e.g: config.py \n" " from dynaconf import Dynaconf \n" " settings = Dynaconf(**options)\n" ) sys.path.append(str(path)) set_settings(ctx, "config.settings") env = settings.current_env.lower() loader = importlib.import_module(f"dynaconf.loaders.{fileformat}_loader") # Turn foo=bar=zaz in {'foo': 'bar=zaz'} env_data = split_vars(_vars) _secrets = split_vars(_secrets) # create placeholder data for every env settings_data = {} secrets_data = {} if env_data: settings_data[env] = env_data settings_data["default"] = {k: "a default value" for k in env_data} if _secrets: secrets_data[env] = _secrets secrets_data["default"] = {k: "a default value" for k in _secrets} if str(path).endswith( constants.ALL_EXTENSIONS + ("py",) ): # pragma: no cover # noqa settings_path = path secrets_path = path.parent / f".secrets.{fileformat}" gitignore_path = path.parent / ".gitignore" else: if fileformat == "env": if str(path) in (".env", "./.env"): # pragma: no cover settings_path = path elif str(path).endswith("/.env"): # pragma: no cover settings_path = path elif str(path).endswith(".env"): # pragma: no cover settings_path = path.parent / ".env" else: settings_path = path / ".env" Path.touch(settings_path) secrets_path = None else: settings_path = path / f"settings.{fileformat}" secrets_path = path / f".secrets.{fileformat}" gitignore_path = path / ".gitignore" if fileformat in ["py", "env"] or env == "main": # for Main env, Python and .env formats writes a single env settings_data = settings_data.get(env, {}) secrets_data = secrets_data.get(env, {}) if not y and settings_path and settings_path.exists(): # pragma: no cover click.confirm( f"⁉ {settings_path} exists do you want to overwrite it?", abort=True, ) if not y and secrets_path and secrets_path.exists(): # pragma: no cover click.confirm( f"⁉ {secrets_path} exists do you want to overwrite it?", abort=True, ) if settings_path: loader.write(settings_path, settings_data, merge=True) click.echo( f"🎛️ {settings_path.name} created to hold your settings.\n" ) if secrets_path: loader.write(secrets_path, secrets_data, merge=True) click.echo(f"🔑 {secrets_path.name} created to hold your secrets.\n") 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: f.writelines([comment, ignore_line, "\n"]) else: existing = ( ignore_line in io.open(str(gitignore_path), encoding=ENC).read() ) if not existing: # pragma: no cover with io.open(str(gitignore_path), "a+", encoding=ENC) as f: f.writelines([comment, ignore_line, "\n"]) click.echo( f"🙈 the {secrets_path.name} is also included in `.gitignore` \n" " beware to not push your secrets to a public repo \n" " or use dynaconf builtin support for Vault Servers.\n" ) if django: # pragma: no cover dj_module, _ = get_module({}, django) dj_filename = dj_module.__file__ if Path(dj_filename).exists(): click.confirm( f"⁉ {dj_filename} is found do you want to add dynaconf?", abort=True, ) with open(dj_filename, "a") as dj_file: dj_file.write(constants.DJANGO_PATCH) click.echo("🎠 Now your Django settings are managed by Dynaconf") else: click.echo("❌ Django settings file not written.") else: click.echo( "🎉 Dynaconf is configured! read more on https://dynaconf.com\n" " Use `dynaconf -i config.settings list` to see your settings\n" ) @main.command(name="list") @click.option( "--env", "-e", default=None, help="Filters the env to get the values" ) @click.option("--key", "-k", default=None, help="Filters a single key") @click.option( "--more", "-m", default=None, help="Pagination more|less style", is_flag=True, ) @click.option( "--loader", "-l", default=None, help="a loader identifier to filter e.g: toml|yaml", ) @click.option( "--all", "_all", "-a", default=False, is_flag=True, help="show dynaconf internal settings?", ) @click.option( "--output", "-o", type=click.Path(writable=True, dir_okay=False), default=None, help="Filepath to write the listed values as json", ) @click.option( "--output-flat", "flat", is_flag=True, default=False, help="Output file is flat (do not include [env] name)", ) def _list(env, key, more, loader, _all=False, output=None, flat=False): """Lists all user defined config values and if `--all` is passed it also shows dynaconf internal variables. """ if env: env = env.strip() if key: key = key.strip() if loader: loader = loader.strip() if env: settings.setenv(env) cur_env = settings.current_env.lower() if cur_env == "main": flat = True click.echo( click.style( f"Working in {cur_env} environment ", bold=True, bg="bright_blue", fg="bright_white", ) ) if not loader: data = settings.as_dict(env=env, internal=_all) else: identifier = f"{loader}_{cur_env}" data = settings._loaded_by_loaders.get(identifier, {}) data = data or settings._loaded_by_loaders.get(loader, {}) # remove to avoid displaying twice data.pop("SETTINGS_MODULE", None) def color(_k): if _k in dir(default_settings): return "blue" return "magenta" def format_setting(_k, _v): key = click.style(_k, bg=color(_k), fg="bright_white") data_type = click.style( f"<{type(_v).__name__}>", bg="bright_black", fg="bright_white" ) value = pprint.pformat(_v) return f"{key}{data_type} {value}" if not key: datalines = "\n".join( format_setting(k, v) for k, v in data.items() if k not in data.get("RENAMED_VARS", []) ) (click.echo_via_pager if more else click.echo)(datalines) if output: loaders.write(output, data, env=not flat and cur_env) else: key = upperfy(key) try: value = settings.get(key, empty) except AttributeError: value = empty if value is empty: click.echo(click.style("Key not found", bg="red", fg="white")) return click.echo(format_setting(key, value)) if output: loaders.write(output, {key: value}, env=not flat and cur_env) if env: settings.setenv() @main.command() @click.argument("to", required=True, type=click.Choice(WRITERS)) @click.option( "--vars", "_vars", "-v", multiple=True, default=None, help=( "key values to be written " "e.g: `dynaconf write toml -e NAME=foo -e X=2" ), ) @click.option( "--secrets", "_secrets", "-s", multiple=True, default=None, help=( "secret key values to be written in .secrets " "e.g: `dynaconf write toml -s TOKEN=kdslmflds -s X=2" ), ) @click.option( "--path", "-p", default=CWD, help="defaults to current directory/settings.{ext}", ) @click.option( "--env", "-e", default="default", help=( "env to write to defaults to DEVELOPMENT for files " "for external sources like Redis and Vault " "it will be DYNACONF or the value set in " "$ENVVAR_PREFIX_FOR_DYNACONF" ), ) @click.option("-y", default=False, is_flag=True) def write(to, _vars, _secrets, path, env, y): """Writes data to specific source""" _vars = split_vars(_vars) _secrets = split_vars(_secrets) loader = importlib.import_module(f"dynaconf.loaders.{to}_loader") if to in EXTS: # Lets write to a file path = Path(path) if str(path).endswith(constants.ALL_EXTENSIONS + ("py",)): settings_path = path secrets_path = path.parent / f".secrets.{to}" else: if to == "env": if str(path) in (".env", "./.env"): # pragma: no cover settings_path = path elif str(path).endswith("/.env"): settings_path = path elif str(path).endswith(".env"): settings_path = path.parent / ".env" else: settings_path = path / ".env" Path.touch(settings_path) secrets_path = None _vars.update(_secrets) else: settings_path = path / f"settings.{to}" secrets_path = path / f".secrets.{to}" if ( _vars and not y and settings_path and settings_path.exists() ): # pragma: no cover # noqa click.confirm( f"{settings_path} exists do you want to overwrite it?", abort=True, ) if ( _secrets and not y and secrets_path and secrets_path.exists() ): # pragma: no cover # noqa click.confirm( f"{secrets_path} exists do you want to overwrite it?", abort=True, ) if to not in ["py", "env"]: if _vars: _vars = {env: _vars} if _secrets: _secrets = {env: _secrets} if _vars and settings_path: loader.write(settings_path, _vars, merge=True) click.echo(f"Data successful written to {settings_path}") if _secrets and secrets_path: loader.write(secrets_path, _secrets, merge=True) click.echo(f"Data successful written to {secrets_path}") else: # pragma: no cover # lets write to external source with settings.using_env(env): # make sure we're in the correct environment loader.write(settings, _vars, **_secrets) click.echo(f"Data successful written to {to}") @main.command() @click.option( "--path", "-p", default=CWD, help="defaults to current directory" ) def validate(path): # pragma: no cover """Validates Dynaconf settings based on rules defined in dynaconf_validators.toml""" # reads the 'dynaconf_validators.toml' from path # for each section register the validator for specific env # call validate path = Path(path) if not str(path).endswith(".toml"): path = path / "dynaconf_validators.toml" if not path.exists(): # pragma: no cover # noqa click.echo(click.style(f"{path} not found", fg="white", bg="red")) sys.exit(1) validation_data = toml.load(open(str(path))) success = True for env, name_data in validation_data.items(): for name, data in name_data.items(): if not isinstance(data, dict): # pragma: no cover click.echo( click.style( f"Invalid rule for parameter '{name}'", fg="white", bg="yellow", ) ) else: data.setdefault("env", env) click.echo( click.style( f"Validating '{name}' with '{data}'", fg="white", bg="blue", ) ) try: Validator(name, **data).validate(settings) except ValidationError as e: click.echo( click.style(f"Error: {e}", fg="white", bg="red") ) success = False if success: click.echo(click.style("Validation success!", fg="white", bg="green")) else: click.echo(click.style("Validation error!", fg="white", bg="red")) sys.exit(1) if __name__ == "__main__": # pragma: no cover main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631213309.0 dynaconf-3.1.7/dynaconf/constants.py0000644000175000017500000000234300000000000021111 0ustar00rochacbrunorochacbruno# pragma: no cover INI_EXTENSIONS = (".ini", ".conf", ".properties") TOML_EXTENSIONS = (".toml", ".tml") YAML_EXTENSIONS = (".yaml", ".yml") JSON_EXTENSIONS = (".json",) ALL_EXTENSIONS = ( INI_EXTENSIONS + TOML_EXTENSIONS + YAML_EXTENSIONS + JSON_EXTENSIONS ) # noqa EXTERNAL_LOADERS = { "ENV": "dynaconf.loaders.env_loader", "VAULT": "dynaconf.loaders.vault_loader", "REDIS": "dynaconf.loaders.redis_loader", } 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 import dynaconf # noqa settings = dynaconf.DjangoDynaconf(__name__) # noqa # HERE ENDS DYNACONF EXTENSION LOAD (No more code below this line) """ INSTANCE_TEMPLATE = """ from dynaconf import Dynaconf settings = Dynaconf( envvar_prefix="DYNACONF", settings_files={settings_files}, ) # `envvar_prefix` = export envvars with `export DYNACONF_FOO=bar`. # `settings_files` = Load these files in the order. """ EXTS = ( "py", "toml", "tml", "yaml", "yml", "ini", "conf", "properties", "json", ) DEFAULT_SETTINGS_FILES = [f"settings.{ext}" for ext in EXTS] + [ f".secrets.{ext}" for ext in EXTS ] ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1631217935.113678 dynaconf-3.1.7/dynaconf/contrib/0000755000175000017500000000000000000000000020161 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1590127290.0 dynaconf-3.1.7/dynaconf/contrib/__init__.py0000644000175000017500000000031400000000000022270 0ustar00rochacbrunorochacbrunofrom dynaconf.contrib.django_dynaconf_v2 import DjangoDynaconf # noqa from dynaconf.contrib.flask_dynaconf import DynaconfConfig # noqa from dynaconf.contrib.flask_dynaconf import FlaskDynaconf # noqa ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807352.0 dynaconf-3.1.7/dynaconf/contrib/django_dynaconf_v2.py0000644000175000017500000001011300000000000024261 0ustar00rochacbrunorochacbruno"""Dynaconf django extension In the `django_project/settings.py` put at the very botton 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 import dynaconf # noqa settings = dynaconf.DjangoDynaconf(__name__) # noqa # HERE ENDS DYNACONF EXTENSION LOAD (No more code below this line) Now in the root of your Django project (the same folder where manage.py is located) Put your config files `settings.{py|yaml|toml|ini|json}` and or `.secrets.{py|yaml|toml|ini|json}` On your projects root folder now you can start as:: DJANGO_DEBUG='false' \ DJANGO_ALLOWED_HOSTS='["localhost"]' \ python manage.py runserver """ import inspect import os import sys import dynaconf try: # pragma: no cover from django import conf from django.conf import settings as django_settings django_installed = True except ImportError: # pragma: no cover django_installed = False def load(django_settings_module_name=None, **kwargs): # pragma: no cover if not django_installed: raise RuntimeError( "To use this extension django must be installed " "install it with: pip install django" ) try: django_settings_module = sys.modules[django_settings_module_name] except KeyError: django_settings_module = sys.modules[ os.environ["DJANGO_SETTINGS_MODULE"] ] 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() } options.update(kwargs) options.setdefault( "SKIP_FILES_FOR_DYNACONF", [settings_file, "dynaconf_merge"] ) options.setdefault("ROOT_PATH_FOR_DYNACONF", _root_path) options.setdefault("ENVVAR_PREFIX_FOR_DYNACONF", "DJANGO") options.setdefault("ENV_SWITCHER_FOR_DYNACONF", "DJANGO_ENV") options.setdefault("ENVIRONMENTS_FOR_DYNACONF", True) options.setdefault("load_dotenv", True) options.setdefault( "default_settings_paths", dynaconf.DEFAULT_SETTINGS_FILES ) class UserSettingsHolder(dynaconf.LazySettings): _django_override = True lazy_settings = dynaconf.LazySettings(**options) dynaconf.settings = lazy_settings # rebind the settings # 2) Set all settings back to django_settings_module for 'django check' lazy_settings.populate_obj(django_settings_module) # 3) Bind `settings` and `DYNACONF` setattr(django_settings_module, "settings", lazy_settings) setattr(django_settings_module, "DYNACONF", lazy_settings) # 4) keep django original settings dj = {} for key in dir(django_settings): if ( key.isupper() and (key != "SETTINGS_MODULE") and key not in lazy_settings.store ): dj[key] = getattr(django_settings, key, None) dj["ORIGINAL_SETTINGS_MODULE"] = django_settings.SETTINGS_MODULE lazy_settings.update(dj) # 5) Patch django.conf.settings class Wrapper: # lazy_settings = conf.settings.lazy_settings def __getattribute__(self, name): if name == "settings": return lazy_settings if name == "UserSettingsHolder": return UserSettingsHolder return getattr(conf, name) # This implementation is recommended by Guido Van Rossum # https://mail.python.org/pipermail/python-ideas/2012-May/014969.html sys.modules["django.conf"] = Wrapper() # 6) Enable standalone scripts to use Dynaconf # This is for when `django.conf.settings` is imported directly # on external `scripts` (out of Django's lifetime) for stack_item in reversed(inspect.stack()): if isinstance( stack_item.frame.f_globals.get("settings"), conf.LazySettings ): stack_item.frame.f_globals["settings"] = lazy_settings return lazy_settings # syntax sugar DjangoDynaconf = load # noqa ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629488031.0 dynaconf-3.1.7/dynaconf/contrib/flask_dynaconf.py0000644000175000017500000001644300000000000023524 0ustar00rochacbrunorochacbrunoimport warnings from collections import ChainMap from contextlib import suppress try: from flask.config import Config flask_installed = True except ImportError: # pragma: no cover flask_installed = False Config = object import dynaconf import pkg_resources class FlaskDynaconf: """The arguments are. app = The created app dynaconf_args = Extra args to be passed to Dynaconf (validator for example) All other values are stored as config vars specially:: ENVVAR_PREFIX_FOR_DYNACONF = env prefix for your envvars to be loaded example: if you set to `MYSITE` then export MYSITE_SQL_PORT='@int 5445' with that exported to env you access using: app.config.SQL_PORT app.config.get('SQL_PORT') app.config.get('sql_port') # get is case insensitive app.config['SQL_PORT'] Dynaconf uses `@int, @bool, @float, @json` to cast env vars SETTINGS_FILE_FOR_DYNACONF = The name of the module or file to use as default to load settings. If nothing is passed it will be `settings.*` or value found in `ENVVAR_FOR_DYNACONF` Dynaconf supports .py, .yml, .toml, ini, json ATTENTION: Take a look at `settings.yml` and `.secrets.yml` to know the required settings format. Settings load order in Dynaconf: - Load all defaults and Flask defaults - Load all passed variables when applying FlaskDynaconf - Update with data in settings files - Update with data in environment vars `ENVVAR_FOR_DYNACONF_` TOML files are very useful to have `envd` settings, lets say, `production` and `development`. You can also achieve the same using multiple `.py` files naming as `settings.py`, `production_settings.py` and `development_settings.py` (see examples/validator) Example:: app = Flask(__name__) FlaskDynaconf( app, ENV='MYSITE', SETTINGS_FILE='settings.yml', EXTRA_VALUE='You can add aditional config vars here' ) Take a look at examples/flask in Dynaconf repository """ def __init__( self, app=None, instance_relative_config=False, dynaconf_instance=None, extensions_list=False, **kwargs, ): """kwargs holds initial dynaconf configuration""" if not flask_installed: # pragma: no cover raise RuntimeError( "To use this extension Flask must be installed " "install it with: pip install flask" ) self.kwargs = kwargs kwargs.setdefault("ENVVAR_PREFIX", "FLASK") env_prefix = f"{kwargs['ENVVAR_PREFIX']}_ENV" # FLASK_ENV kwargs.setdefault("ENV_SWITCHER", env_prefix) kwargs.setdefault("ENVIRONMENTS", True) kwargs.setdefault("load_dotenv", True) kwargs.setdefault( "default_settings_paths", dynaconf.DEFAULT_SETTINGS_FILES ) self.dynaconf_instance = dynaconf_instance self.instance_relative_config = instance_relative_config self.extensions_list = extensions_list if app: self.init_app(app, **kwargs) def init_app(self, app, **kwargs): """kwargs holds initial dynaconf configuration""" self.kwargs.update(kwargs) self.settings = self.dynaconf_instance or dynaconf.LazySettings( **self.kwargs ) dynaconf.settings = self.settings # rebind customized settings app.config = self.make_config(app) app.dynaconf = self.settings if self.extensions_list: if not isinstance(self.extensions_list, str): self.extensions_list = "EXTENSIONS" app.config.load_extensions(self.extensions_list) def make_config(self, app): root_path = app.root_path if self.instance_relative_config: # pragma: no cover root_path = app.instance_path if self.dynaconf_instance: self.settings.update(self.kwargs) return DynaconfConfig( root_path=root_path, defaults=app.config, _settings=self.settings, _app=app, ) class DynaconfConfig(Config): """ Replacement for flask.config_class that responds as a Dynaconf instance. """ def __init__(self, _settings, _app, *args, **kwargs): """perform the initial load""" super(DynaconfConfig, self).__init__(*args, **kwargs) # Bring Dynaconf instance value to Flask Config Config.update(self, _settings.store) self._settings = _settings self._app = _app def __contains__(self, item): return hasattr(self, item) def __getitem__(self, key): try: return self._settings[key] except KeyError: return Config.__getitem__(self, key) def __setitem__(self, key, value): """ Allows app.config['key'] = 'foo' """ return self._settings.__setitem__(key, value) def _chain_map(self): return ChainMap(self._settings, dict(dict.items(self))) def keys(self): return self._chain_map().keys() def values(self): return self._chain_map().values() def items(self): return self._chain_map().items() def __iter__(self): return self._chain_map().__iter__() def __getattr__(self, name): """ First try to get value from dynaconf then from Flask Config """ with suppress(AttributeError): return getattr(self._settings, name) with suppress(KeyError): return self[name] raise AttributeError( f"'{self.__class__.__name__}' object has no attribute '{name}'" ) def __call__(self, name, *args, **kwargs): return self.get(name, *args, **kwargs) def get(self, key, default=None): """Gets config from dynaconf variables if variables does not exists in dynaconf try getting from `app.config` to support runtime settings.""" return self._settings.get(key, Config.get(self, key, default)) def load_extensions(self, key="EXTENSIONS", app=None): """Loads flask extensions dynamically.""" app = app or self._app extensions = app.config.get(key) if not extensions: warnings.warn( f"Settings is missing {key} to load Flask Extensions", RuntimeWarning, ) return for object_reference in app.config[key]: # add a placeholder `name` to create a valid entry point entry_point_spec = f"__name = {object_reference}" # parse the entry point specification entry_point = pkg_resources.EntryPoint.parse(entry_point_spec) # dynamically resolve the entry point initializer = entry_point.resolve() # Invoke extension initializer initializer(app) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1606154253.0 dynaconf-3.1.7/dynaconf/default_settings.py0000644000175000017500000002070200000000000022440 0ustar00rochacbrunorochacbrunoimport importlib import os import sys import warnings from dynaconf.utils import RENAMED_VARS from dynaconf.utils import upperfy from dynaconf.utils import warn_deprecations from dynaconf.utils.files import find_file from dynaconf.utils.parse_conf import parse_conf_data from dynaconf.vendor.dotenv import load_dotenv def try_renamed(key, value, older_key, current_key): if value is None: if key == current_key: if older_key in os.environ: warnings.warn( f"{older_key} is deprecated please use {current_key}", DeprecationWarning, ) value = os.environ[older_key] return value def get(key, default=None): value = os.environ.get(upperfy(key)) # compatibility with renamed variables for old, new in RENAMED_VARS.items(): value = try_renamed(key, value, old, new) return ( parse_conf_data(value, tomlfy=True, box_settings={}) if value is not None else default ) def start_dotenv(obj=None, root_path=None): # load_from_dotenv_if_installed obj = obj or {} _find_file = getattr(obj, "find_file", find_file) root_path = ( root_path or getattr(obj, "_root_path", None) or get("ROOT_PATH_FOR_DYNACONF") ) dotenv_path = ( obj.get("DOTENV_PATH_FOR_DYNACONF") or get("DOTENV_PATH_FOR_DYNACONF") or _find_file(".env", project_root=root_path) ) load_dotenv( dotenv_path, verbose=obj.get("DOTENV_VERBOSE_FOR_DYNACONF", False), override=obj.get("DOTENV_OVERRIDE_FOR_DYNACONF", False), ) warn_deprecations(os.environ) def reload(load_dotenv=None, *args, **kwargs): if load_dotenv: start_dotenv(*args, **kwargs) importlib.reload(sys.modules[__name__]) # default proj root # pragma: no cover ROOT_PATH_FOR_DYNACONF = get("ROOT_PATH_FOR_DYNACONF", None) # Default settings file SETTINGS_FILE_FOR_DYNACONF = get("SETTINGS_FILE_FOR_DYNACONF", []) # MISPELLS `FILES` when/if it happens mispelled_files = get("SETTINGS_FILES_FOR_DYNACONF", None) if not SETTINGS_FILE_FOR_DYNACONF and mispelled_files is not None: SETTINGS_FILE_FOR_DYNACONF = mispelled_files # # ENV SETTINGS # # In dynaconf 1.0.0 `NAMESPACE` got renamed to `ENV` # If provided environments will be loaded separatelly ENVIRONMENTS_FOR_DYNACONF = get("ENVIRONMENTS_FOR_DYNACONF", False) # If False dynaconf will allow access to first level settings only in upper LOWERCASE_READ_FOR_DYNACONF = get("LOWERCASE_READ_FOR_DYNACONF", True) # The environment variable to switch current env ENV_SWITCHER_FOR_DYNACONF = get( "ENV_SWITCHER_FOR_DYNACONF", "ENV_FOR_DYNACONF" ) # The current env by default is DEVELOPMENT # to switch is needed to `export ENV_FOR_DYNACONF=PRODUCTION` # or put that value in .env file # this value is used only when reading files like .toml|yaml|ini|json ENV_FOR_DYNACONF = get(ENV_SWITCHER_FOR_DYNACONF, "DEVELOPMENT") # This variable exists to support `from_env` method FORCE_ENV_FOR_DYNACONF = get("FORCE_ENV_FOR_DYNACONF", None) # Default values is taken from DEFAULT pseudo env # this value is used only when reading files like .toml|yaml|ini|json DEFAULT_ENV_FOR_DYNACONF = get("DEFAULT_ENV_FOR_DYNACONF", "DEFAULT") # Global values are taken from DYNACONF env used for exported envvars # Values here overwrites all other envs # This namespace is used for files and also envvars ENVVAR_PREFIX_FOR_DYNACONF = get("ENVVAR_PREFIX_FOR_DYNACONF", "DYNACONF") # By default all environment variables (filtered by `envvar_prefix`) will # be pulled into settings space. In case some of them are polluting the space, # setting this flag to `True` will change this behaviour. # Only "known" variables will be considered -- that is variables defined before # in settings files (or includes/preloads). IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF = get( "IGNORE_UNKNOWN_ENVVARS_FOR_DYNACONF", False ) # 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) # BY default `__` is the separator for nested env vars # export `DYNACONF__DATABASE__server=server.com` # export `DYNACONF__DATABASE__PORT=6666` # Should result in settings.DATABASE == {'server': 'server.com', 'PORT': 6666} # To disable it one can set `NESTED_SEPARATOR_FOR_DYNACONF=false` NESTED_SEPARATOR_FOR_DYNACONF = get("NESTED_SEPARATOR_FOR_DYNACONF", "__") # The env var specifying settings module ENVVAR_FOR_DYNACONF = get("ENVVAR_FOR_DYNACONF", "SETTINGS_FILE_FOR_DYNACONF") # Default values for redis configs default_redis = { "host": get("REDIS_HOST_FOR_DYNACONF", "localhost"), "port": int(get("REDIS_PORT_FOR_DYNACONF", 6379)), "db": int(get("REDIS_DB_FOR_DYNACONF", 0)), "decode_responses": get("REDIS_DECODE_FOR_DYNACONF", True), "username": get("REDIS_USERNAME_FOR_DYNACONF", None), "password": get("REDIS_PASSWORD_FOR_DYNACONF", None), } REDIS_FOR_DYNACONF = get("REDIS_FOR_DYNACONF", default_redis) REDIS_ENABLED_FOR_DYNACONF = get("REDIS_ENABLED_FOR_DYNACONF", False) # Hashicorp Vault Project vault_scheme = get("VAULT_SCHEME_FOR_DYNACONF", "http") vault_host = get("VAULT_HOST_FOR_DYNACONF", "localhost") vault_port = get("VAULT_PORT_FOR_DYNACONF", "8200") default_vault = { "url": get( "VAULT_URL_FOR_DYNACONF", f"{vault_scheme}://{vault_host}:{vault_port}" ), "token": get("VAULT_TOKEN_FOR_DYNACONF", None), "cert": get("VAULT_CERT_FOR_DYNACONF", None), "verify": get("VAULT_VERIFY_FOR_DYNACONF", None), "timeout": get("VAULT_TIMEOUT_FOR_DYNACONF", None), "proxies": get("VAULT_PROXIES_FOR_DYNACONF", None), "allow_redirects": get("VAULT_ALLOW_REDIRECTS_FOR_DYNACONF", None), } VAULT_FOR_DYNACONF = get("VAULT_FOR_DYNACONF", default_vault) VAULT_ENABLED_FOR_DYNACONF = get("VAULT_ENABLED_FOR_DYNACONF", False) VAULT_PATH_FOR_DYNACONF = get("VAULT_PATH_FOR_DYNACONF", "dynaconf") VAULT_MOUNT_POINT_FOR_DYNACONF = get( "VAULT_MOUNT_POINT_FOR_DYNACONF", "secret" ) VAULT_ROOT_TOKEN_FOR_DYNACONF = get("VAULT_ROOT_TOKEN_FOR_DYNACONF", None) VAULT_KV_VERSION_FOR_DYNACONF = get("VAULT_KV_VERSION_FOR_DYNACONF", 1) VAULT_AUTH_WITH_IAM_FOR_DYNACONF = get( "VAULT_AUTH_WITH_IAM_FOR_DYNACONF", False ) VAULT_AUTH_ROLE_FOR_DYNACONF = get("VAULT_AUTH_ROLE_FOR_DYNACONF", None) VAULT_ROLE_ID_FOR_DYNACONF = get("VAULT_ROLE_ID_FOR_DYNACONF", None) VAULT_SECRET_ID_FOR_DYNACONF = get("VAULT_SECRET_ID_FOR_DYNACONF", None) # Only core loaders defined on this list will be invoked core_loaders = ["YAML", "TOML", "INI", "JSON", "PY"] CORE_LOADERS_FOR_DYNACONF = get("CORE_LOADERS_FOR_DYNACONF", core_loaders) # External Loaders to read vars from different data stores default_loaders = [ "dynaconf.loaders.env_loader", # 'dynaconf.loaders.redis_loader' # 'dynaconf.loaders.vault_loader' ] LOADERS_FOR_DYNACONF = get("LOADERS_FOR_DYNACONF", default_loaders) # Errors in loaders should be silenced? SILENT_ERRORS_FOR_DYNACONF = get("SILENT_ERRORS_FOR_DYNACONF", True) # always fresh variables FRESH_VARS_FOR_DYNACONF = get("FRESH_VARS_FOR_DYNACONF", []) DOTENV_PATH_FOR_DYNACONF = get("DOTENV_PATH_FOR_DYNACONF", None) DOTENV_VERBOSE_FOR_DYNACONF = get("DOTENV_VERBOSE_FOR_DYNACONF", False) DOTENV_OVERRIDE_FOR_DYNACONF = get("DOTENV_OVERRIDE_FOR_DYNACONF", False) # Currently this is only used by cli. INSTANCE_FOR_DYNACONF specifies python # dotted path to custom LazySettings instance. Last dotted path item should be # instance of LazySettings. INSTANCE_FOR_DYNACONF = get("INSTANCE_FOR_DYNACONF", None) # https://msg.pyyaml.org/load YAML_LOADER_FOR_DYNACONF = get("YAML_LOADER_FOR_DYNACONF", "safe_load") # Use commentjson? https://commentjson.readthedocs.io/en/latest/ COMMENTJSON_ENABLED_FOR_DYNACONF = get( "COMMENTJSON_ENABLED_FOR_DYNACONF", False ) # Extra file, or list of files where to look for secrets # useful for CI environment like jenkins # where you can export this variable pointing to a local # absolute path of the secrets file. SECRETS_FOR_DYNACONF = get("SECRETS_FOR_DYNACONF", None) # To include extra paths based on envvar INCLUDES_FOR_DYNACONF = get("INCLUDES_FOR_DYNACONF", []) # To pre-load extra paths based on envvar PRELOAD_FOR_DYNACONF = get("PRELOAD_FOR_DYNACONF", []) # Files to skip if found on search tree SKIP_FILES_FOR_DYNACONF = get("SKIP_FILES_FOR_DYNACONF", []) # Backwards compatibility with renamed variables for old, new in RENAMED_VARS.items(): setattr(sys.modules[__name__], old, locals()[new]) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1631217935.1170113 dynaconf-3.1.7/dynaconf/loaders/0000755000175000017500000000000000000000000020152 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631212713.0 dynaconf-3.1.7/dynaconf/loaders/__init__.py0000644000175000017500000002173200000000000022270 0ustar00rochacbrunorochacbrunoimport importlib import os from dynaconf import constants as ct from dynaconf import default_settings from dynaconf.loaders import ini_loader from dynaconf.loaders import json_loader from dynaconf.loaders import py_loader from dynaconf.loaders import toml_loader from dynaconf.loaders import yaml_loader from dynaconf.utils import deduplicate from dynaconf.utils import ensure_a_list from dynaconf.utils.boxing import DynaBox from dynaconf.utils.files import get_local_filename from dynaconf.utils.parse_conf import false_values def default_loader(obj, defaults=None): """Loads default settings and check if there are overridings exported as environment variables""" defaults = defaults or {} default_settings_values = { key: value for key, value in default_settings.__dict__.items() # noqa if key.isupper() } all_keys = deduplicate( list(defaults.keys()) + list(default_settings_values.keys()) ) for key in all_keys: if not obj.exists(key): value = defaults.get(key, default_settings_values.get(key)) obj.set(key, value) # start dotenv to get default env vars from there # check overrides in env vars if obj.get("load_dotenv") is True: default_settings.start_dotenv(obj) # Deal with cases where a custom ENV_SWITCHER_IS_PROVIDED # Example: Flask and Django Extensions env_switcher = defaults.get( "ENV_SWITCHER_FOR_DYNACONF", "ENV_FOR_DYNACONF" ) for key in all_keys: if key not in default_settings_values.keys(): continue env_value = obj.get_environ( env_switcher if key == "ENV_FOR_DYNACONF" else key, default="_not_found", ) if env_value != "_not_found": obj.set(key, env_value, tomlfy=True) def _run_hook_module(hook, hook_module, obj, key=None): """Run the hook function from the settings obj. given a hook name, a hook_module and a settings object load the function and execute if found. """ if hook in obj._loaded_hooks.get(hook_module.__file__, {}): # already loaded return if hook_module and getattr(hook_module, "_error", False): raise hook_module._error hook_func = getattr(hook_module, hook, None) if hook_func: hook_dict = hook_func(obj.dynaconf.clone()) if hook_dict: merge = hook_dict.pop( "dynaconf_merge", hook_dict.pop("DYNACONF_MERGE", False) ) if key and key in hook_dict: obj.set(key, hook_dict[key], tomlfy=False, merge=merge) elif not key: obj.update(hook_dict, tomlfy=False, merge=merge) obj._loaded_hooks[hook_module.__file__][hook] = hook_dict def execute_hooks(hook, obj, env=None, silent=True, key=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: hook_module_name = ".".join( loaded_module.split(".")[:-1] + ["dynaconf_hooks"] ) try: hook_module = importlib.import_module(hook_module_name) except (ImportError, TypeError): # There was no hook on the same path as a python module continue else: _run_hook_module( hook=hook, hook_module=hook_module, obj=obj, key=key, ) # Try to load from python filename path for loaded_file in obj._loaded_files: hook_file = os.path.join( os.path.dirname(loaded_file), "dynaconf_hooks.py" ) hook_module = py_loader.import_from_filename( obj, hook_file, silent=silent ) if not hook_module: # There was no hook on the same path as a python file continue _run_hook_module( hook=hook, hook_module=hook_module, obj=obj, key=key, ) def settings_loader( obj, settings_module=None, env=None, silent=True, key=None, filename=None ): """Loads from defined settings module :param obj: A dynaconf instance :param settings_module: A path or a list of paths e.g settings.toml :param env: Env to look for data defaults: development :param silent: Boolean to raise loading errors :param key: Load a single key if provided :param filename: optional filename to override the settings_module """ if filename is None: settings_module = settings_module or obj.settings_module if not settings_module: # pragma: no cover return files = ensure_a_list(settings_module) else: files = ensure_a_list(filename) files.extend(ensure_a_list(obj.get("SECRETS_FOR_DYNACONF", None))) found_files = [] modules_names = [] for item in files: item = str(item) # Ensure str in case of LocalPath/Path is passed. if item.endswith(ct.ALL_EXTENSIONS + (".py",)): p_root = obj._root_path or ( os.path.dirname(found_files[0]) if found_files else None ) found = obj.find_file(item, project_root=p_root) if found: found_files.append(found) else: # a bare python module name w/o extension modules_names.append(item) enabled_core_loaders = [ item.upper() for item in obj.get("CORE_LOADERS_FOR_DYNACONF") or [] ] # add `.local.` to found_files list to search for local files. found_files.extend( [ get_local_filename(item) for item in found_files if ".local." not in str(item) ] ) for mod_file in modules_names + found_files: # can be set to multiple files settings.py,settings.yaml,... # Cascade all loaders loaders = [ {"ext": ct.YAML_EXTENSIONS, "name": "YAML", "loader": yaml_loader}, {"ext": ct.TOML_EXTENSIONS, "name": "TOML", "loader": toml_loader}, {"ext": ct.INI_EXTENSIONS, "name": "INI", "loader": ini_loader}, {"ext": ct.JSON_EXTENSIONS, "name": "JSON", "loader": json_loader}, ] for loader in loaders: if loader["name"] not in enabled_core_loaders: continue if mod_file.endswith(loader["ext"]): loader["loader"].load( obj, filename=mod_file, env=env, silent=silent, key=key ) continue if mod_file.endswith(ct.ALL_EXTENSIONS): continue if "PY" not in enabled_core_loaders: # pyloader is disabled continue # must be Python file or module # load from default defined module settings.py or .secrets.py if exists py_loader.load(obj, mod_file, key=key) # load from the current env e.g: development_settings.py env = env or obj.current_env if mod_file.endswith(".py"): if ".secrets.py" == mod_file: tmpl = ".{0}_{1}{2}" mod_file = "secrets.py" else: tmpl = "{0}_{1}{2}" dirname = os.path.dirname(mod_file) filename, extension = os.path.splitext(os.path.basename(mod_file)) new_filename = tmpl.format(env.lower(), filename, extension) env_mod_file = os.path.join(dirname, new_filename) global_filename = tmpl.format("global", filename, extension) global_mod_file = os.path.join(dirname, global_filename) else: env_mod_file = f"{env.lower()}_{mod_file}" global_mod_file = f"global_{mod_file}" py_loader.load( obj, env_mod_file, identifier=f"py_{env.upper()}", silent=True, key=key, ) # load from global_settings.py py_loader.load( obj, global_mod_file, identifier="py_global", silent=True, key=key ) def enable_external_loaders(obj): """Enable external service loaders like `VAULT_` and `REDIS_` looks forenv variables like `REDIS_ENABLED_FOR_DYNACONF` """ for name, loader in ct.EXTERNAL_LOADERS.items(): enabled = getattr(obj, f"{name.upper()}_ENABLED_FOR_DYNACONF", False) if ( enabled and enabled not in false_values and loader not in obj.LOADERS_FOR_DYNACONF ): # noqa obj.LOADERS_FOR_DYNACONF.insert(0, loader) def write(filename, data, env=None): """Writes `data` to `filename` infers format by file extension.""" loader_name = f"{filename.rpartition('.')[-1]}_loader" loader = globals().get(loader_name) if not loader: raise IOError(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: data = {env: data} loader.write(filename, data, merge=False) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631212713.0 dynaconf-3.1.7/dynaconf/loaders/base.py0000644000175000017500000001403400000000000021440 0ustar00rochacbrunorochacbrunoimport io import warnings from dynaconf.utils import build_env_list from dynaconf.utils import ensure_a_list from dynaconf.utils import upperfy class BaseLoader: """Base loader for dynaconf source files. :param obj: {[LazySettings]} -- [Dynaconf settings] :param env: {[string]} -- [the current env to be loaded defaults to [development]] :param identifier: {[string]} -- [identifier ini, yaml, json, py, toml] :param extensions: {[list]} -- [List of extensions with dots ['.a', '.b']] :param file_reader: {[callable]} -- [reads file return dict] :param string_reader: {[callable]} -- [reads string return dict] """ def __init__( self, obj, env, identifier, extensions, file_reader, string_reader ): """Instantiates a loader for different sources""" self.obj = obj self.env = env or obj.current_env self.identifier = identifier self.extensions = extensions self.file_reader = file_reader self.string_reader = string_reader @staticmethod def warn_not_installed(obj, identifier): # pragma: no cover if identifier not in obj._not_installed_warnings: warnings.warn( f"{identifier} support is not installed in your environment. " f"`pip install dynaconf[{identifier}]`" ) obj._not_installed_warnings.append(identifier) def load(self, filename=None, key=None, silent=True): """ Reads and loads in to `self.obj` a single key or all keys from source :param filename: Optional filename to load :param key: if provided load a single key :param silent: if load erros should be silenced """ filename = filename or self.obj.get(self.identifier.upper()) if not filename: return if not isinstance(filename, (list, tuple)): split_files = ensure_a_list(filename) if all([f.endswith(self.extensions) for f in split_files]): # noqa files = split_files # it is a ['file.ext', ...] else: # it is a single config as string files = [filename] else: # it is already a list/tuple files = filename source_data = self.get_source_data(files) if self.obj.get("ENVIRONMENTS_FOR_DYNACONF") is False: self._envless_load(source_data, silent, key) else: self._load_all_envs(source_data, silent, key) def get_source_data(self, files): """Reads each file and returns source data for each file {"path/to/file.ext": {"key": "value"}} """ data = {} 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: content = self.file_reader(open_file) self.obj._loaded_files.append(source_file) if content: data[source_file] = content except IOError as e: if ".local." not in source_file: warnings.warn( f"{self.identifier}_loader: {source_file} " f":{str(e)}" ) else: # for tests it is possible to pass string content = self.string_reader(source_file) if content: data[source_file] = content return data def _envless_load(self, source_data, silent=True, key=None): """Load all the keys from each file without env separation""" for file_data in source_data.values(): self._set_data_to_obj( file_data, self.identifier, key=key, ) def _load_all_envs(self, source_data, silent=True, key=None): """Load configs from files separating by each environment""" for file_data in source_data.values(): # env name is checked in lower file_data = {k.lower(): value for k, value in file_data.items()} # is there a `dynaconf_merge` on top level of file? file_merge = file_data.get("dynaconf_merge") for env in build_env_list(self.obj, self.env): env = env.lower() # lower for better comparison try: data = file_data[env] or {} except KeyError: if silent: continue raise 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, file_merge, key, ) def _set_data_to_obj( self, data, identifier, file_merge=None, key=False, ): """Calls settings.set to add the keys""" # data 1st level keys should be transformed to upper case. data = {upperfy(k): v for k, v in data.items()} if key: key = upperfy(key) if self.obj.filter_strategy: data = self.obj.filter_strategy(data) # is there a `dynaconf_merge` inside an `[env]`? file_merge = file_merge or data.pop("DYNACONF_MERGE", False) if not key: self.obj.update( data, loader_identifier=identifier, merge=file_merge, ) elif key in data: self.obj.set( key, data.get(key), loader_identifier=identifier, merge=file_merge, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613139008.0 dynaconf-3.1.7/dynaconf/loaders/env_loader.py0000644000175000017500000000556000000000000022650 0ustar00rochacbrunorochacbrunofrom os import environ from dynaconf.utils import upperfy from dynaconf.utils.parse_conf import parse_conf_data from dynaconf.vendor.dotenv import cli as dotenv_cli IDENTIFIER = "env" def load(obj, env=None, silent=True, key=None): """Loads envvars with prefixes: `DYNACONF_` (default global) or `$(ENVVAR_PREFIX_FOR_DYNACONF)_` """ global_prefix = obj.get("ENVVAR_PREFIX_FOR_DYNACONF") if global_prefix is False or global_prefix.upper() != "DYNACONF": load_from_env(obj, "DYNACONF", key, silent, IDENTIFIER + "_global") # Load the global env if exists and overwrite everything load_from_env(obj, global_prefix, key, silent, IDENTIFIER + "_global") def load_from_env( obj, prefix=False, key=None, silent=False, identifier=IDENTIFIER, env=False, # backwards compatibility bc renamed param ): if prefix is False and env is not False: prefix = env env_ = "" if prefix is not False: if not isinstance(prefix, str): raise TypeError("`prefix/env` must be str or False") prefix = prefix.upper() env_ = f"{prefix}_" # Load a single environment variable explicitly. if key: key = upperfy(key) value = environ.get(f"{env_}{key}") if value: try: # obj is a Settings obj.set(key, value, loader_identifier=identifier, tomlfy=True) except AttributeError: # obj is a dict obj[key] = parse_conf_data( value, tomlfy=True, box_settings=obj ) # Load environment variables in bulk (when matching). else: # 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 = { key[trim_len:]: parse_conf_data( data, tomlfy=True, box_settings=obj ) for key, data in environ.items() if key.startswith(env_) and not ( # Ignore environment variables that haven't been # pre-defined in settings space. ignore_unknown and key[trim_len:] not in known_keys ) } # Update the settings space based on gathered data from environment. if data: obj.update(data, loader_identifier=identifier) def write(settings_path, settings_data, **kwargs): """Write data to .env file""" for key, value in settings_data.items(): quote_mode = ( isinstance(value, str) and (value.startswith("'") or value.startswith('"')) ) or isinstance(value, (list, dict)) dotenv_cli.set_key( str(settings_path), key, str(value), quote_mode="always" if quote_mode else "none", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631212157.0 dynaconf-3.1.7/dynaconf/loaders/ini_loader.py0000644000175000017500000000351300000000000022633 0ustar00rochacbrunorochacbrunoimport io from pathlib import Path from dynaconf import default_settings from dynaconf.constants import INI_EXTENSIONS from dynaconf.loaders.base import BaseLoader from dynaconf.utils import object_merge try: from configobj import ConfigObj except ImportError: # pragma: no cover ConfigObj = None def load(obj, env=None, silent=True, key=None, filename=None): """ Reads and loads in to "obj" a single key or all keys from source file. :param obj: the settings instance :param env: settings current env default='development' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :param filename: Optional custom filename to load :return: None """ if ConfigObj is None: # pragma: no cover BaseLoader.warn_not_installed(obj, "ini") return loader = BaseLoader( obj=obj, env=env, identifier="ini", extensions=INI_EXTENSIONS, file_reader=lambda fileobj: ConfigObj(fileobj).dict(), string_reader=lambda strobj: ConfigObj(strobj.split("\n")).dict(), ) loader.load( filename=filename, key=key, silent=silent, ) def write(settings_path, settings_data, merge=True): """Write data to a settings file. :param settings_path: the filepath :param settings_data: a dictionary with data :param merge: boolean if existing file should be merged with new data """ 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 ) as open_file: object_merge(ConfigObj(open_file).dict(), settings_data) new = ConfigObj() new.update(settings_data) new.write(open(str(settings_path), "bw")) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631212157.0 dynaconf-3.1.7/dynaconf/loaders/json_loader.py0000644000175000017500000000443600000000000023032 0ustar00rochacbrunorochacbrunoimport io import json from pathlib import Path from dynaconf import default_settings from dynaconf.constants import JSON_EXTENSIONS from dynaconf.loaders.base import BaseLoader from dynaconf.utils import object_merge from dynaconf.utils.parse_conf import try_to_encode try: # pragma: no cover import commentjson except ImportError: # pragma: no cover commentjson = None def load(obj, env=None, silent=True, key=None, filename=None): """ Reads and loads in to "obj" a single key or all keys from source file. :param obj: the settings instance :param env: settings current env default='development' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :param filename: Optional custom filename to load :return: None """ if ( obj.get("COMMENTJSON_ENABLED_FOR_DYNACONF") and commentjson ): # pragma: no cover # noqa file_reader = commentjson.load string_reader = commentjson.loads else: file_reader = json.load string_reader = json.loads loader = BaseLoader( obj=obj, env=env, identifier="json", extensions=JSON_EXTENSIONS, file_reader=file_reader, string_reader=string_reader, ) loader.load( filename=filename, key=key, silent=silent, ) def write(settings_path, settings_data, merge=True): """Write data to a settings file. :param settings_path: the filepath :param settings_data: a dictionary with data :param merge: boolean if existing file should be merged with new data """ 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 ) as open_file: object_merge(json.load(open_file), settings_data) with io.open( str(settings_path), "w", encoding=default_settings.ENCODING_FOR_DYNACONF, ) as open_file: json.dump(settings_data, open_file, cls=DynaconfEncoder) class DynaconfEncoder(json.JSONEncoder): """Transform Dynaconf custom types instances to json representation""" def default(self, o): return try_to_encode(o, callback=super().default) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631212713.0 dynaconf-3.1.7/dynaconf/loaders/py_loader.py0000644000175000017500000001157700000000000022515 0ustar00rochacbrunorochacbrunoimport errno import importlib import inspect import io import types from contextlib import suppress from pathlib import Path from dynaconf import default_settings from dynaconf.utils import DynaconfDict from dynaconf.utils import object_merge from dynaconf.utils import upperfy from dynaconf.utils.files import find_file def load(obj, settings_module, identifier="py", silent=False, key=None): """Tries to import a python module""" mod, loaded_from = get_module(obj, settings_module, silent) if not (mod and loaded_from): return load_from_python_object(obj, mod, settings_module, key, identifier) def load_from_python_object( obj, mod, settings_module, key=None, identifier=None ): file_merge = getattr(mod, "dynaconf_merge", False) or getattr( mod, "DYNACONF_MERGE", False ) for setting in dir(mod): # A setting var in a Python file should start with upper case # valid: A_value=1, ABC_value=3 A_BBB__default=1 # invalid: a_value=1, MyValue=3 # This is to avoid loading functions, classes and built-ins if setting.split("__")[0].isupper(): if key is None or key == setting: setting_value = getattr(mod, setting) obj.set( setting, setting_value, loader_identifier=identifier, merge=file_merge, ) obj._loaded_py_modules.append(mod.__name__) obj._loaded_files.append(mod.__file__) def try_to_load_from_py_module_name( obj, name, key=None, identifier="py", silent=False ): """Try to load module by its string name. Arguments: obj {LAzySettings} -- Dynaconf settings instance name {str} -- Name of the module e.g: foo.bar.zaz Keyword Arguments: key {str} -- Single key to be loaded (default: {None}) identifier {str} -- Name of identifier to store (default: 'py') silent {bool} -- Weather to raise or silence exceptions. """ ctx = suppress(ImportError, TypeError) if silent else suppress() with ctx: mod = importlib.import_module(str(name)) load_from_python_object(obj, mod, name, key, identifier) return True # loaded ok! # if it reaches this point that means exception occurred, module not found. return False def get_module(obj, filename, silent=False): try: mod = importlib.import_module(filename) loaded_from = "module" mod.is_error = False except (ImportError, TypeError): mod = import_from_filename(obj, filename, silent=silent) if mod and not mod._is_error: loaded_from = "filename" else: # it is important to return None in case of not loaded loaded_from = None return mod, loaded_from def import_from_filename(obj, filename, silent=False): # pragma: no cover """If settings_module is a filename path import it.""" if filename in [item.filename for item in inspect.stack()]: raise ImportError( "Looks like you are loading dynaconf " f"from inside the {filename} file and then it is trying " "to load itself entering in a circular reference " "problem. To solve it you have to " "invoke your program from another root folder " "or rename your program file." ) _find_file = getattr(obj, "find_file", find_file) if not filename.endswith(".py"): filename = f"{filename}.py" if filename in default_settings.SETTINGS_FILE_FOR_DYNACONF: silent = True mod = types.ModuleType(filename.rstrip(".py")) mod.__file__ = filename mod._is_error = False mod._error = None try: with io.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: e.strerror = ( f"py_loader: error loading file " f"({e.strerror} {filename})\n" ) if silent and e.errno in (errno.ENOENT, errno.EISDIR): return mod._is_error = True mod._error = e return mod def write(settings_path, settings_data, merge=True): """Write data to a settings file. :param settings_path: the filepath :param settings_data: a dictionary with data :param merge: boolean if existing file should be merged with new data """ settings_path = Path(settings_path) if settings_path.exists() and merge: # pragma: no cover existing = DynaconfDict() load(existing, str(settings_path)) object_merge(existing, settings_data) with io.open( str(settings_path), "w", encoding=default_settings.ENCODING_FOR_DYNACONF, ) as f: f.writelines( [f"{upperfy(k)} = {repr(v)}\n" for k, v in settings_data.items()] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1600729045.0 dynaconf-3.1.7/dynaconf/loaders/redis_loader.py0000644000175000017500000000664500000000000023173 0ustar00rochacbrunorochacbrunofrom dynaconf.utils import build_env_list from dynaconf.utils import upperfy from dynaconf.utils.parse_conf import parse_conf_data from dynaconf.utils.parse_conf import unparse_conf_data try: from redis import StrictRedis except ImportError: StrictRedis = None IDENTIFIER = "redis" def load(obj, env=None, silent=True, key=None): """Reads and loads in to "settings" a single key or all keys from redis :param obj: the settings instance :param env: settings env default='DYNACONF' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :return: None """ if StrictRedis is None: raise ImportError( "redis package is not installed in your environment. " "`pip install dynaconf[redis]` or disable the redis loader with " "export REDIS_ENABLED_FOR_DYNACONF=false" ) redis = StrictRedis(**obj.get("REDIS_FOR_DYNACONF")) prefix = obj.get("ENVVAR_PREFIX_FOR_DYNACONF") # prefix is added to env_list to keep backwards compatibility env_list = [prefix] + build_env_list(obj, env or obj.current_env) for env_name in env_list: holder = f"{prefix.upper()}_{env_name.upper()}" try: if key: value = redis.hget(holder.upper(), key) if value: parsed_value = parse_conf_data( value, tomlfy=True, box_settings=obj ) if parsed_value: obj.set(key, parsed_value) else: data = { key: parse_conf_data(value, tomlfy=True, box_settings=obj) for key, value in redis.hgetall(holder.upper()).items() } if data: obj.update(data, loader_identifier=IDENTIFIER) except Exception: if silent: return False raise def write(obj, data=None, **kwargs): """Write a value in to loader source :param obj: settings object :param data: vars to be stored :param kwargs: vars to be stored :return: """ if obj.REDIS_ENABLED_FOR_DYNACONF is False: raise RuntimeError( "Redis is not configured \n" "export REDIS_ENABLED_FOR_DYNACONF=true\n" "and configure the REDIS_FOR_DYNACONF_* variables" ) client = StrictRedis(**obj.REDIS_FOR_DYNACONF) holder = obj.get("ENVVAR_PREFIX_FOR_DYNACONF").upper() # add env to holder holder = f"{holder}_{obj.current_env.upper()}" data = data or {} data.update(kwargs) if not data: raise AttributeError("Data must be provided") redis_data = { upperfy(key): unparse_conf_data(value) for key, value in data.items() } client.hmset(holder.upper(), redis_data) load(obj) def delete(obj, key=None): """ Delete a single key if specified, or all env if key is none :param obj: settings object :param key: key to delete from store location :return: None """ client = StrictRedis(**obj.REDIS_FOR_DYNACONF) holder = obj.get("ENVVAR_PREFIX_FOR_DYNACONF").upper() # add env to holder holder = f"{holder}_{obj.current_env.upper()}" if key: client.hdel(holder.upper(), upperfy(key)) obj.unset(key) else: keys = client.hkeys(holder.upper()) client.delete(holder.upper()) obj.unset_all(keys) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631212157.0 dynaconf-3.1.7/dynaconf/loaders/toml_loader.py0000644000175000017500000000403000000000000023022 0ustar00rochacbrunorochacbrunoimport io 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 def load(obj, env=None, silent=True, key=None, filename=None): """ Reads and loads in to "obj" a single key or all keys from source file. :param obj: the settings instance :param env: settings current env default='development' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :param filename: Optional custom filename to load :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, ) def write(settings_path, settings_data, merge=True): """Write data to a settings file. :param settings_path: the filepath :param settings_data: a dictionary with data :param merge: boolean if existing file should be merged with new data """ 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 ) 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) def encode_nulls(data): """TOML does not support `None` so this function transforms to '@none '.""" if data is None: return "@none " if isinstance(data, dict): return {key: encode_nulls(value) for key, value in data.items()} elif isinstance(data, (list, tuple)): return [encode_nulls(item) for item in data] return data ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1613139008.0 dynaconf-3.1.7/dynaconf/loaders/vault_loader.py0000644000175000017500000001275300000000000023215 0ustar00rochacbrunorochacbruno# docker run -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' -p 8200:8200 vault # pip install hvac from dynaconf.utils import build_env_list from dynaconf.utils.parse_conf import parse_conf_data try: import boto3 except ImportError: boto3 = None try: from hvac import Client from hvac.exceptions import InvalidPath except ImportError: raise ImportError( "vault package is not installed in your environment. " "`pip install dynaconf[vault]` or disable the vault loader with " "export VAULT_ENABLED_FOR_DYNACONF=false" ) IDENTIFIER = "vault" # backwards compatibility _get_env_list = build_env_list def get_client(obj): client = Client( **{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( role_id=obj.VAULT_ROLE_ID_FOR_DYNACONF, secret_id=obj.get("VAULT_SECRET_ID_FOR_DYNACONF"), ) elif obj.VAULT_ROOT_TOKEN_FOR_DYNACONF is not None: client.token = obj.VAULT_ROOT_TOKEN_FOR_DYNACONF elif obj.VAULT_AUTH_WITH_IAM_FOR_DYNACONF: if boto3 is None: raise ImportError( "boto3 package is not installed in your environment. " "`pip install boto3` or disable the VAULT_AUTH_WITH_IAM" ) session = boto3.Session() credentials = session.get_credentials() client.auth.aws.iam_login( credentials.access_key, credentials.secret_key, credentials.token, role=obj.VAULT_AUTH_ROLE_FOR_DYNACONF, ) assert client.is_authenticated(), ( "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 return client def load(obj, env=None, silent=None, key=None): """Reads and loads in to "settings" a single key or all keys from vault :param obj: the settings instance :param env: settings env default='DYNACONF' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :return: 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"] except InvalidPath: # The given path is not a directory dirs = [] env_list = dirs + build_env_list(obj, env) for env in env_list: path = "/".join([obj.VAULT_PATH_FOR_DYNACONF, env]) try: if obj.VAULT_KV_VERSION_FOR_DYNACONF == 2: data = client.secrets.kv.v2.read_secret_version( path, mount_point=obj.VAULT_MOUNT_POINT_FOR_DYNACONF ) else: data = client.secrets.kv.read_secret( "data/" + path, mount_point=obj.VAULT_MOUNT_POINT_FOR_DYNACONF, ) except InvalidPath: # If the path doesn't exist, ignore it and set data to None data = None if data: # There seems to be a data dict within a data dict, # extract the inner data data = data.get("data", {}).get("data", {}) try: if obj.VAULT_KV_VERSION_FOR_DYNACONF == 2 and data: data = data.get("data", {}) if data and key: value = parse_conf_data( data.get(key), tomlfy=True, box_settings=obj ) if value: obj.set(key, value) elif data: obj.update(data, loader_identifier=IDENTIFIER, tomlfy=True) except Exception: if silent: return False raise def write(obj, data=None, **kwargs): """Write a value in to loader source :param obj: settings object :param data: vars to be stored :param kwargs: vars to be stored :return: """ if obj.VAULT_ENABLED_FOR_DYNACONF is False: raise RuntimeError( "Vault is not configured \n" "export VAULT_ENABLED_FOR_DYNACONF=true\n" "and configure the VAULT_FOR_DYNACONF_* variables" ) data = data or {} data.update(kwargs) if not data: raise AttributeError("Data must be provided") data = {"data": data} client = get_client(obj) if obj.VAULT_KV_VERSION_FOR_DYNACONF == 1: mount_point = obj.VAULT_MOUNT_POINT_FOR_DYNACONF + "/data" else: mount_point = obj.VAULT_MOUNT_POINT_FOR_DYNACONF path = "/".join([obj.VAULT_PATH_FOR_DYNACONF, obj.current_env.lower()]) client.secrets.kv.create_or_update_secret( path, secret=data, mount_point=mount_point ) load(obj) def list_envs(obj, path=""): """ This function is a helper to get a list of all the existing envs in the source of data, the use case is: existing_envs = vault_loader.list_envs(settings) for env in exiting_envs: with settings.using_env(env): # switch to the env # do something with a key of that env :param obj: settings object :param path: path to the vault secrets :return: list containing all the keys at the given path """ client = get_client(obj) path = path or obj.get("VAULT_PATH_FOR_DYNACONF") try: return client.list(f"/secret/metadata/{path}")["data"]["keys"] except TypeError: return [] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631212157.0 dynaconf-3.1.7/dynaconf/loaders/yaml_loader.py0000644000175000017500000000520000000000000023011 0ustar00rochacbrunorochacbrunoimport io from pathlib import Path from warnings import warn from dynaconf import default_settings from dynaconf.constants import YAML_EXTENSIONS from dynaconf.loaders.base import BaseLoader from dynaconf.utils import object_merge from dynaconf.utils.parse_conf import try_to_encode from dynaconf.vendor.ruamel import yaml # Add support for Dynaconf Lazy values to YAML dumper yaml.SafeDumper.yaml_representers[ None ] = lambda self, data: yaml.representer.SafeRepresenter.represent_str( self, try_to_encode(data) ) def load(obj, env=None, silent=True, key=None, filename=None): """ Reads and loads in to "obj" a single key or all keys from source file. :param obj: the settings instance :param env: settings current env default='development' :param silent: if errors should raise :param key: if defined load a single key, else load all in env :param filename: Optional custom filename to load :return: None """ # Resolve the loaders # https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation # Possible values are `safe_load, full_load, unsafe_load, load` yaml_reader = getattr( yaml, obj.get("YAML_LOADER_FOR_DYNACONF"), yaml.safe_load ) if yaml_reader.__name__ == "unsafe_load": # pragma: no cover warn( "yaml.unsafe_load is deprecated." " Please read https://msg.pyyaml.org/load for full details." " Try to use full_load or safe_load." ) loader = BaseLoader( obj=obj, env=env, identifier="yaml", extensions=YAML_EXTENSIONS, file_reader=yaml_reader, string_reader=yaml_reader, ) loader.load( filename=filename, key=key, silent=silent, ) def write(settings_path, settings_data, merge=True): """Write data to a settings file. :param settings_path: the filepath :param settings_data: a dictionary with data :param merge: boolean if existing file should be merged with new data """ 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 ) as open_file: object_merge(yaml.safe_load(open_file), settings_data) with io.open( str(settings_path), "w", encoding=default_settings.ENCODING_FOR_DYNACONF, ) as open_file: yaml.dump( settings_data, open_file, Dumper=yaml.dumper.SafeDumper, explicit_start=True, indent=2, default_flow_style=False, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1631217935.1170113 dynaconf-3.1.7/dynaconf/strategies/0000755000175000017500000000000000000000000020673 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631212157.0 dynaconf-3.1.7/dynaconf/strategies/__init__.py0000644000175000017500000000000000000000000022772 0ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631212506.0 dynaconf-3.1.7/dynaconf/strategies/filtering.py0000644000175000017500000000102400000000000023225 0ustar00rochacbrunorochacbrunofrom dynaconf.utils import upperfy class PrefixFilter: def __init__(self, prefix): if not isinstance(prefix, str): raise TypeError("`SETTINGS_FILE_PREFIX` must be str") self.prefix = "{}_".format(upperfy(prefix)) def __call__(self, data): """Filter incoming data by prefix""" len_prefix = len(self.prefix) return { upperfy(key[len_prefix:]): value for key, value in data.items() if upperfy(key[:len_prefix]) == self.prefix } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1590127290.0 dynaconf-3.1.7/dynaconf/test_settings.py0000644000175000017500000000020600000000000021770 0ustar00rochacbrunorochacbruno# pragma: no cover TESTING = True LOADERS_FOR_DYNACONF = [ "dynaconf.loaders.env_loader", # 'dynaconf.loaders.redis_loader' ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1631217935.1170113 dynaconf-3.1.7/dynaconf/utils/0000755000175000017500000000000000000000000017661 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631216676.0 dynaconf-3.1.7/dynaconf/utils/__init__.py0000644000175000017500000003270000000000000021774 0ustar00rochacbrunorochacbrunofrom __future__ import annotations import os 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 from dynaconf.utils.boxing import DynaBox from dynaconf.base import LazySettings, Settings BANNER = """ ██████╗ ██╗ ██╗███╗ ██╗ █████╗ ██████╗ ██████╗ ███╗ ██╗███████╗ ██╔══██╗╚██╗ ██╔╝████╗ ██║██╔══██╗██╔════╝██╔═══██╗████╗ ██║██╔════╝ ██║ ██║ ╚████╔╝ ██╔██╗ ██║███████║██║ ██║ ██║██╔██╗ ██║█████╗ ██║ ██║ ╚██╔╝ ██║╚██╗██║██╔══██║██║ ██║ ██║██║╚██╗██║██╔══╝ ██████╔╝ ██║ ██║ ╚████║██║ ██║╚██████╗╚██████╔╝██║ ╚████║██║ ╚═════╝ ╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ """ if os.name == "nt": # pragma: no cover # windows can't handle the above charmap BANNER = "DYNACONF" def object_merge( old: Any, new: Any, unique: bool = False, full_path: List[str] = None ) -> Any: """ Recursively merge two data structures, new is mutated in-place. :param old: The existing data. :param new: The new data to get old values merged in to. :param unique: When set to True existing list items are not set. :param full_path: Indicates the elements of a tree. """ if full_path is None: full_path = [] if old == new or old is None or new is None: # Nothing to merge return new if isinstance(old, list) and isinstance(new, list): 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 # Need to make every `None` on `_store` to be an wrapped `LazyNone` for key, value in old.items(): if ( existing_value is not None and 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 else: object_merge( value, new[key], full_path=full_path[1:] if full_path else None, ) handle_metavalues(old, new) return new def recursive_get( obj: Union[DynaBox, Dict[str, int], Dict[str, Union[str, int]]], names: Optional[List[str]], ) -> 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. """ if not names: return head, tail = names[0], names[1:] result = getattr(obj, head, None) if not tail: return result return recursive_get(result, tail) def handle_metavalues( old: Union[DynaBox, Dict[str, int], Dict[str, Union[str, int]]], new: Any ) -> None: """Cleanup of MetaValues on new dict""" for key in list(new.keys()): # 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 new.pop(key, None) old.pop(key, None) elif getattr(new[key], "_dynaconf_merge", False): # a Merge on `new` triggers merge with existing data new[key] = object_merge( old.get(key), new[key].unwrap(), unique=new[key].unique ) # Data structures containing merge tokens if isinstance(new.get(key), (list, tuple)): has_merge = "dynaconf_merge" in new[key] has_merge_unique = "dynaconf_merge_unique" in new[key] if has_merge or has_merge_unique: value = list(new[key]) unique = False try: value.remove("dynaconf_merge") except ValueError: value.remove("dynaconf_merge_unique") unique = True for item in old.get(key)[::-1]: if unique and item in value: continue value.insert(0, item) new[key] = value elif isinstance(new.get(key), dict): local_merge = new[key].pop( "dynaconf_merge", new[key].pop("dynaconf_merge_unique", None) ) if local_merge not in (True, False, None) and not new[key]: # In case `dynaconf_merge:` holds value not boolean - ref #241 new[key] = local_merge if local_merge: new[key] = object_merge(old.get(key), new[key]) class DynaconfDict(dict): """A dict representing en empty Dynaconf object useful to run loaders in to a dict for testing""" def __init__(self, *args, **kwargs): self._fresh = False self._loaded_envs = [] self._loaded_hooks = defaultdict(dict) self._loaded_py_modules = [] self._loaded_files = [] self._deleted = set() self._store = {} self._env_cache = {} self._loaded_by_loaders = {} self._loaders = [] self._defaults = {} self.environ = os.environ self.SETTINGS_MODULE = None self.filter_strategy = kwargs.get("filter_strategy", None) 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) def set(self, key: str, value: str, *args, **kwargs) -> None: self[key] = value @staticmethod def get_environ(key, default=None): # pragma: no cover return os.environ.get(key, default) def exists(self, key: str, **kwargs) -> bool: return self.get(key, missing) is not missing RENAMED_VARS = { # old: new "DYNACONF_NAMESPACE": "ENV_FOR_DYNACONF", "NAMESPACE_FOR_DYNACONF": "ENV_FOR_DYNACONF", "DYNACONF_SETTINGS_MODULE": "SETTINGS_FILE_FOR_DYNACONF", "DYNACONF_SETTINGS": "SETTINGS_FILE_FOR_DYNACONF", "SETTINGS_MODULE": "SETTINGS_FILE_FOR_DYNACONF", "SETTINGS_MODULE_FOR_DYNACONF": "SETTINGS_FILE_FOR_DYNACONF", "PROJECT_ROOT": "ROOT_PATH_FOR_DYNACONF", "PROJECT_ROOT_FOR_DYNACONF": "ROOT_PATH_FOR_DYNACONF", "DYNACONF_SILENT_ERRORS": "SILENT_ERRORS_FOR_DYNACONF", "DYNACONF_ALWAYS_FRESH_VARS": "FRESH_VARS_FOR_DYNACONF", "BASE_NAMESPACE_FOR_DYNACONF": "DEFAULT_ENV_FOR_DYNACONF", "GLOBAL_ENV_FOR_DYNACONF": "ENVVAR_PREFIX_FOR_DYNACONF", } 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(): if old in kwargs: kwargs[new] = kwargs[old] # update cross references for c_old, c_new in RENAMED_VARS.items(): if c_new == new: kwargs[c_old] = kwargs[new] class Missing: """ Sentinel value object/singleton used to differentiate between ambiguous situations where `None` is a valid value. """ def __bool__(self) -> bool: """Respond to boolean duck-typing.""" return False def __eq__(self, other: Union[DynaBox, Missing]) -> bool: """Equality check for a singleton.""" return isinstance(other, self.__class__) # Ensure compatibility with Python 2.x __nonzero__ = __bool__ def __repr__(self) -> str: """ Unambiguously identify this string-based representation of Missing, used as a singleton. """ return "" missing = Missing() def deduplicate(list_object: List[str]) -> List[str]: """Rebuild `list_object` removing duplicated and keeping order""" new = [] for item in list_object: if item not in new: new.append(item) return new def warn_deprecations(data: Any) -> None: for old, new in RENAMED_VARS.items(): if old in data: warnings.warn( f"You are using {old} which is a deprecated settings " f"replace it with {new}", DeprecationWarning, ) def trimmed_split( s: str, seps: Union[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: continue data = [item.strip() for item in s.strip().split(sep)] return data return [s] # raw un-splitted def ensure_a_list(data: Any) -> Union[List[int], List[str]]: """Ensure data is a list or wrap it in a list""" if not data: return [] if isinstance(data, (list, tuple, set)): return list(data) if isinstance(data, str): data = trimmed_split(data) # settings.toml,other.yaml return data return [data] def build_env_list( obj: Union[Settings, LazySettings], env: Optional[str] ) -> List[str]: """Build env list for loaders to iterate. Arguments: obj {LazySettings} -- A Dynaconf settings instance env {str} -- The current env to be loaded Returns: [str] -- A list of string names of the envs to load. """ # add the [default] env env_list = [obj.get("DEFAULT_ENV_FOR_DYNACONF")] # compatibility with older versions that still uses [dynaconf] as # [default] env global_env = obj.get("ENVVAR_PREFIX_FOR_DYNACONF") or "DYNACONF" 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) # add a manually set env if env and env not in env_list: env_list.append(env) # add the [global] env env_list.append("GLOBAL") # loaders are responsible to change to lower/upper cases return [env.lower() for env in env_list] def upperfy(key: str) -> str: """Receive a string key and returns its upper version. Example: input: foo output: FOO input: foo_bar output: FOO_BAR input: foo__bar__ZAZ output: FOO__bar__ZAZ Arguments: key {str} -- A string key that may contain dunders `__` Returns: The key as upper case but keeping the nested elements. """ key = str(key) if "__" in key: parts = key.split("__") return "__".join([parts[0].upper()] + parts[1:]) return key.upper() def multi_replace(text: str, patterns: Dict[str, str]) -> str: """Replaces multiple pairs in a string Arguments: text {str} -- A "string text" patterns {dict} -- A dict of {"old text": "new text"} Returns: text -- str """ for old, new in patterns.items(): text = text.replace(old, new) return text def extract_json_objects( text: str, decoder: JSONDecoder = JSONDecoder() ) -> Iterator[Dict[str, Union[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 of a parent JSON object. """ pos = 0 while True: match = text.find("{", pos) if match == -1: break try: result, index = decoder.raw_decode(text[match:]) yield result pos = match + index except ValueError: pos = match + 1 def recursively_evaluate_lazy_format( value: Any, settings: Union[Settings, LazySettings] ) -> Any: """Given a value as a data structure, traverse all its members to find Lazy values and evaluate it. For example: Evaluate values inside lists and dicts """ if getattr(value, "_dynaconf_lazy_format", None): value = value(settings) if isinstance(value, list): # Keep the original type, can be a BoxList value = value.__class__( [ recursively_evaluate_lazy_format(item, settings) for item in value ] ) return value def isnamedtupleinstance(value): """Check if value is a namedtuple instance stackoverflow.com/questions/2166818/ how-to-check-if-an-object-is-an-instance-of-a-namedtuple """ t = type(value) b = t.__bases__ if len(b) != 1 or b[0] != tuple: return False f = getattr(t, "_fields", None) if not isinstance(f, tuple): return False return all(type(n) == str for n in f) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1614714907.0 dynaconf-3.1.7/dynaconf/utils/boxing.py0000644000175000017500000000566700000000000021537 0ustar00rochacbrunorochacbrunoimport inspect from functools import wraps 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 def evaluate_lazy_format(f): """Marks a method on Dynabox instance to lazily evaluate LazyFormat objects upon access.""" @wraps(f) def evaluate(dynabox, item, *args, **kwargs): value = f(dynabox, item, *args, **kwargs) settings = dynabox._box_config["box_settings"] if getattr(value, "_dynaconf_lazy_format", None): dynabox._box_config[ f"raw_{item.lower()}" ] = f"@{value.formatter.token} {value.value}" return recursively_evaluate_lazy_format(value, settings) return evaluate class DynaBox(Box): """Specialized Box for dynaconf it allows items/attrs to be found both in upper or lower case""" @evaluate_lazy_format def __getattr__(self, item, *args, **kwargs): try: return super(DynaBox, self).__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) @evaluate_lazy_format def __getitem__(self, item, *args, **kwargs): try: return super(DynaBox, self).__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) def __copy__(self): return self.__class__( super(Box, self).copy(), box_settings=self._box_config.get("box_settings"), ) def copy(self): return self.__class__( super(Box, self).copy(), 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 def __dir__(self): keys = list(self.keys()) reserved = [ item[0] for item in inspect.getmembers(DynaBox) if not item[0].startswith("__") ] return ( keys + [k.lower() for k in keys] + [k.upper() for k in keys] + reserved ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807352.0 dynaconf-3.1.7/dynaconf/utils/files.py0000644000175000017500000000626200000000000021343 0ustar00rochacbrunorochacbrunoimport inspect import io import os from dynaconf.utils import deduplicate 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") if os.path.isfile(path): # pragma: no cover path = os.path.dirname(path) last_dir = None current_dir = os.path.abspath(path) paths = [] while last_dir != current_dir: paths.append(current_dir) paths.append(os.path.join(current_dir, "config")) if break_at and current_dir == os.path.abspath(break_at): # noqa break parent_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir)) last_dir, current_dir = current_dir, parent_dir return paths SEARCHTREE = [] def find_file(filename=".env", project_root=None, skip_files=None, **kwargs): """Search in increasingly higher folders for the given file Returns path to the file if found, or an empty string otherwise. This function will build a `search_tree` based on: - Project_root if specified - Invoked script location and its parents until root - Current working directory For each path in the `search_tree` it will also look for an aditional `./config` folder. """ search_tree = [] work_dir = os.getcwd() skip_files = skip_files or [] # If filename is an absolute path and exists, just return it # if the absolute path does not exist, return empty string so # that it can be joined and avoid IoError if os.path.isabs(filename): return filename if os.path.exists(filename) else "" if project_root is not None: search_tree.extend(_walk_to_root(project_root, break_at=work_dir)) script_dir = os.path.dirname(os.path.abspath(inspect.stack()[-1].filename)) # Path to invoked script and recursively to root with its ./config dirs search_tree.extend(_walk_to_root(script_dir)) # Path to where Python interpreter was invoked and recursively to root search_tree.extend(_walk_to_root(work_dir)) # Don't look the same place twice search_tree = deduplicate(search_tree) global SEARCHTREE SEARCHTREE[:] = search_tree for dirname in search_tree: check_path = os.path.join(dirname, filename) if check_path in skip_files: continue if os.path.exists(check_path): return check_path # First found will return # return empty string if not found so it can still be joined in os.path return "" def read_file(path, **kwargs): content = "" with io.open(path, **kwargs) as open_file: content = open_file.read().strip() return content def get_local_filename(filename): """Takes a filename like `settings.toml` and returns `settings.local.toml` Arguments: filename {str} -- The filename or complete path Returns: [str] -- The same name or path with `.local.` added. """ name, _, extension = os.path.basename(str(filename)).rpartition( os.path.extsep ) return os.path.join( os.path.dirname(str(filename)), f"{name}.local.{extension}" ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807352.0 dynaconf-3.1.7/dynaconf/utils/functional.py0000644000175000017500000001056500000000000022404 0ustar00rochacbrunorochacbrunoimport copy import operator class Empty: def __str__(self): return "EMPTY" empty = Empty() def new_method_proxy(func): def inner(self, *args): if self._wrapped is empty: self._setup() return func(self._wrapped, *args) return inner class LazyObject: """ A wrapper for another class that can be used to delay instantiation of the wrapped class. By subclassing, you have the opportunity to intercept and alter the instantiation. """ # Avoid infinite recursion when tracing __init__. _wrapped = None _kwargs = None _django_override = False def __init__(self): # Note: if a subclass overrides __init__(), it will likely need to # override __copy__() and __deepcopy__() as well. self._wrapped = empty __getattr__ = new_method_proxy(getattr) def __setattr__(self, name, value): if name in ["_wrapped", "_kwargs", "_warn_dynaconf_global_settings"]: # Assign to __dict__ to avoid infinite __setattr__ loops. self.__dict__[name] = value else: if self._wrapped is empty: self._setup() setattr(self._wrapped, name, value) def __delattr__(self, name): if name in ["_wrapped", "_kwargs"]: raise TypeError(f"can't delete {name}.") if self._wrapped is empty: self._setup() delattr(self._wrapped, name) def _setup(self): """ Must be implemented by subclasses to initialize the wrapped object. """ raise NotImplementedError( "subclasses of LazyObject must provide a _setup() method" ) # Because we have messed with __class__ below, we confuse pickle as to what # class we are pickling. We're going to have to initialize the wrapped # object to successfully pickle it, so we might as well just pickle the # wrapped object since they're supposed to act the same way. # # Unfortunately, if we try to simply act like the wrapped object, the ruse # will break down when pickle gets our id(). Thus we end up with pickle # thinking, in effect, that we are a distinct object from the wrapped # object, but with the same __dict__. This can cause problems (see #25389). # # So instead, we define our own __reduce__ method and custom unpickler. We # pickle the wrapped object as the unpickler's argument, so that pickle # will pickle it normally, and then the unpickler simply returns its # argument. def __reduce__(self): if self._wrapped is empty: self._setup() return (unpickle_lazyobject, (self._wrapped,)) def __copy__(self): if self._wrapped is empty: # If uninitialized, copy the wrapper. Use type(self), not # self.__class__, because the latter is proxied. return type(self)() else: # If initialized, return a copy of the wrapped object. return copy.copy(self._wrapped) def __deepcopy__(self, memo): if self._wrapped is empty: # We have to use type(self), not self.__class__, because the # latter is proxied. result = type(self)() memo[id(self)] = result return result return copy.deepcopy(self._wrapped, memo) __bytes__ = new_method_proxy(bytes) __str__ = new_method_proxy(str) __bool__ = new_method_proxy(bool) # Introspection support __dir__ = new_method_proxy(dir) # Need to pretend to be the wrapped class, for the sake of objects that # care about this (especially in equality tests) __class__ = property(new_method_proxy(operator.attrgetter("__class__"))) __eq__ = new_method_proxy(operator.eq) __lt__ = new_method_proxy(operator.lt) __gt__ = new_method_proxy(operator.gt) __ne__ = new_method_proxy(operator.ne) __hash__ = new_method_proxy(hash) # List/Tuple/Dictionary methods support __getitem__ = new_method_proxy(operator.getitem) __setitem__ = new_method_proxy(operator.setitem) __delitem__ = new_method_proxy(operator.delitem) __iter__ = new_method_proxy(iter) __len__ = new_method_proxy(len) __contains__ = new_method_proxy(operator.contains) def unpickle_lazyobject(wrapped): """ Used to unpickle lazy objects. Just return its argument, which will be the wrapped object. """ return wrapped ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629488016.0 dynaconf-3.1.7/dynaconf/utils/parse_conf.py0000644000175000017500000002331600000000000022357 0ustar00rochacbrunorochacbrunoimport json import os import re import warnings from functools import wraps from dynaconf.utils import extract_json_objects 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.vendor import toml try: from jinja2 import Environment jinja_env = Environment() for p_method in ("abspath", "realpath", "relpath", "dirname", "basename"): jinja_env.filters[p_method] = getattr(os.path, p_method) except ImportError: # pragma: no cover jinja_env = None true_values = ("t", "true", "enabled", "1", "on", "yes", "True") false_values = ("f", "false", "disabled", "0", "off", "no", "False", "") KV_PATTERN = re.compile(r"([a-zA-Z0-9 ]*=[a-zA-Z0-9\- :]*)") """matches `a=b, c=d, e=f` used on `VALUE='@merge foo=bar'` variables.""" class DynaconfParseError(Exception): """Error to raise when parsing @casts""" class MetaValue: """A Marker to trigger specific actions on `set` and `object_merge`""" _meta_value = True def __init__(self, value, box_settings): self.box_settings = box_settings self.value = parse_conf_data( value, tomlfy=True, box_settings=box_settings ) def __repr__(self): return f"{self.__class__.__name__}({self.value}) on {id(self)}" def unwrap(self): return self.value class Reset(MetaValue): """Triggers an existing key to be reset to its value NOTE: DEPRECATED on v3.0.0 """ _dynaconf_reset = True def __init__(self, value, box_settings): self.box_settings = box_settings self.value = parse_conf_data( value, tomlfy=True, box_settings=self.box_settings ) warnings.warn(f"{self.value} does not need `@reset` anymore.") class Del(MetaValue): """Triggers an existing key to be deleted""" _dynaconf_del = True def unwrap(self): raise ValueError("Del object has no value") class Merge(MetaValue): """Triggers an existing key to be merged""" _dynaconf_merge = True def __init__(self, value, box_settings, unique=False): self.box_settings = box_settings self.value = parse_conf_data( value, tomlfy=True, box_settings=box_settings ) if isinstance(self.value, (int, float, bool)): # @merge 1, @merge 1.1, @merge False self.value = [self.value] elif isinstance(self.value, str): # @merge {"valid": "json"} json_object = list( extract_json_objects( multi_replace( self.value, { ": True": ": true", ":True": ": true", ": False": ": false", ":False": ": false", ": None": ": null", ":None": ": null", }, ) ) ) if len(json_object) == 1: self.value = json_object[0] else: matches = KV_PATTERN.findall(self.value) # a=b, c=d if matches: self.value = { k.strip(): parse_conf_data( v, tomlfy=True, box_settings=box_settings ) for k, v in ( match.strip().split("=") for match in matches ) } elif "," in self.value: # @merge foo,bar self.value = self.value.split(",") else: # @merge foo self.value = [self.value] self.unique = unique class BaseFormatter: def __init__(self, function, token): self.function = function self.token = token def __call__(self, value, **context): return self.function(value, **context) def __str__(self): return str(self.token) def _jinja_formatter(value, **context): if jinja_env is None: # pragma: no cover raise ImportError( "jinja2 must be installed to enable '@jinja' settings in dynaconf" ) return jinja_env.from_string(value).render(**context) class Formatters: """Dynaconf builtin formatters""" python_formatter = BaseFormatter(str.format, "format") jinja_formatter = BaseFormatter(_jinja_formatter, "jinja") class Lazy: """Holds data to format lazily.""" _dynaconf_lazy_format = True def __init__(self, value, formatter=Formatters.python_formatter): self.value = value self.formatter = formatter @property def context(self): """Builds a context for formatting.""" return {"env": os.environ, "this": self.settings} def __call__(self, settings): """LazyValue triggers format lazily.""" self.settings = settings return self.formatter(self.value, **self.context) def __str__(self): """Gives string representation for the object.""" return str(self.value) def __repr__(self): """Give the quoted str representation""" return f"'@{self.formatter} {self.value}'" def _dynaconf_encode(self): """Encodes this object values to be serializable to json""" return f"@{self.formatter} {self.value}" def try_to_encode(value, callback=str): """Tries to encode a value by verifying existence of `_dynaconf_encode`""" try: return value._dynaconf_encode() except (AttributeError, TypeError): return callback(value) def evaluate_lazy_format(f): """Marks a method on Settings instance to lazily evaluate LazyFormat objects upon access.""" @wraps(f) def evaluate(settings, *args, **kwargs): value = f(settings, *args, **kwargs) return recursively_evaluate_lazy_format(value, settings) return evaluate converters = { "@str": str, "@int": int, "@float": float, "@bool": lambda value: str(value).lower() in true_values, "@json": json.loads, "@format": lambda value: Lazy(value), "@jinja": lambda value: Lazy(value, formatter=Formatters.jinja_formatter), # Meta Values to trigger pre assignment actions "@reset": Reset, # @reset is DEPRECATED on v3.0.0 "@del": Del, "@merge": Merge, "@merge_unique": lambda value, box_settings: Merge( value, box_settings, unique=True ), # Special markers to be used as placeholders e.g: in prefilled forms # will always return None when evaluated "@note": lambda value: None, "@comment": lambda value: None, "@null": lambda value: None, "@none": lambda value: None, } def get_converter(converter_key, value, box_settings): converter = converters[converter_key] try: converted_value = converter(value, box_settings=box_settings) except TypeError: converted_value = converter(value) return converted_value 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 def _parse_conf_data(data, tomlfy=False, box_settings=None): """ @int @bool @float @json (for lists and dicts) strings does not need converters export DYNACONF_DEFAULT_THEME='material' export DYNACONF_DEBUG='@bool True' export DYNACONF_DEBUG_TOOLBAR_ENABLED='@bool False' export DYNACONF_PAGINATION_PER_PAGE='@int 20' export DYNACONF_MONGODB_SETTINGS='@json {"DB": "quokka_db"}' export DYNACONF_ALLOWED_EXTENSIONS='@json ["jpg", "png"]' """ # 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 if ( castenabled and data 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) else: value = parse_with_toml(data) if tomlfy else data if isinstance(value, dict): value = DynaBox(value, box_settings=box_settings) return value def parse_conf_data(data, tomlfy=False, box_settings=None): # fix for https://github.com/rochacbruno/dynaconf/issues/595 if isnamedtupleinstance(data): return data # not enforced to not break backwards compatibility with custom loaders 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) for item in data ] if isinstance(data, (dict, DynaBox)): # recursively parse inner dict items _parsed = {} for k, v in data.items(): _parsed[k] = parse_conf_data( v, tomlfy=tomlfy, box_settings=box_settings ) return _parsed # return parsed string value return _parse_conf_data(data, tomlfy=tomlfy, box_settings=box_settings) def unparse_conf_data(value): if isinstance(value, bool): return f"@bool {value}" if isinstance(value, int): return f"@int {value}" if isinstance(value, float): return f"@float {value}" if isinstance(value, (list, dict)): return f"@json {json.dumps(value)}" if isinstance(value, Lazy): return try_to_encode(value) if value is None: return "@none " return value ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631213309.0 dynaconf-3.1.7/dynaconf/validator.py0000644000175000017500000003257600000000000021075 0ustar00rochacbrunorochacbrunofrom __future__ import annotations from collections import defaultdict 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 from dynaconf.utils.functional import empty EQUALITY_ATTRS = ( "names", "must_exist", "when", "condition", "operations", "envs", ) class ValidationError(Exception): pass class Validator: """Validators are conditions attached to settings variables names or patterns:: Validator('MESSAGE', must_exist=True, eq='Hello World') The above ensure MESSAGE is available in default env and is equal to 'Hello World' `names` are a one (or more) names or patterns:: Validator('NAME') Validator('NAME', 'OTHER_NAME', 'EVEN_OTHER') Validator(r'^NAME', r'OTHER./*') The `operations` are:: eq: value == other ne: value != other gt: value > other lt: value < other gte: value >= other lte: value <= other is_type_of: isinstance(value, type) is_in: value in sequence is_not_in: value not in sequence identity: value is other cont: contain value in len_eq: len(value) == other len_ne: len(value) != other len_min: len(value) > other len_max: len(value) < other `env` is which env to be checked, can be a list or default is used. `when` holds a validator and its return decides if validator runs or not:: Validator('NAME', must_exist=True, when=Validator('OTHER', eq=2)) # NAME is required only if OTHER eq to 2 # When the very first thing to be performed when passed. # if no env is passed to `when` it is inherited `must_exist` is alias to `required` requirement. (executed after when):: settings.get(value, empty) returns non empty condition is a callable to be executed and return boolean:: Validator('NAME', condition=lambda x: x == 1) # it is executed before operations. """ default_messages = MappingProxyType( { "must_exist_true": "{name} is required in env {env}", "must_exist_false": "{name} cannot exists in env {env}", "condition": "{name} invalid for {function}({value}) in env {env}", "operations": ( "{name} must {operation} {op_value} " "but it is {value} in env {env}" ), "combined": "combined validators failed {errors}", } ) 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, **operations: Any, ) -> None: # Copy immutable MappingProxyType as a mutable dict self.messages = dict(self.default_messages) if messages: self.messages.update(messages) if when is not None and not isinstance(when, Validator): raise TypeError("when must be Validator instance") if condition is not None and not callable(condition): raise TypeError("condition must be callable") self.names = names self.must_exist = must_exist if must_exist is not None else required self.condition = condition self.when = when self.cast = cast or (lambda value: value) self.operations = operations self.default = default self.description = description self.envs: Optional[Sequence[str]] = None if isinstance(env, str): self.envs = [env] elif isinstance(env, (list, tuple)): self.envs = env def __or__(self, other: Validator) -> CombinedValidator: return OrValidator(self, other, description=self.description) def __and__(self, other: Validator) -> CombinedValidator: return AndValidator(self, other, description=self.description) def __eq__(self, other: object) -> bool: if self is other: return True if type(self).__name__ != type(other).__name__: return False identical_attrs = ( getattr(self, attr) == getattr(other, attr) for attr in EQUALITY_ATTRS ) if all(identical_attrs): return True return False def validate( self, settings: Any, only: Optional[Union[str, Sequence]] = None, exclude: Optional[Union[str, Sequence]] = None, ) -> None: """Raise ValidationError if invalid""" # If only or exclude are not set, this value always passes startswith only = ensure_a_list(only or [""]) if only and not isinstance(only[0], str): raise ValueError("'only' must be a string or list of strings.") exclude = ensure_a_list(exclude) if exclude and not isinstance(exclude[0], str): raise ValueError("'exclude' must be a string or list of strings.") if self.envs is None: self.envs = [settings.current_env] if self.when is not None: try: # inherit env if not defined if self.when.envs is None: self.when.envs = self.envs self.when.validate(settings, only=only, exclude=exclude) except ValidationError: # if when is invalid, return canceling validation flow return # If only using current_env, skip using_env decoration (reload) if ( len(self.envs) == 1 and self.envs[0].upper() == settings.current_env.upper() ): self._validate_items( settings, settings.current_env, only=only, exclude=exclude ) return for env in self.envs: self._validate_items( settings.from_env(env), only=only, exclude=exclude ) def _validate_items( self, settings: Any, env: Optional[str] = None, only: Optional[Union[str, Sequence]] = None, exclude: Optional[Union[str, Sequence]] = None, ) -> None: env = env or settings.current_env for name in self.names: # Skip if only is set and name isn't in the only list if only and not any(name.startswith(sub) for sub in only): continue # Skip if exclude is set and name is in the exclude list if exclude and any(name.startswith(sub) for sub in exclude): continue if self.default is not empty: default_value = ( self.default(settings, self) if callable(self.default) else self.default ) else: default_value = empty value = self.cast(settings.setdefault(name, default_value)) # 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) ) if self.must_exist is False and value is not empty: raise ValidationError( self.messages["must_exist_false"].format( name=name, env=env ) ) if self.must_exist in (False, None) and value is empty: continue # 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, ) ) # 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, ) ) class CombinedValidator(Validator): def __init__( self, validator_a: Validator, validator_b: Validator, *args: Any, **kwargs: Any, ) -> None: """Takes 2 validators and combines the validation""" self.validators = (validator_a, validator_b) super().__init__(*args, **kwargs) for attr in EQUALITY_ATTRS: if not getattr(self, attr, None): value = tuple( getattr(validator, attr) for validator in self.validators ) setattr(self, attr, value) def validate( self, settings: Any, only: Optional[Union[str, Sequence]] = None, exclude: Optional[Union[str, Sequence]] = None, ) -> None: # pragma: no cover raise NotImplementedError( "subclasses OrValidator or AndValidator implements this method" ) class OrValidator(CombinedValidator): """Evaluates on Validator() | Validator()""" def validate( self, settings: Any, only: Optional[Union[str, Sequence]] = None, exclude: Optional[Union[str, Sequence]] = None, ) -> None: """Ensure at least one of the validators are valid""" errors = [] for validator in self.validators: try: validator.validate(settings, only=only, exclude=exclude) 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 ) ) ) class AndValidator(CombinedValidator): """Evaluates on Validator() & Validator()""" def validate( self, settings: Any, only: Optional[Union[str, Sequence]] = None, exclude: Optional[Union[str, Sequence]] = None, ) -> None: """Ensure both the validators are valid""" errors = [] for validator in self.validators: try: validator.validate(settings, only=only, exclude=exclude) 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 ) ) ) class ValidatorList(list): def __init__( self, settings: Any, validators: Optional[Sequence[Validator]] = None, *args: Validator, **kwargs: Any, ) -> None: if isinstance(validators, (list, tuple)): 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 self.settings = settings def register(self, *args: Validator, **kwargs: Validator): validators: List[Validator] = list( chain.from_iterable(kwargs.values()) # type: ignore ) validators.extend(args) for validator in validators: if validator and validator not in self: self.append(validator) def descriptions( self, flat: bool = False ) -> Dict[str, Union[str, List[str]]]: if flat: descriptions: Dict[str, Union[str, List[str]]] = {} else: descriptions = defaultdict(list) for validator in self: for name in validator.names: if isinstance(name, tuple) and len(name) > 0: name = name[0] if flat: descriptions.setdefault(name, validator.description) else: descriptions[name].append( # type: ignore validator.description ) return descriptions def validate( self, only: Optional[Union[str, Sequence]] = None, exclude: Optional[Union[str, Sequence]] = None, ) -> None: for validator in self: validator.validate(self.settings, only=only, exclude=exclude) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1594760737.0 dynaconf-3.1.7/dynaconf/validator_conditions.py0000644000175000017500000000255000000000000023313 0ustar00rochacbrunorochacbruno# pragma: no cover """ Implement basic assertions to be used in assertion action """ def eq(value, other): """Equal""" return value == other def ne(value, other): """Not equal""" return value != other def gt(value, other): """Greater than""" return value > other def lt(value, other): """Lower than""" return value < other def gte(value, other): """Greater than or equal""" return value >= other def lte(value, other): """Lower than or equal""" return value <= other def identity(value, other): """Identity check using ID""" return value is other def is_type_of(value, other): """Type check""" return isinstance(value, other) def is_in(value, other): """Existence""" return value in other def is_not_in(value, other): """Inexistence""" return value not in other def cont(value, other): """Contains""" return other in value def len_eq(value, other): """Length Equal""" return len(value) == other def len_ne(value, other): """Length Not equal""" return len(value) != other def len_min(value, other): """Minimum length""" return len(value) >= other def len_max(value, other): """Maximum lenght""" return len(value) <= other def startswith(value, term): """returns value.startswith(term) result""" return value.startswith(term) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1631217935.1170113 dynaconf-3.1.7/dynaconf/vendor/0000755000175000017500000000000000000000000020016 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1598289371.0 dynaconf-3.1.7/dynaconf/vendor/__init__.py0000644000175000017500000000000000000000000022115 0ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1631217935.1203446 dynaconf-3.1.7/dynaconf/vendor/box/0000755000175000017500000000000000000000000020606 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807553.0 dynaconf-3.1.7/dynaconf/vendor/box/__init__.py0000644000175000017500000000036600000000000022724 0ustar00rochacbrunorochacbruno__author__='Chris Griffith' __version__='4.2.3' from .box import Box from .box_list import BoxList from .config_box import ConfigBox from .shorthand_box import SBox from .exceptions import BoxError,BoxKeyError from .from_file import box_from_file././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807552.0 dynaconf-3.1.7/dynaconf/vendor/box/box.py0000644000175000017500000003321700000000000021756 0ustar00rochacbrunorochacbruno_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='_' _I='utf-8' _H='_box_config' _G=True _F='camel_killer_box' _E='conversion_box' _D='frozen_box' _C='__safe_keys' _B=False _A=None import copy,re,string,warnings from collections.abc import Iterable,Mapping,Callable from keyword import kwlist from pathlib import Path from typing import Any,Union,Tuple,List,Dict from dynaconf.vendor import box from .converters import _to_json,_from_json,_from_toml,_to_toml,_from_yaml,_to_yaml,BOX_PARAMETERS from .exceptions import BoxError,BoxKeyError,BoxTypeError,BoxValueError,BoxWarning __all__=['Box'] _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 _recursive_tuples(iterable,box_class,recreate_tuples=_B,**E): D=recreate_tuples;C=box_class;B=[] for A in iterable: if isinstance(A,dict):B.append(C(A,**E)) elif isinstance(A,list)or D and isinstance(A,tuple):B.append(_recursive_tuples(A,C,D,**E)) else:B.append(A) return tuple(B) 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:] raise BoxError('Could not split box dots properly') def _get_box_config():return{_S:_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') 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 A.__setitem__(D,C) elif isinstance(B[0],Iterable): for (D,C) in B[0]:A.__setitem__(D,C) else:raise BoxValueError('First argument must be mapping or iterable') elif B:raise BoxTypeError(f"Box expected at most 1 argument, got {len(B)}") 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 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.") B.merge_update(A);return B def __hash__(A): if A._box_config[_D]: B=54321 for C in A.items():B^=hash(C) return B raise BoxTypeError('unhashable type: "Box"') def __dir__(B): D=string.ascii_letters+string.digits+_J;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: for E in A: if E not in D:break else:C.add(A) for A in B.keys(): if A not in C: if B._box_config[_E]: A=B._safe_attr(A) if A:C.add(A) return list(C) def get(B,key,default=NO_DEFAULT): 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) 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,list)and not isinstance(A,box.BoxList):return box.BoxList(A) return A return B[C] def copy(A):return Box(super().copy(),**A.__box_config()) def __copy__(A):return Box(super().copy(),**A.__box_config()) def __deepcopy__(A,memodict=_A): B=memodict;E=A._box_config[_D];D=A.__box_config();D[_D]=_B;C=A.__class__(**D);B=B or{};B[id(A)]=C for (F,G) in A.items():C[copy.deepcopy(F,B)]=copy.deepcopy(G,B) C._box_config[_D]=E;return C def __setstate__(A,state):B=state;A._box_config=B[_H];A.__dict__.update(B) def keys(A):return super().keys() 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] 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()) elif isinstance(A,Callable):C=A() elif hasattr(A,'copy'):C=A.copy() else:C=A B.__convert_and_store(item,C);return C def __box_config(C): A={} for (B,D) in C._box_config.copy().items(): if not B.startswith('__'):A[B]=D 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 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 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()) 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()) 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): 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) raise BoxKeyError(str(E)) from _A def __getattr__(A,item): B=item try: try:C=A.__getitem__(B,_ignore_default=_G) except KeyError:C=object.__getattribute__(A,B) except AttributeError as E: if B=='__getstate__':raise BoxKeyError(B) from _A if B==_H:raise BoxError('_box_config key must exist') from _A 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) 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: 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) 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 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) if D in A._box_config[_C]:B=A._box_config[_C][D] 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 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): for D in A: if _camel_killer(B)==D:B=D;break super().__delitem__(B) def __delattr__(A,item): B=item if A._box_config[_D]:raise BoxError(_W) 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) except KeyError as D: if A._box_config[_E]: C=A._safe_attr(B) if C in A._box_config[_C]:A.__delitem__(A._box_config[_C][C]);del A._box_config[_C][C];return raise BoxKeyError(D) def pop(B,key,*C): A=key if C: if len(C)!=1:raise BoxError('pop() takes only one optional argument "default"') try:D=B[A] except KeyError:return C[0] else:del B[A];return D try:D=B[A] except KeyError:raise BoxKeyError('{0}'.format(A)) from _A else:del B[A];return D def clear(A):super().clear();A._box_config[_C].clear() def popitem(A): try:B=next(A.__iter__()) except StopIteration:raise BoxKeyError('Empty box') from _A return B,A.pop(B) def __repr__(A):return f"" def __str__(A):return str(A.to_dict()) def __iter__(A): for B in A.keys():yield B def __reversed__(A): for B in reversed(list(A.keys())):yield B def to_dict(D): A=dict(D) for (C,B) in A.items(): if B is D:A[C]=A elif isinstance(B,Box):A[C]=B.to_dict() elif isinstance(B,box.BoxList):A[C]=B.to_list() return A def update(C,__m=_A,**D): B=__m if B: if hasattr(B,_Z): for A in B:C.__convert_and_store(A,B[A]) else: for (A,E) in B:C.__convert_and_store(A,E) for A in D:C.__convert_and_store(A,D[A]) 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]) if isinstance(v,dict)and not B: v=A.__class__(v,**A.__box_config()) if k in A and isinstance(A[k],dict): if isinstance(A[k],Box):A[k].merge_update(v) else:A[k].update(v) return if isinstance(v,list)and not B:v=box.BoxList(v,**A.__box_config()) A.__setitem__(k,v) if C: if hasattr(C,_Z): for B in C:D(B,C[B]) else: for (B,F) in C:D(B,F) for B in E:D(B,E[B]) def setdefault(B,item,default=_A): C=item;A=default if C in B:return B[C] if isinstance(A,dict):A=B.__class__(A,**B.__box_config()) 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) 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) 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}" 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) 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) @classmethod def from_json(E,json_string=_A,filename=_A,encoding=_I,errors=_N,**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) @classmethod def from_yaml(E,yaml_string=_A,filename=_A,encoding=_I,errors=_N,**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) @classmethod def from_toml(D,toml_string=_A,filename=_A,encoding=_I,errors=_N,**B): C={} for A in B.copy(): if A in BOX_PARAMETERS:C[A]=B.pop(A) E=_from_toml(toml_string=toml_string,filename=filename,encoding=encoding,errors=errors);return D(E,**C)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807552.0 dynaconf-3.1.7/dynaconf/vendor/box/box_list.py0000644000175000017500000001257500000000000023015 0ustar00rochacbrunorochacbruno_H='toml' _G='box_dots' _F='BoxList is frozen' _E='frozen_box' _D=False _C='strict' _B='utf-8' _A=None import copy,re from typing import Iterable,Optional from dynaconf.vendor import box from .converters import _to_yaml,_from_yaml,_to_json,_from_json,_to_toml,_from_toml,_to_csv,_from_csv,BOX_PARAMETERS from .exceptions import BoxError,BoxTypeError,BoxKeyError _list_pos_re=re.compile('\\[(\\d+)\\]') DYNABOX_CLASS=_A def get_dynabox_class_avoiding_circular_import(): global DYNABOX_CLASS if DYNABOX_CLASS is _A:from dynaconf.utils.boxing import DynaBox as A;DYNABOX_CLASS=A return DYNABOX_CLASS class BoxList(list): def __init__(A,iterable=_A,box_class=_A,**C): B=iterable;A.box_class=box_class or get_dynabox_class_avoiding_circular_import();A.box_options=C;A.box_org_ref=A.box_org_ref=id(B)if B else 0 if B: for D in B:A.append(D) if C.get(_E): def E(*A,**B):raise BoxError(_F) for F in ['append','extend','insert','pop','remove','reverse','sort']:A.__setattr__(F,E) def __getitem__(B,item): A=item if B.box_options.get(_G)and isinstance(A,str)and A.startswith('['): C=_list_pos_re.search(A);D=super(BoxList,B).__getitem__(int(C.groups()[0])) if len(C.group())==len(A):return D return D.__getitem__(A[len(C.group()):].lstrip('.')) return super(BoxList,B).__getitem__(A) def __delitem__(A,key): if A.box_options.get(_E):raise BoxError(_F) super(BoxList,A).__delitem__(key) def __setitem__(B,key,value): C=value;A=key if B.box_options.get(_E):raise BoxError(_F) if B.box_options.get(_G)and isinstance(A,str)and A.startswith('['): D=_list_pos_re.search(A);E=int(D.groups()[0]) if len(D.group())==len(A):return super(BoxList,B).__setitem__(E,C) 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' 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) return _D def append(A,p_object): B=p_object if isinstance(B,dict)and not A._is_intact_type(B): try:B=A.box_class(B,**A.box_options) except AttributeError as C: if'box_class'in A.__dict__:raise BoxKeyError(C) elif isinstance(B,list)and not A._is_intact_type(B): try:B=A if id(B)==A.box_org_ref else BoxList(B,**A.box_options) except AttributeError as C: if'box_org_ref'in A.__dict__:raise BoxKeyError(C) super(BoxList,A).append(B) def extend(A,iterable): for B in iterable:A.append(B) def insert(B,index,p_object): A=p_object if isinstance(A,dict)and not B._is_intact_type(A):A=B.box_class(A,**B.box_options) elif isinstance(A,list)and not B._is_intact_type(A):A=B if id(A)==B.box_org_ref else BoxList(A) super(BoxList,B).insert(index,A) def __repr__(A):return f"" def __str__(A):return str(A.to_list()) def __copy__(A):return BoxList((B for B in A),A.box_class,**A.box_options) def __deepcopy__(B,memo=_A): A=memo;C=B.__class__();A=A or{};A[id(B)]=C for D in B:C.append(copy.deepcopy(D,memo=A)) return C def __hash__(A): if A.box_options.get(_E):B=98765;B^=hash(tuple(A));return B raise BoxTypeError("unhashable type: 'BoxList'") def to_list(C): A=[] for B in C: if B is C:A.append(A) elif isinstance(B,box.Box):A.append(B.to_dict()) elif isinstance(B,BoxList):A.append(B.to_list()) else:A.append(B) return A def to_json(D,filename=_A,encoding=_B,errors=_C,multiline=_D,**E): C=errors;B=encoding;A=filename if A and multiline: F=[_to_json(A,filename=_D,encoding=B,errors=C,**E)for A in D] with open(A,'w',encoding=B,errors=C)as G:G.write('\n'.join(F)) else:return _to_json(D.to_list(),filename=A,encoding=B,errors=C,**E) @classmethod def from_json(E,json_string=_A,filename=_A,encoding=_B,errors=_C,multiline=_D,**A): D={} for B in list(A.keys()): if B in BOX_PARAMETERS:D[B]=A.pop(B) C=_from_json(json_string,filename=filename,encoding=encoding,errors=errors,multiline=multiline,**A) if not isinstance(C,list):raise BoxError(f"json data not returned as a list, but rather a {type(C).__name__}") return E(C,**D) def to_yaml(A,filename=_A,default_flow_style=_D,encoding=_B,errors=_C,**B):return _to_yaml(A.to_list(),filename=filename,default_flow_style=default_flow_style,encoding=encoding,errors=errors,**B) @classmethod def from_yaml(E,yaml_string=_A,filename=_A,encoding=_B,errors=_C,**A): D={} for B in list(A.keys()): 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,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) @classmethod def from_toml(F,toml_string=_A,filename=_A,key_name=_H,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) E=_from_toml(toml_string=toml_string,filename=filename,encoding=encoding,errors=errors) if A not in E:raise BoxError(f"{A} was not found.") return F(E[A],**D) def to_csv(A,filename,encoding=_B,errors=_C):_to_csv(A,filename=filename,encoding=encoding,errors=errors) @classmethod def from_csv(A,filename,encoding=_B,errors=_C):return A(_from_csv(filename=filename,encoding=encoding,errors=errors))././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807552.0 dynaconf-3.1.7/dynaconf/vendor/box/config_box.py0000644000175000017500000000320100000000000023271 0ustar00rochacbrunorochacbruno_H='getint' _G='getfloat' _F='getboolean' _E='list' _D='float' _C='int' _B='bool' _A=None from dynaconf.vendor.box.box import Box class ConfigBox(Box): _protected_keys=dir(Box)+[_B,_C,_D,_E,_F,_G,_H] 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: if B is not _A:return B raise D 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 def int(C,item,default=_A): B=default;A=item try:A=C.__getattr__(A) except AttributeError as D: if B is not _A:return B raise D return int(A) def float(C,item,default=_A): B=default;A=item try:A=C.__getattr__(A) except AttributeError as D: if B is not _A:return B raise D return float(A) def list(E,item,default=_A,spliter=',',strip=True,mod=_A): C=strip;B=default;A=item try:A=E.__getattr__(A) except AttributeError as F: if B is not _A:return B raise F if C:A=A.lstrip('[').rstrip(']') D=[B.strip()if C else B for B in A.split(spliter)] if mod:return list(map(mod,D)) return D def getboolean(A,item,default=_A):return A.bool(item,default) def getint(A,item,default=_A):return A.int(item,default) def getfloat(A,item,default=_A):return A.float(item,default) def __repr__(A):return ''.format(str(A.to_dict())) def copy(A):return ConfigBox(super().copy()) def __copy__(A):return ConfigBox(super().copy())././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807552.0 dynaconf-3.1.7/dynaconf/vendor/box/converters.py0000644000175000017500000000613500000000000023357 0ustar00rochacbrunorochacbruno_G='r' _F='w' _E=False _D=True _C='strict' _B='utf-8' _A=None 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 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) if create: try:B.touch(exist_ok=_D) except OSError as C:raise BoxError(f"Could not create file {A} - {C}") else:return if not B.exists():raise BoxError(f'File "{A}" does not exist') if not B.is_file():raise BoxError(f"{A} is not a file") 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)) 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: 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) else:raise BoxError('from_json requires a string or filename') return C 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) 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 if B: _exists(B) with open(B,_G,encoding=encoding,errors=errors)as E:D=yaml.load(E,**A) elif C:D=yaml.load(C,**A) else:raise BoxError('from_yaml requires a string or filename') return D 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) 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) elif B:C=toml.loads(B) else:raise BoxError('from_toml requires a string or filename') return C def _to_csv(box_list,filename,encoding=_B,errors=_C): B=filename;A=box_list;C=list(A[0].keys()) for E in A: 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: 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]././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807553.0 dynaconf-3.1.7/dynaconf/vendor/box/exceptions.py0000644000175000017500000000030500000000000023337 0ustar00rochacbrunorochacbrunoclass BoxError(Exception):0 class BoxKeyError(BoxError,KeyError,AttributeError):0 class BoxTypeError(BoxError,TypeError):0 class BoxValueError(BoxError,ValueError):0 class BoxWarning(UserWarning):0././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807553.0 dynaconf-3.1.7/dynaconf/vendor/box/from_file.py0000644000175000017500000000266200000000000023130 0ustar00rochacbrunorochacbrunofrom json import JSONDecodeError from pathlib import Path from typing import Union from dynaconf.vendor.toml import TomlDecodeError from dynaconf.vendor.ruamel.yaml import YAMLError from .exceptions import BoxError from .box import Box from .box_list import BoxList __all__=['box_from_file'] def _to_json(data): try:return Box.from_json(data) except JSONDecodeError:raise BoxError('File is not JSON as expected') except BoxError:return BoxList.from_json(data) def _to_yaml(data): try:return Box.from_yaml(data) except YAMLError:raise BoxError('File is not YAML as expected') 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') 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) if not A.exists():raise BoxError(f'file "{A}" does not exist') B=A.read_text(encoding=encoding,errors=errors) if C: if C.lower()=='json':return _to_json(B) if C.lower()=='yaml':return _to_yaml(B) if C.lower()=='toml':return _to_toml(B) raise BoxError(f'"{C}" is an unknown type, please use either toml, yaml or json') if A.suffix in('.json','.jsn'):return _to_json(B) if A.suffix in('.yaml','.yml'):return _to_yaml(B) if A.suffix in('.tml','.toml'):return _to_toml(B) raise BoxError(f"Could not determine file type based off extension, please provide file_type")././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807553.0 dynaconf-3.1.7/dynaconf/vendor/box/shorthand_box.py0000644000175000017500000000105000000000000024016 0ustar00rochacbrunorochacbrunofrom 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'] @property def dict(self):return self.to_dict() @property def json(self):return self.to_json() @property def yaml(self):return self.to_yaml() @property def toml(self):return self.to_toml() def __repr__(A):return ''.format(str(A.to_dict())) def copy(A):return SBox(super(SBox,A).copy()) def __copy__(A):return SBox(super(SBox,A).copy())././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1631217935.123678 dynaconf-3.1.7/dynaconf/vendor/click/0000755000175000017500000000000000000000000021103 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807554.0 dynaconf-3.1.7/dynaconf/vendor/click/__init__.py0000644000175000017500000000366300000000000023224 0ustar00rochacbrunorochacbrunofrom .core import Argument,BaseCommand,Command,CommandCollection,Context,Group,MultiCommand,Option,Parameter from .decorators import argument from .decorators import command from .decorators import confirmation_option from .decorators import group from .decorators import help_option from .decorators import make_pass_decorator from .decorators import option from .decorators import pass_context from .decorators import pass_obj from .decorators import password_option from .decorators import version_option from .exceptions import Abort from .exceptions import BadArgumentUsage from .exceptions import BadOptionUsage from .exceptions import BadParameter from .exceptions import ClickException from .exceptions import FileError from .exceptions import MissingParameter from .exceptions import NoSuchOption from .exceptions import UsageError from .formatting import HelpFormatter from .formatting import wrap_text from .globals import get_current_context from .parser import OptionParser from .termui import clear from .termui import confirm from .termui import echo_via_pager from .termui import edit from .termui import get_terminal_size from .termui import getchar from .termui import launch from .termui import pause from .termui import progressbar from .termui import prompt from .termui import secho from .termui import style from .termui import unstyle from .types import BOOL from .types import Choice from .types import DateTime from .types import File from .types import FLOAT from .types import FloatRange from .types import INT from .types import IntRange from .types import ParamType from .types import Path from .types import STRING from .types import Tuple from .types import UNPROCESSED from .types import UUID from .utils import echo from .utils import format_filename from .utils import get_app_dir from .utils import get_binary_stream from .utils import get_os_args from .utils import get_text_stream from .utils import open_file __version__='8.0.0.dev'././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807553.0 dynaconf-3.1.7/dynaconf/vendor/click/_bashcomplete.py0000644000175000017500000001441700000000000024271 0ustar00rochacbrunorochacbruno_I='COMP_CWORD' _H='COMP_WORDS' _G='fish' _F='zsh' _E='bash' _D='_' _C=False _B=None _A=True import copy,os,re from collections import abc from .core import Argument from .core import MultiCommand from .core import Option from .parser import split_arg_string from .types import Choice from .utils import echo 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} _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 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: if isinstance(A.command,MultiCommand): if not A.command.chain: E,C,B=A.command.resolve_command(A,B) if C is _B:return A A=C.make_context(E,B,parent=A,resilient_parsing=_A);B=A.protected_args+A.args else: while B: E,C,B=A.command.resolve_command(A,B) if C is _B:return A D=C.make_context(E,B,parent=A,allow_extra_args=_A,allow_interspersed_args=_C,resilient_parsing=_A);B=D.args A=D;B=D.protected_args+D.args else:break return A def start_of_option(param_str):A=param_str;return A and A[:1]=='-' def is_incomplete_option(all_args,cmd_param): A=cmd_param if not isinstance(A,Option):return _C if A.is_flag:return _C B=_B for (D,C) in enumerate(reversed([A for A in all_args if A!=WORDBREAK])): if D+1>A.nargs:break if start_of_option(C):B=C return _A if B and B in A.opts else _C def is_incomplete_argument(current_params,cmd_param): A=cmd_param if not isinstance(A,Argument):return _C B=current_params[A.name] if B is _B:return _A if A.nargs==-1:return _A if isinstance(B,abc.Iterable)and A.nargs>1 and len(B)0:return f"{A}d {E:02}:{D:02}:{C:02}" else:return f"{E:02}:{D:02}:{C:02}" return'' def format_pos(A): B=str(A.pos) if A.length_known:B+=f"/{A.length}" return B def format_pct(A):return f"{int(A.pct*100): 4}%"[1:] def format_bar(A): if A.length_known:C=int(A.pct*A.width);B=A.fill_char*C;B+=A.empty_char*(A.width-C) elif A.finished:B=A.fill_char*A.width else: B=list(A.empty_char*(A.width or 1)) if A.time_per_iteration!=0:B[int((math.cos(A.pos*A.time_per_iteration)/2.0+0.5)*A.width)]=A.fill_char B=''.join(B) return B def format_progress_line(A): C=A.show_percent;B=[] if A.length_known and C is _A:C=not A.show_pos if A.show_pos:B.append(A.format_pos()) if C:B.append(A.format_pct()) if A.show_eta and A.eta_known and not A.finished:B.append(A.format_eta()) if A.item_show_func is not _A: D=A.item_show_func(A.current_item) if D is not _A:B.append(D) return (A.bar_template%{'label':A.label,'bar':A.format_bar(),'info':A.info_sep.join(B)}).rstrip() def render_progress(A): from .termui import get_terminal_size as G if A.is_hidden:return 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=A.length:A.finished=_B if time.time()-A.last_eta<1.0:return A.last_eta=time.time() if A.pos:B=(time.time()-A.start)/A.pos else:B=time.time()-A.start A.avg=A.avg[-6:]+[B];A.eta_known=A.length_known def update(A,n_steps,current_item=_A): B=current_item;A.make_step(n_steps) if B is not _A:A.current_item=B 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 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() if not isatty(sys.stdin)or not isatty(C):return _nullpager(C,A,B) D=(os.environ.get('PAGER',_A)or'').strip() if D: if WIN:return _tempfilepager(A,D,B) 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) try: if hasattr(os,H)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 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) try: for D in generator: if not A:D=strip_ansi(D) B.stdin.write(D.encode(H,_H)) except (OSError,KeyboardInterrupt):pass else:B.stdin.close() while _B: try:B.wait() except KeyboardInterrupt:pass else:break def _tempfilepager(generator,cmd,color): import tempfile as C;A=C.mktemp();B=''.join(generator) if not color:B=strip_ansi(B) D=get_best_encoding(sys.stdout) with open_stream(A,'wb')[0]as E:E.write(B.encode(D)) try:os.system(f'{cmd} "{A}"') finally:os.unlink(A) def _nullpager(stream,generator,color): for A in generator: if not color:A=strip_ansi(A) stream.write(A) class Editor: def __init__(A,editor=_A,env=_A,require_save=_B,extension='.txt'):A.editor=editor;A.env=env;A.require_save=require_save;A.extension=extension def get_editor(A): if A.editor is not _A:return A.editor for D in ('VISUAL','EDITOR'): B=os.environ.get(D) if B:return B if WIN:return'notepad' for C in ('sensible-editor','vim','nano'): if os.system(f"which {C} >/dev/null 2>&1")==0:return C return'vi' def edit_file(A,filename): import subprocess as D;B=A.get_editor() if A.env:C=os.environ.copy();C.update(A.env) else:C=_A try: E=D.Popen(f'{B} "{filename}"',env=C,shell=_B);F=E.wait() 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] if not E and A and not A.endswith(_D):A+=_D I,B=H.mkstemp(prefix='editor-',suffix=D.extension) try: if not E: if WIN:F=K;A=A.replace(_D,L) 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=open(B,'rb') try:G=C.read() finally:C.close() if E:return G else:return G.decode(K).replace(L,_D) finally:os.unlink(B) def open_url(url,wait=_C,locate=_C): F='"';D=locate;C=wait;A=url;import subprocess as G def E(url): A=url;import urllib as B if A.startswith('file://'):A=B.unquote(A[7:]) return A if sys.platform=='darwin': B=['open'] if C:B.append('-W') if D:B.append('-R') B.append(E(A));H=open('/dev/null','w') try:return G.Popen(B,stderr=H).wait() finally:H.close() elif WIN: if D:A=E(A.replace(F,''));B=f'explorer /select,"{A}"' else:A=A.replace(F,'');C='/WAIT'if C else'';B=f'start {C} "" "{A}"' return os.system(B) elif CYGWIN: if D:A=os.path.dirname(E(A).replace(F,''));B=f'cygstart "{A}"' else:A=A.replace(F,'');C='-w'if C else'';B=f'cygstart {C} "{A}"' return os.system(B) try: if D:A=os.path.dirname(E(A))or'.' else:A=E(A) I=G.Popen(['xdg-open',A]) if C:return I.wait() return 0 except OSError: if A.startswith(('http://','https://'))and not D and not C:import webbrowser as J;J.open(A);return 0 return 1 def _translate_ch_to_exc(ch): if ch=='\x03':raise KeyboardInterrupt() if ch=='\x04'and not WIN:raise EOFError() if ch=='\x1a'and WIN:raise EOFError() if WIN: import msvcrt @contextlib.contextmanager def raw_terminal():yield def getchar(echo): if echo:B=msvcrt.getwche else:B=msvcrt.getwch A=B() if A in('\x00','à'):A+=B() _translate_ch_to_exc(A);return A else: import tty,termios @contextlib.contextmanager def raw_terminal(): if not isatty(sys.stdin):B=open('/dev/tty');A=B.fileno() else:A=sys.stdin.fileno();B=_A try: C=termios.tcgetattr(A) try:tty.setraw(A);yield A finally: termios.tcsetattr(A,termios.TCSADRAIN,C);sys.stdout.flush() if B is not _A:B.close() 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) if echo and isatty(sys.stdout):sys.stdout.write(A) _translate_ch_to_exc(A);return A././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807555.0 dynaconf-3.1.7/dynaconf/vendor/click/_textwrap.py0000644000175000017500000000130000000000000023464 0ustar00rochacbrunorochacbrunoimport textwrap from contextlib import contextmanager class TextWrapper(textwrap.TextWrapper): def _handle_long_word(E,reversed_chunks,cur_line,cur_len,width): B=cur_line;A=reversed_chunks;C=max(width-cur_len,1) if E.break_long_words:D=A[-1];F=D[:C];G=D[C:];B.append(F);A[-1]=G elif not B:B.append(A.pop()) @contextmanager def extra_indent(self,indent): B=indent;A=self;C=A.initial_indent;D=A.subsequent_indent;A.initial_indent+=B;A.subsequent_indent+=B try:yield finally:A.initial_indent=C;A.subsequent_indent=D def indent_only(A,text): B=[] for (D,E) in enumerate(text.splitlines()): C=A.initial_indent if D>0:C=A.subsequent_indent B.append(f"{C}{E}") return '\n'.join(B)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807556.0 dynaconf-3.1.7/dynaconf/vendor/click/_unicodefun.py0000644000175000017500000000317300000000000023757 0ustar00rochacbrunorochacbrunoimport 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 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.add(A) if A.lower()in('c.utf8','c.utf-8'):H=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' 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 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" 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}")././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807556.0 dynaconf-3.1.7/dynaconf/vendor/click/_winconsole.py0000644000175000017500000001134100000000000023774 0ustar00rochacbrunorochacbruno_E=False _D='strict' _C='utf-16-le' _B=True _A=None import ctypes,io,time from ctypes import byref,c_char,c_char_p,c_int,c_ssize_t,c_ulong,c_void_p,POINTER,py_object,windll,WINFUNCTYPE from ctypes.wintypes import DWORD from ctypes.wintypes import HANDLE from ctypes.wintypes import LPCWSTR from ctypes.wintypes import LPWSTR import msvcrt from ._compat import _NonClosingTextIOWrapper try:from ctypes import pythonapi except ImportError:pythonapi=_A else:PyObject_GetBuffer=pythonapi.PyObject_GetBuffer;PyBuffer_Release=pythonapi.PyBuffer_Release c_ssize_p=POINTER(c_ssize_t) kernel32=windll.kernel32 GetStdHandle=kernel32.GetStdHandle ReadConsoleW=kernel32.ReadConsoleW WriteConsoleW=kernel32.WriteConsoleW GetConsoleMode=kernel32.GetConsoleMode GetLastError=kernel32.GetLastError GetCommandLineW=WINFUNCTYPE(LPWSTR)(('GetCommandLineW',windll.kernel32)) CommandLineToArgvW=WINFUNCTYPE(POINTER(LPWSTR),LPCWSTR,POINTER(c_int))(('CommandLineToArgvW',windll.shell32)) LocalFree=WINFUNCTYPE(ctypes.c_void_p,ctypes.c_void_p)(('LocalFree',windll.kernel32)) STDIN_HANDLE=GetStdHandle(-10) STDOUT_HANDLE=GetStdHandle(-11) STDERR_HANDLE=GetStdHandle(-12) PyBUF_SIMPLE=0 PyBUF_WRITABLE=1 ERROR_SUCCESS=0 ERROR_NOT_ENOUGH_MEMORY=8 ERROR_OPERATION_ABORTED=995 STDIN_FILENO=0 STDOUT_FILENO=1 STDERR_FILENO=2 EOF=b'\x1a' MAX_BYTES_WRITTEN=32767 class Py_buffer(ctypes.Structure):_fields_=[('buf',c_void_p),('obj',py_object),('len',c_ssize_t),('itemsize',c_ssize_t),('readonly',c_int),('ndim',c_int),('format',c_char_p),('shape',c_ssize_p),('strides',c_ssize_p),('suboffsets',c_ssize_p),('internal',c_void_p)] if pythonapi is _A:get_buffer=_A else: def get_buffer(obj,writable=_E): A=Py_buffer();B=PyBUF_WRITABLE if writable else PyBUF_SIMPLE;PyObject_GetBuffer(py_object(obj),byref(A),B) try:C=c_char*A.len;return C.from_address(A.buf) finally:PyBuffer_Release(byref(A)) class _WindowsConsoleRawIOBase(io.RawIOBase): def __init__(A,handle):A.handle=handle def isatty(A):io.RawIOBase.isatty(A);return _B class _WindowsConsoleReader(_WindowsConsoleRawIOBase): def readable(A):return _B def readinto(D,b): A=len(b) if not A:return 0 elif A%2:raise ValueError('cannot read odd number of bytes from UTF-16-LE encoded console') B=get_buffer(b,writable=_B);E=A//2;C=c_ulong();F=ReadConsoleW(HANDLE(D.handle),B,E,byref(C),_A) if GetLastError()==ERROR_OPERATION_ABORTED:time.sleep(0.1) if not F:raise OSError(f"Windows error: {GetLastError()}") if B[0]==EOF:return 0 return 2*C.value class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): def writable(A):return _B @staticmethod def _get_error_message(errno): A=errno if A==ERROR_SUCCESS:return'ERROR_SUCCESS' elif A==ERROR_NOT_ENOUGH_MEMORY:return'ERROR_NOT_ENOUGH_MEMORY' return f"Windows error {A}" def write(A,b): B=len(b);E=get_buffer(b);F=min(B,MAX_BYTES_WRITTEN)//2;C=c_ulong();WriteConsoleW(HANDLE(A.handle),E,F,byref(C),_A);D=2*C.value if D==0 and B>0:raise OSError(A._get_error_message(GetLastError())) return D class ConsoleStream: def __init__(A,text_stream,byte_stream):A._text_stream=text_stream;A.buffer=byte_stream @property def name(self):return self.buffer.name def write(A,x): if isinstance(x,str):return A._text_stream.write(x) try:A.flush() except Exception:pass return A.buffer.write(x) def writelines(A,lines): for B in lines:A.write(B) def __getattr__(A,name):return getattr(A._text_stream,name) def isatty(A):return A.buffer.isatty() def __repr__(A):return f"" class WindowsChunkedWriter: def __init__(A,wrapped):A.__wrapped=wrapped def __getattr__(A,name):return getattr(A.__wrapped,name) def write(D,text): B=len(text);A=0 while A" def get_usage(A,ctx):raise NotImplementedError('Base commands cannot get usage') def get_help(A,ctx):raise NotImplementedError('Base commands cannot get help') def make_context(A,info_name,args,parent=_A,**B): for (D,E) in A.context_settings.items(): if D not in B:B[D]=E C=Context(A,info_name=info_name,parent=parent,**B) with C.scope(cleanup=_B):A.parse_args(C,args) return C def parse_args(A,ctx,args):raise NotImplementedError('Base commands do not know how to parse arguments.') def invoke(A,ctx):raise NotImplementedError('Base commands are not invokable by default') def main(E,args=_A,prog_name=_A,complete_var=_A,standalone_mode=_C,**G): D=standalone_mode;C=prog_name;B=args;_verify_python_env() if B is _A:B=sys.argv[1:] else:B=list(B) if C is _A:C=make_str(os.path.basename(sys.argv[0]if sys.argv else __file__)) _bashcomplete(E,C,complete_var) try: try: with E.make_context(C,B,**G)as F: H=E.invoke(F) if not D:return H F.exit() except (EOFError,KeyboardInterrupt):echo(file=sys.stderr);raise Abort() except ClickException as A: if not D:raise A.show();sys.exit(A.exit_code) except OSError as A: if A.errno==errno.EPIPE:sys.stdout=PacifyFlushWrapper(sys.stdout);sys.stderr=PacifyFlushWrapper(sys.stderr);sys.exit(1) else:raise except Exit as A: if D:sys.exit(A.exit_code) else:return A.exit_code except Abort: if not D:raise echo('Aborted!',file=sys.stderr);sys.exit(1) 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[] if help and B in help:help=help.split(B,1)[0] A.help=help;A.epilog=epilog;A.options_metavar=options_metavar;A.short_help=short_help;A.add_help_option=add_help_option;A.no_args_is_help=no_args_is_help;A.hidden=hidden;A.deprecated=deprecated def __repr__(A):return f"<{A.__class__.__name__} {A.name}>" def get_usage(B,ctx):A=ctx.make_formatter();B.format_usage(ctx,A);return A.getvalue().rstrip('\n') def get_params(B,ctx): A=B.params;C=B.get_help_option(ctx) if C is not _A:A=A+[C] return A def format_usage(A,ctx,formatter):B=A.collect_usage_pieces(ctx);formatter.write_usage(ctx.command_path,' '.join(B)) def collect_usage_pieces(A,ctx): B=[A.options_metavar] for C in A.get_params(ctx):B.extend(C.get_usage_pieces(ctx)) return B def get_help_option_names(C,ctx): A=set(ctx.help_option_names) for B in C.params:A.difference_update(B.opts);A.difference_update(B.secondary_opts) return A def get_help_option(A,ctx): B=A.get_help_option_names(ctx) if not B or not A.add_help_option:return def C(ctx,param,value): A=ctx if value and not A.resilient_parsing:echo(A.get_help(),color=A.color);A.exit() return Option(B,is_flag=_C,is_eager=_C,expose_value=_B,callback=C,help='Show this message and exit.') def make_parser(C,ctx): A=ctx;B=OptionParser(A) for D in C.get_params(A):D.add_to_parser(B,A) return B def get_help(B,ctx):A=ctx.make_formatter();B.format_help(ctx,A);return A.getvalue().rstrip('\n') def get_short_help_str(A,limit=45):return A.short_help or A.help and make_default_short_help(A.help,limit)or'' def format_help(A,ctx,formatter):C=formatter;B=ctx;A.format_usage(B,C);A.format_help_text(B,C);A.format_options(B,C);A.format_epilog(B,C) def format_help_text(B,ctx,formatter): A=formatter if B.help: A.write_paragraph() with A.indentation(): C=B.help if B.deprecated:C+=DEPRECATED_HELP_NOTICE A.write_text(C) elif B.deprecated: A.write_paragraph() with A.indentation():A.write_text(DEPRECATED_HELP_NOTICE) def format_options(D,ctx,formatter): B=formatter;A=[] for E in D.get_params(ctx): C=E.get_help_record(ctx) if C is not _A:A.append(C) if A: with B.section('Options'):B.write_dl(A) def format_epilog(B,ctx,formatter): A=formatter if B.epilog: A.write_paragraph() with A.indentation():A.write_text(B.epilog) def parse_args(C,ctx,args): B=args;A=ctx if not B and C.no_args_is_help and not A.resilient_parsing:echo(A.get_help(),color=A.color);A.exit() D=C.make_parser(A);E,B,F=D.parse_args(args=B) for G in iter_params_for_processing(F,C.get_params(A)):H,B=G.handle_parse_result(A,E,B) if B and not A.allow_extra_args and not A.resilient_parsing:A.fail(f"Got unexpected extra argument{'s'if len(B)!=1 else''} ({' '.join(map(make_str,B))})") A.args=B;return B def invoke(A,ctx): _maybe_show_deprecated_notice(A) if A.callback is not _A:return ctx.invoke(A.callback,**ctx.params) class MultiCommand(Command): allow_extra_args=_C;allow_interspersed_args=_B def __init__(A,name=_A,invoke_without_command=_B,no_args_is_help=_A,subcommand_metavar=_A,chain=_B,result_callback=_A,**G): E=chain;D=invoke_without_command;C=no_args_is_help;B=subcommand_metavar;Command.__init__(A,name,**G) if C is _A:C=not D A.no_args_is_help=C;A.invoke_without_command=D if B is _A: if E:B=SUBCOMMANDS_METAVAR else:B=SUBCOMMAND_METAVAR A.subcommand_metavar=B;A.chain=E;A.result_callback=result_callback if A.chain: for F in A.params: if isinstance(F,Argument)and not F.required:raise RuntimeError('Multi commands in chain mode cannot have optional arguments.') def collect_usage_pieces(A,ctx):B=Command.collect_usage_pieces(A,ctx);B.append(A.subcommand_metavar);return B def format_options(A,ctx,formatter):B=formatter;Command.format_options(A,ctx,B);A.format_commands(ctx,B) def resultcallback(A,replace=_B): 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) A.result_callback=D=update_wrapper(C,f);return D return B def format_commands(F,ctx,formatter): D=formatter;B=[] for C in F.list_commands(ctx): A=F.get_command(ctx,C) if A is _A:continue if A.hidden:continue B.append((C,A)) if len(B): G=D.width-6-max((len(A[0])for A in B));E=[] for (C,A) in B:help=A.get_short_help_str(G);E.append((C,help)) if E: with D.section('Commands'):D.write_dl(E) def parse_args(C,ctx,args): A=ctx if not args and C.no_args_is_help and not A.resilient_parsing:echo(A.get_help(),color=A.color);A.exit() B=Command.parse_args(C,A,args) if C.chain:A.protected_args=B;A.args=[] elif B:A.protected_args,A.args=B[:1],B[1:] return A.args def invoke(B,ctx): A=ctx def F(value): C=value if B.result_callback is not _A:C=A.invoke(B.result_callback,C,**A.params) return C if not A.protected_args: if B.invoke_without_command: if not B.chain:return Command.invoke(B,A) with A:Command.invoke(B,A);return F([]) A.fail('Missing command.') D=A.protected_args+A.args;A.args=[];A.protected_args=[] if not B.chain: with A: E,G,D=B.resolve_command(A,D);A.invoked_subcommand=E;Command.invoke(B,A);C=G.make_context(E,D,parent=A) with C:return F(C.command.invoke(C)) with A: A.invoked_subcommand='*'if D else _A;Command.invoke(B,A);H=[] while D:E,G,D=B.resolve_command(A,D);C=G.make_context(E,D,parent=A,allow_extra_args=_C,allow_interspersed_args=_B);H.append(C);D,C.args=C.args,[] I=[] for C in H: with C:I.append(C.command.invoke(C)) return F(I) def resolve_command(D,ctx,args): A=ctx;B=make_str(args[0]);E=B;C=D.get_command(A,B) if C is _A and A.token_normalize_func is not _A:B=A.token_normalize_func(B);C=D.get_command(A,B) if C is _A and not A.resilient_parsing: if split_opt(B)[0]:D.parse_args(A,A.args) A.fail(f"No such command '{E}'.") return B,C,args[1:] def get_command(A,ctx,cmd_name):raise NotImplementedError() def list_commands(A,ctx):return[] class Group(MultiCommand): def __init__(A,name=_A,commands=_A,**B):MultiCommand.__init__(A,name,**B);A.commands=commands or{} def add_command(C,cmd,name=_A): B=cmd;A=name;A=A or B.name if A is _A:raise TypeError('Command has no name.') _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 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 return A def get_command(A,ctx,cmd_name):return A.commands.get(cmd_name) def list_commands(A,ctx):return sorted(A.commands) class CommandCollection(MultiCommand): def __init__(A,name=_A,sources=_A,**B):MultiCommand.__init__(A,name,**B);A.sources=sources or[] def add_source(A,multi_cmd):A.sources.append(multi_cmd) def get_command(A,ctx,cmd_name): C=cmd_name for D in A.sources: B=D.get_command(ctx,C) if B is not _A: if A.chain:_check_multicommand(A,C,B) return B def list_commands(B,ctx): A=set() for C in B.sources:A.update(C.list_commands(ctx)) return sorted(A) class Parameter: param_type_name='parameter' def __init__(A,param_decls=_A,type=_A,required=_B,default=_A,callback=_A,nargs=_A,metavar=_A,expose_value=_C,is_eager=_B,envvar=_A,autocompletion=_A): D=expose_value;C=default;B=nargs;A.name,A.opts,A.secondary_opts=A._parse_decls(param_decls or(),D);A.type=convert_type(type,C) if B is _A: if A.type.is_composite:B=A.type.arity else:B=1 A.required=required;A.callback=callback;A.nargs=B;A.multiple=_B;A.expose_value=D;A.default=C;A.is_eager=is_eager;A.metavar=metavar;A.envvar=envvar;A.autocompletion=autocompletion def __repr__(A):return f"<{A.__class__.__name__} {A.name}>" @property def human_readable_name(self):return self.name def make_metavar(A): 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 return B def get_default(A,ctx): if callable(A.default):B=A.default() else:B=A.default return A.type_cast_value(ctx,B) def add_to_parser(A,parser,ctx):0 def consume_value(B,ctx,opts): C=ctx;A=opts.get(B.name);D=ParameterSource.COMMANDLINE if A is _A:A=B.value_from_envvar(C);D=ParameterSource.ENVIRONMENT if A is _A:A=C.lookup_default(B.name);D=ParameterSource.DEFAULT_MAP if A is not _A:C.set_parameter_source(B.name,D) return A def type_cast_value(A,ctx,value): C=value;B=ctx if A.type.is_composite: if A.nargs<=1:raise TypeError(f"Attempted to invoke composite type but nargs has been set to {A.nargs}. This is not supported; nargs needs to be set to a fixed value > 1.") if A.multiple:return tuple((A.type(D or(),A,B)for D in C or())) return A.type(C or(),A,B) def D(value,level): E=level;C=value if E==0:return A.type(C,A,B) return tuple((D(A,E-1)for A in C or())) return D(C,(A.nargs!=1)+bool(A.multiple)) def process_value(B,ctx,value): A=value if A is not _A:return B.type_cast_value(ctx,A) def value_is_missing(A,value): B=value if B is _A:return _C if(A.nargs!=1 or A.multiple)and B==():return _C return _B def full_process_value(B,ctx,value): C=ctx;A=value;A=B.process_value(C,A) if A is _A and not C.resilient_parsing: A=B.get_default(C) if A is not _A:C.set_parameter_source(B.name,ParameterSource.DEFAULT) if B.required and B.value_is_missing(A):raise MissingParameter(ctx=C,param=B) return A def resolve_envvar_value(B,ctx): if B.envvar is _A:return if isinstance(B.envvar,(tuple,list)): for C in B.envvar: A=os.environ.get(C) if A is not _A:return A else: A=os.environ.get(B.envvar) if A!='':return A def value_from_envvar(B,ctx): A=B.resolve_envvar_value(ctx) if A is not _A and B.nargs!=1:A=B.type.split_envvar_value(A) return A def handle_parse_result(A,ctx,opts,args): B=ctx with augment_usage_errors(B,param=A): C=A.consume_value(B,opts) try:C=A.full_process_value(B,C) except Exception: if not B.resilient_parsing:raise C=_A if A.callback is not _A: try:C=A.callback(B,A,C) except Exception: if not B.resilient_parsing:raise if A.expose_value:B.params[A.name]=C 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)) 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() 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 if B is _A: if C is not _A:B=_C else:B=bool(A.secondary_opts) if B and H:A.default=_B if C is _A:C=not A.default A.is_flag=B;A.flag_value=C if A.is_flag and isinstance(A.flag_value,bool)and type in[_A,bool]:A.type=BOOL;A.is_bool_flag=_C else:A.is_bool_flag=_B A.count=F if F: if type is _A:A.type=IntRange(min=0) if H:A.default=0 A.multiple=multiple;A.allow_from_autoenv=allow_from_autoenv;A.help=help;A.show_default=show_default;A.show_choices=show_choices;A.show_envvar=show_envvar if __debug__: if A.nargs<0:raise TypeError('Options cannot have nargs < 0') if A.prompt and A.is_flag and not A.is_bool_flag:raise TypeError('Cannot prompt for flags that are not bools.') if not A.is_bool_flag and A.secondary_opts:raise TypeError('Got secondary option for non boolean flag.') if A.is_bool_flag and A.hide_input and A.prompt is not _A:raise TypeError('Hidden input does not work with boolean flag prompts.') 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=[] 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 if H in B: E,G=B.split(H,1);E=E.rstrip() if E:D.append(split_opt(E));C.append(E) G=G.lstrip() 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() if not A.isidentifier():A=_A if A is _A: if not expose_value:return _A,C,F raise TypeError('Could not determine name for option') 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} 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" 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 if A.hidden:return F=[] def G(opts): B,C=join_options(opts) if C:F[:]=[_C] if not A.is_flag and not A.count:B+=f" {A.make_metavar()}" return B H=[G(A.opts)] if A.secondary_opts:H.append(G(A.secondary_opts)) help=A.help or'';C=[] if A.show_envvar: 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 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 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 def get_default(A,ctx): if A.is_flag and not A.is_bool_flag: for B in ctx.command.params: if B.name==A.name and B.default:return B.flag_value return _A return Parameter.get_default(A,ctx) def prompt_for_value(A,ctx): B=A.get_default(ctx) if A.is_bool_flag:return confirm(A.prompt,B) return prompt(A.prompt,default=B,type=A.type,hide_input=A.hide_input,show_choices=A.show_choices,confirmation_prompt=A.confirmation_prompt,value_proc=lambda x:A.process_value(ctx,x)) def resolve_envvar_value(A,ctx): B=ctx;C=Parameter.resolve_envvar_value(A,B) if C is not _A:return C if A.allow_from_autoenv and B.auto_envvar_prefix is not _A:D=f"{B.auto_envvar_prefix}_{A.name.upper()}";return os.environ.get(D) def value_from_envvar(A,ctx): B=A.resolve_envvar_value(ctx) if B is _A:return _A C=(A.nargs!=1)+bool(A.multiple) if C>0 and B is not _A: B=A.type.split_envvar_value(B) if A.multiple and A.nargs!=1:B=batch(B,A.nargs) return B def full_process_value(A,ctx,value): C=value;B=ctx if C is _A and A.prompt is not _A and not B.resilient_parsing:return A.prompt_for_value(B) return Parameter.full_process_value(A,B,C) class Argument(Parameter): param_type_name='argument' 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 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 def human_readable_name(self): A=self if A.metavar is not _A:return A.metavar return A.name.upper() def make_metavar(A): if A.metavar is not _A:return A.metavar 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 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() 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()] def get_error_hint(A,ctx):return repr(A.make_metavar()) def add_to_parser(A,parser,ctx):parser.add_argument(dest=A.name,nargs=A.nargs,obj=A)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807554.0 dynaconf-3.1.7/dynaconf/vendor/click/decorators.py0000644000175000017500000002100300000000000023616 0ustar00rochacbrunorochacbruno_J='is_eager' _I='prompt' _H='expose_value' _G='callback' _F='is_flag' _E='cls' _D=False _C=True _B='help' _A=None import inspect,sys from functools import update_wrapper from .core import Argument from .core import Command from .core import Group from .core import Option 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) 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) 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 def B(f): def B(*D,**E): B=get_current_context() 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 update_wrapper(B,f) return B def _make_command(f,name,attrs,cls): A=attrs if isinstance(f,Command):raise TypeError('Attempted to convert a callback into a command twice.') try:B=f.__click_params__;B.reverse();del f.__click_params__ except AttributeError:B=[] help=A.get(_B) if help is _A: help=inspect.getdoc(f) if isinstance(help,bytes):help=help.decode('utf-8') else:help=inspect.cleandoc(help) A[_B]=help;return cls(name=name or f.__name__.lower().replace('_','-'),callback=f,params=B,**A) def command(name=_A,cls=_A,**C): 'Creates a new :class:`Command` and uses the decorated function as\n callback. This will also automatically attach all decorated\n :func:`option`\\s and :func:`argument`\\s as parameters to the command.\n\n The name of the command defaults to the name of the function with\n underscores replaced by dashes. If you want to change that, you can\n pass the intended name as the first argument.\n\n All keyword arguments are forwarded to the underlying command class.\n\n Once decorated the function turns into a :class:`Command` instance\n that can be invoked as a command line utility or be attached to a\n command :class:`Group`.\n\n :param name: the name of the command. This defaults to the function\n name with underscores replaced by dashes.\n :param cls: the command class to instantiate. This defaults to\n :class:`Command`.\n ';A=cls if A is _A:A=Command def B(f):B=_make_command(f,name,C,A);B.__doc__=f.__doc__;return B return B def group(name=_A,**A):'Creates a new :class:`Group` with a function as callback. This\n works otherwise the same as :func:`command` just that the `cls`\n parameter is set to :class:`Group`.\n ';A.setdefault(_E,Group);return command(name,**A) def _param_memo(f,param): A=param if isinstance(f,Command):f.params.append(A) else: if not hasattr(f,'__click_params__'):f.__click_params__=[] f.__click_params__.append(A) def argument(*B,**A): 'Attaches an argument to the command. All positional arguments are\n passed as parameter declarations to :class:`Argument`; all keyword\n arguments are forwarded unchanged (except ``cls``).\n This is equivalent to creating an :class:`Argument` instance manually\n and attaching it to the :attr:`Command.params` list.\n\n :param cls: the argument class to instantiate. This defaults to\n :class:`Argument`.\n ' def C(f):C=A.pop(_E,Argument);_param_memo(f,C(B,**A));return f return C def option(*B,**C): 'Attaches an option to the command. All positional arguments are\n passed as parameter declarations to :class:`Option`; all keyword\n arguments are forwarded unchanged (except ``cls``).\n This is equivalent to creating an :class:`Option` instance manually\n and attaching it to the :attr:`Command.params` list.\n\n :param cls: the option class to instantiate. This defaults to\n :class:`Option`.\n ' def A(f): A=C.copy() if _B in A:A[_B]=inspect.cleandoc(A[_B]) D=A.pop(_E,Option);_param_memo(f,D(B,**A));return f return A def confirmation_option(*B,**A): "Shortcut for confirmation prompts that can be ignored by passing\n ``--yes`` as parameter.\n\n This is equivalent to decorating a function with :func:`option` with\n the following parameters::\n\n def callback(ctx, param, value):\n if not value:\n ctx.abort()\n\n @click.command()\n @click.option('--yes', is_flag=True, callback=callback,\n expose_value=False, prompt='Do you want to continue?')\n def dropdb():\n pass\n " 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) 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) 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 if D is _A: if hasattr(sys,'_getframe'):E=sys._getframe(1).f_globals.get('__name__') else:E='' def C(f): G=A.pop('prog_name',_A);H=A.pop('message','%(prog)s, version %(version)s') def C(ctx,param,value): A=ctx if not value or A.resilient_parsing:return C=G if C is _A:C=A.find_root().info_name B=D if B is _A: try:import pkg_resources as I except ImportError:pass else: for F in I.working_set: J=F.get_entry_map().get('console_scripts')or{} for K in J.values(): 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) 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 ' def C(f): 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) return C././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807554.0 dynaconf-3.1.7/dynaconf/vendor/click/exceptions.py0000644000175000017500000000634100000000000023642 0ustar00rochacbrunorochacbruno_A=None from ._compat import filename_to_ui,get_text_stderr from .utils import echo def _join_param_hints(param_hint): A=param_hint if isinstance(A,(tuple,list)):return ' / '.join((repr(B)for B in A)) return A class ClickException(Exception): exit_code=1 def __init__(B,message):A=message;super().__init__(A);B.message=A def format_message(A):return A.message def __str__(A):return A.message def show(B,file=_A): A=file if A is _A:A=get_text_stderr() echo(f"Error: {B.format_message()}",file=A) class UsageError(ClickException): exit_code=2 def __init__(A,message,ctx=_A):ClickException.__init__(A,message);A.ctx=ctx;A.cmd=A.ctx.command if A.ctx else _A def show(A,file=_A): B=file if B is _A:B=get_text_stderr() C=_A;D='' if A.cmd is not _A and A.cmd.get_help_option(A.ctx)is not _A:D=f"Try '{A.ctx.command_path} {A.ctx.help_option_names[0]}' for help.\n" if A.ctx is not _A:C=A.ctx.color;echo(f"{A.ctx.get_usage()}\n{D}",file=B,color=C) echo(f"Error: {A.format_message()}",file=B,color=C) class BadParameter(UsageError): def __init__(A,message,ctx=_A,param=_A,param_hint=_A):UsageError.__init__(A,message,ctx);A.param=param;A.param_hint=param_hint def format_message(A): if A.param_hint is not _A:B=A.param_hint elif A.param is not _A:B=A.param.get_error_hint(A.ctx) else:return f"Invalid value: {A.message}" B=_join_param_hints(B);return f"Invalid value for {B}: {A.message}" class MissingParameter(BadParameter): def __init__(A,message=_A,ctx=_A,param=_A,param_hint=_A,param_type=_A):BadParameter.__init__(A,message,ctx,param,param_hint);A.param_type=param_type def format_message(A): if A.param_hint is not _A:B=A.param_hint elif A.param is not _A:B=A.param.get_error_hint(A.ctx) else:B=_A B=_join_param_hints(B);D=A.param_type if D is _A and A.param is not _A:D=A.param.param_type_name C=A.message if A.param is not _A: E=A.param.type.get_missing_message(A.param) if E: if C:C+=f". {E}" else:C=E F=f" {B}"if B else'';return f"Missing {D}{F}.{' 'if C else''}{C or''}" def __str__(A): if A.message is _A:B=A.param.name if A.param else _A;return f"missing parameter: {B}" else:return A.message class NoSuchOption(UsageError): def __init__(A,option_name,message=_A,possibilities=_A,ctx=_A): C=option_name;B=message if B is _A:B=f"no such option: {C}" UsageError.__init__(A,B,ctx);A.option_name=C;A.possibilities=possibilities def format_message(A): B=[A.message] if A.possibilities: if len(A.possibilities)==1:B.append(f"Did you mean {A.possibilities[0]}?") else:C=sorted(A.possibilities);B.append(f"(Possible options: {', '.join(C)})") return ' '.join(B) class BadOptionUsage(UsageError): def __init__(A,option_name,message,ctx=_A):UsageError.__init__(A,message,ctx);A.option_name=option_name class BadArgumentUsage(UsageError): def __init__(A,message,ctx=_A):UsageError.__init__(A,message,ctx) class FileError(ClickException): def __init__(A,filename,hint=_A): C=filename;B=hint;D=filename_to_ui(C) if B is _A:B='unknown error' ClickException.__init__(A,B);A.ui_filename=D;A.filename=C def format_message(A):return f"Could not open file {A.ui_filename}: {A.message}" class Abort(RuntimeError):0 class Exit(RuntimeError): __slots__='exit_code', def __init__(A,code=0):A.exit_code=code././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807554.0 dynaconf-3.1.7/dynaconf/vendor/click/formatting.py0000644000175000017500000000647700000000000023645 0ustar00rochacbrunorochacbruno_E=True _D=False _C=' ' _B='\n' _A=None from contextlib import contextmanager from ._compat import term_len from .parser import split_opt from .termui import get_terminal_size FORCED_WIDTH=_A def measure_table(rows): A={} for C in rows: for (B,D) in enumerate(C):A[B]=max(A.get(B,0),term_len(D)) return tuple((B for(C,B)in sorted(A.items()))) def iter_rows(rows,col_count): for A in rows:A=tuple(A);yield A+('',)*(col_count-len(A)) def wrap_text(text,width=78,initial_indent='',subsequent_indent='',preserve_paragraphs=_D): A=text;from ._textwrap import TextWrapper as I;A=A.expandtabs();E=I(width,initial_indent=initial_indent,subsequent_indent=subsequent_indent,replace_whitespace=_D) if not preserve_paragraphs:return E.fill(A) F=[];C=[];B=_A def H(): if not C:return if C[0].strip()=='\x08':F.append((B or 0,_E,_B.join(C[1:]))) else:F.append((B or 0,_D,_C.join(C))) del C[:] for D in A.splitlines(): if not D:H();B=_A else: if B is _A:J=term_len(D);D=D.lstrip();B=J-term_len(D) C.append(D) H();G=[] for (B,K,A) in F: with E.extra_indent(_C*B): if K:G.append(E.indent_only(A)) else:G.append(E.fill(A)) return '\n\n'.join(G) class HelpFormatter: def __init__(B,indent_increment=2,width=_A,max_width=_A): C=max_width;A=width;B.indent_increment=indent_increment if C is _A:C=80 if A is _A: A=FORCED_WIDTH if A is _A:A=max(min(get_terminal_size()[0],C)-2,50) B.width=A;B.current_indent=0;B.buffer=[] def write(A,string):A.buffer.append(string) def indent(A):A.current_indent+=A.indent_increment def dedent(A):A.current_indent-=A.indent_increment def write_usage(A,prog,args='',prefix='Usage: '): E=prefix;B=f"{E:>{A.current_indent}}{prog} ";D=A.width-A.current_indent if D>=term_len(B)+20:C=_C*term_len(B);A.write(wrap_text(args,D,initial_indent=B,subsequent_indent=C)) else:A.write(B);A.write(_B);C=_C*(max(A.current_indent,term_len(E))+4);A.write(wrap_text(args,D,initial_indent=C,subsequent_indent=C)) A.write(_B) def write_heading(A,heading):A.write(f"{'':>{A.current_indent}}{heading}:\n") def write_paragraph(A): if A.buffer:A.write(_B) def write_text(A,text):C=max(A.width-A.current_indent,11);B=_C*A.current_indent;A.write(wrap_text(text,C,initial_indent=B,subsequent_indent=B,preserve_paragraphs=_E));A.write(_B) def write_dl(A,rows,col_max=30,col_spacing=2): G=col_spacing;C=rows;C=list(C);E=measure_table(C) if len(E)!=2:raise TypeError('Expected two columns for definition list') B=min(E[0],col_max)+G for (F,H) in iter_rows(C,len(E)): A.write(f"{'':>{A.current_indent}}{F}") if not H:A.write(_B);continue if term_len(F)<=B-G:A.write(_C*(B-term_len(F))) else:A.write(_B);A.write(_C*(B+A.current_indent)) I=max(A.width-B-2,10);J=wrap_text(H,I,preserve_paragraphs=_E);D=J.splitlines() if D: A.write(f"{D[0]}\n") for K in D[1:]:A.write(f"{'':>{B+A.current_indent}}{K}\n") if len(D)>1:A.write(_B) else:A.write(_B) @contextmanager def section(self,name): A=self;A.write_paragraph();A.write_heading(name);A.indent() try:yield finally:A.dedent() @contextmanager def indentation(self): self.indent() try:yield finally:self.dedent() def getvalue(A):return ''.join(A.buffer) def join_options(options): A=[];B=_D for C in options: D=split_opt(C)[0] if D=='/':B=_E A.append((len(D),C)) A.sort(key=lambda x:x[0]);A=', '.join((B[1]for B in A));return A,B././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807554.0 dynaconf-3.1.7/dynaconf/vendor/click/globals.py0000644000175000017500000000073300000000000023103 0ustar00rochacbrunorochacbruno_A=None from threading import local _local=local() def get_current_context(silent=False): try:return _local.stack[-1] except (AttributeError,IndexError): 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): A=color if A is not _A:return A B=get_current_context(silent=True) if B is not _A:return B.color././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807555.0 dynaconf-3.1.7/dynaconf/vendor/click/parser.py0000644000175000017500000001314200000000000022752 0ustar00rochacbrunorochacbruno_D=False _C='append' _B='store' _A=None import re from collections import deque from .exceptions import BadArgumentUsage from .exceptions import BadOptionUsage from .exceptions import NoSuchOption from .exceptions import UsageError def _unpack_args(args,nargs_spec): D=nargs_spec;C=args;C=deque(C);D=deque(D);A=[];B=_A def F(c): try: if B is _A:return c.popleft() else:return c.pop() except IndexError:return _A while D: E=F(D) if E==1:A.append(F(C)) elif E>1: G=[F(C)for A in range(E)] if B is not _A:G.reverse() A.append(tuple(G)) elif E<0: if B is not _A:raise TypeError('Cannot have two nargs < 0') B=len(A);A.append(_A) if B is not _A:A[B]=tuple(C);C=[];A[B+1:]=reversed(A[B+1:]) return tuple(A),list(C) def _error_opt_args(nargs,opt): B=nargs;A=opt if B==1:raise BadOptionUsage(A,f"{A} option requires an argument") raise BadOptionUsage(A,f"{A} option requires {B} arguments") def split_opt(opt): A=opt;B=A[:1] if B.isalnum():return'',A if A[1:2]==B:return A[:2],A[2:] return B,A[1:] def normalize_opt(opt,ctx): B=ctx;A=opt if B is _A or B.token_normalize_func is _A:return A C,A=split_opt(A);return f"{C}{B.token_normalize_func(A)}" def split_arg_string(string): B=string;C=[] for D in re.finditer('(\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|\\"([^\\"\\\\]*(?:\\\\.[^\\"\\\\]*)*)\\"|\\S+)\\s*',B,re.S): A=D.group().strip() if A[:1]==A[-1:]and A[:1]in'"\'':A=A[1:-1].encode('ascii','backslashreplace').decode('unicode-escape') try:A=type(B)(A) except UnicodeError:pass C.append(A) return C class Option: def __init__(A,opts,dest,action=_A,nargs=1,const=_A,obj=_A): D=action;A._short_opts=[];A._long_opts=[];A.prefixes=set() for B in opts: C,E=split_opt(B) if not C:raise ValueError(f"Invalid start character for option ({B})") A.prefixes.add(C[0]) if len(C)==1 and len(E)==1:A._short_opts.append(B) else:A._long_opts.append(B);A.prefixes.add(C) if D is _A:D=_B A.dest=dest;A.action=D;A.nargs=nargs;A.const=const;A.obj=obj @property def takes_value(self):return self.action in(_B,_C) def process(A,value,state): C=value;B=state if A.action==_B:B.opts[A.dest]=C elif A.action=='store_const':B.opts[A.dest]=A.const elif A.action==_C:B.opts.setdefault(A.dest,[]).append(C) elif A.action=='append_const':B.opts.setdefault(A.dest,[]).append(A.const) elif A.action=='count':B.opts[A.dest]=B.opts.get(A.dest,0)+1 else:raise ValueError(f"unknown action '{A.action}'") B.order.append(A.obj) class Argument: def __init__(A,dest,nargs=1,obj=_A):A.dest=dest;A.nargs=nargs;A.obj=obj def process(A,value,state): C=state;B=value if A.nargs>1: D=sum((1 for A in B if A is _A)) if D==len(B):B=_A elif D!=0:raise BadArgumentUsage(f"argument {A.dest} takes {A.nargs} values") C.opts[A.dest]=B;C.order.append(A.obj) 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 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): D=obj;C=opts if D is _A:D=dest C=[normalize_opt(A,B.ctx)for A in C];A=Option(C,dest,action=action,nargs=nargs,const=const,obj=D);B._opt_prefixes.update(A.prefixes) for E in A._short_opts:B._short_opt[E]=A for E in A._long_opts:B._long_opt[E]=A def add_argument(B,dest,nargs=1,obj=_A): A=obj if A is _A:A=dest B._args.append(Argument(dest=dest,nargs=nargs,obj=A)) def parse_args(B,args): A=ParsingState(args) try:B._process_args_for_options(A);B._process_args_for_args(A) except UsageError: if B.ctx is _A or not B.ctx.resilient_parsing:raise return A.opts,A.largs,A.order def _process_args_for_args(B,state): A=state;C,D=_unpack_args(A.largs+A.rargs,[A.nargs for A in B._args]) for (E,F) in enumerate(B._args):F.process(C[E],A) A.largs=D;A.rargs=[] def _process_args_for_options(C,state): B=state while B.rargs: A=B.rargs.pop(0);D=len(A) if A=='--':return elif A[:1]in C._opt_prefixes and D>1:C._process_opts(A,B) elif C.allow_interspersed_args:B.largs.append(A) else:B.rargs.insert(0,A);return def _match_long_opt(D,opt,explicit_value,state): E=explicit_value;B=state;A=opt if A not in D._long_opt:H=[B for B in D._long_opt if B.startswith(A)];raise NoSuchOption(A,possibilities=H,ctx=D.ctx) F=D._long_opt[A] if F.takes_value: if E is not _A:B.rargs.insert(0,E) C=F.nargs if len(B.rargs)" 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 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): 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) if not A.mix_stderr:F=io.BytesIO();sys.stderr=io.TextIOWrapper(F,encoding=A.charset) if A.mix_stderr:sys.stderr=sys.stdout sys.stdin=input def L(prompt=_A):sys.stdout.write(prompt or'');A=input.readline().rstrip(_B);sys.stdout.write(f"{A}\n");sys.stdout.flush();return A def M(prompt=_A):sys.stdout.write(f"{prompt or''}\n");sys.stdout.flush();return input.readline().rstrip(_B) def N(echo): A=sys.stdin.read(1) if echo:sys.stdout.write(A);sys.stdout.flush() return A O=color def P(stream=_A,color=_A): A=color if A is _A:return not O return not A Q=termui.visible_prompt_func;R=termui.hidden_prompt_func;S=termui._getchar;T=utils.should_strip_ansi;termui.visible_prompt_func=L;termui.hidden_prompt_func=M;termui._getchar=N;utils.should_strip_ansi=P;G={} try: for (B,C) in D.items(): G[B]=os.environ.get(B) if C is _A: try:del os.environ[B] except Exception:pass else:os.environ[B]=C yield(E,not A.mix_stderr and F) finally: for (B,C) in G.items(): if C is _A: try:del os.environ[B] 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): C=args;E=_A with B.isolation(input=input,env=env,color=color)as H: F=_A;A=0 if isinstance(C,str):C=shlex.split(C) try:I=G.pop('prog_name') except KeyError:I=B.get_default_prog_name(cli) try:cli.main(args=C or(),prog_name=I,**G) except SystemExit as D: 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 except Exception as D: if not catch_exceptions:raise F=D;A=1;E=sys.exc_info() finally: sys.stdout.flush();K=H[0].getvalue() if B.mix_stderr:J=_A else:J=H[1].getvalue() return Result(runner=B,stdout_bytes=K,stderr_bytes=J,exit_code=A,exception=F,exc_info=E) @contextlib.contextmanager def isolated_filesystem(self): B=os.getcwd();A=tempfile.mkdtemp();os.chdir(A) try:yield A finally: os.chdir(B) try:shutil.rmtree(A) except OSError:pass././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807555.0 dynaconf-3.1.7/dynaconf/vendor/click/types.py0000644000175000017500000002146200000000000022626 0ustar00rochacbrunorochacbruno_F='text' _E='replace' _D='utf-8' _C=True _B=False _A=None import os,stat from datetime import datetime from ._compat import _get_argv_encoding from ._compat import filename_to_ui from ._compat import get_filesystem_encoding from ._compat import get_strerror from ._compat import open_stream from .exceptions import BadParameter from .utils import LazyFile from .utils import safecall class ParamType: is_composite=_B;name=_A;envvar_list_splitter=_A def __call__(B,value,param=_A,ctx=_A): A=value if A is not _A:return B.convert(A,param,ctx) def get_metavar(A,param):0 def get_missing_message(A,param):0 def convert(A,value,param,ctx):return value def split_envvar_value(A,rv):return (rv or'').split(A.envvar_list_splitter) def fail(A,message,param=_A,ctx=_A):raise BadParameter(message,ctx=ctx,param=param) class CompositeParamType(ParamType): is_composite=_C @property def arity(self):raise NotImplementedError() class FuncParamType(ParamType): def __init__(A,func):A.name=func.__name__;A.func=func def convert(B,value,param,ctx): A=value try:return B.func(A) except ValueError: try:A=str(A) except UnicodeError:A=A.decode(_D,_E) B.fail(A,param,ctx) class UnprocessedParamType(ParamType): name=_F def convert(A,value,param,ctx):return value def __repr__(A):return'UNPROCESSED' class StringParamType(ParamType): name=_F def convert(D,value,param,ctx): A=value if isinstance(A,bytes): B=_get_argv_encoding() try:A=A.decode(B) except UnicodeError: C=get_filesystem_encoding() if C!=B: try:A=A.decode(C) except UnicodeError:A=A.decode(_D,_E) else:A=A.decode(_D,_E) return A return A def __repr__(A):return'STRING' class Choice(ParamType): name='choice' def __init__(A,choices,case_sensitive=_C):A.choices=choices;A.case_sensitive=case_sensitive def get_metavar(A,param):return f"[{'|'.join(A.choices)}]" def get_missing_message(A,param):B=',\n\t'.join(A.choices);return f"Choose from:\n\t{B}" def convert(D,value,param,ctx): E=value;B=ctx;C=E;A={A:A for A in D.choices} if B is not _A and B.token_normalize_func is not _A:C=B.token_normalize_func(E);A={B.token_normalize_func(C):D for(C,D)in A.items()} if not D.case_sensitive:C=C.casefold();A={B.casefold():C for(B,C)in A.items()} if C in A:return A[C] D.fail(f"invalid choice: {E}. (choose from {', '.join(D.choices)})",param,B) def __repr__(A):return f"Choice({list(A.choices)})" class DateTime(ParamType): name='datetime' def __init__(A,formats=_A):A.formats=formats or['%Y-%m-%d','%Y-%m-%dT%H:%M:%S','%Y-%m-%d %H:%M:%S'] def get_metavar(A,param):return f"[{'|'.join(A.formats)}]" def _try_to_convert_date(A,value,format): try:return datetime.strptime(value,format) except ValueError:return _A def convert(A,value,param,ctx): B=value for format in A.formats: C=A._try_to_convert_date(B,format) if C:return C A.fail(f"invalid datetime format: {B}. (choose from {', '.join(A.formats)})") def __repr__(A):return'DateTime' class IntParamType(ParamType): name='integer' def convert(B,value,param,ctx): A=value try:return int(A) except ValueError:B.fail(f"{A} is not a valid integer",param,ctx) def __repr__(A):return'INT' class IntRange(IntParamType): name='integer range' def __init__(A,min=_A,max=_A,clamp=_B):A.min=min;A.max=max;A.clamp=clamp def convert(A,value,param,ctx): D=ctx;C=param;B=IntParamType.convert(A,value,C,D) if A.clamp: if A.min is not _A and BA.max:return A.max if A.min is not _A and BA.max: if A.min is _A:A.fail(f"{B} is bigger than the maximum valid value {A.max}.",C,D) elif A.max is _A:A.fail(f"{B} is smaller than the minimum valid value {A.min}.",C,D) else:A.fail(f"{B} is not in the valid range of {A.min} to {A.max}.",C,D) return B def __repr__(A):return f"IntRange({A.min}, {A.max})" class FloatParamType(ParamType): name='float' def convert(B,value,param,ctx): A=value try:return float(A) except ValueError:B.fail(f"{A} is not a valid floating point value",param,ctx) def __repr__(A):return'FLOAT' class FloatRange(FloatParamType): name='float range' def __init__(A,min=_A,max=_A,clamp=_B):A.min=min;A.max=max;A.clamp=clamp def convert(A,value,param,ctx): D=ctx;C=param;B=FloatParamType.convert(A,value,C,D) if A.clamp: if A.min is not _A and BA.max:return A.max if A.min is not _A and BA.max: if A.min is _A:A.fail(f"{B} is bigger than the maximum valid value {A.max}.",C,D) elif A.max is _A:A.fail(f"{B} is smaller than the minimum valid value {A.min}.",C,D) else:A.fail(f"{B} is not in the valid range of {A.min} to {A.max}.",C,D) return B def __repr__(A):return f"FloatRange({A.min}, {A.max})" class BoolParamType(ParamType): name='boolean' def convert(B,value,param,ctx): A=value if isinstance(A,bool):return bool(A) A=A.lower() if A in('true','t','1','yes','y'):return _C elif A in('false','f','0','no','n'):return _B B.fail(f"{A} is not a valid boolean",param,ctx) def __repr__(A):return'BOOL' class UUIDParameterType(ParamType): name='uuid' def convert(B,value,param,ctx): A=value;import uuid try:return uuid.UUID(A) except ValueError:B.fail(f"{A} is not a valid UUID value",param,ctx) def __repr__(A):return'UUID' class File(ParamType): name='filename';envvar_list_splitter=os.path.pathsep def __init__(A,mode='r',encoding=_A,errors='strict',lazy=_A,atomic=_B):A.mode=mode;A.encoding=encoding;A.errors=errors;A.lazy=lazy;A.atomic=atomic def resolve_lazy_flag(A,value): if A.lazy is not _A:return A.lazy if value=='-':return _B elif'w'in A.mode:return _C return _B def convert(A,value,param,ctx): C=ctx;B=value try: if hasattr(B,'read')or hasattr(B,'write'):return B E=A.resolve_lazy_flag(B) if E: D=LazyFile(B,A.mode,A.encoding,A.errors,atomic=A.atomic) if C is not _A:C.call_on_close(D.close_intelligently) return D D,F=open_stream(B,A.mode,A.encoding,A.errors,atomic=A.atomic) if C is not _A: if F:C.call_on_close(safecall(D.close)) else:C.call_on_close(safecall(D.flush)) return D except OSError as G:A.fail(f"Could not open file: {filename_to_ui(B)}: {get_strerror(G)}",param,C) class Path(ParamType): envvar_list_splitter=os.path.pathsep def __init__(A,exists=_B,file_okay=_C,dir_okay=_C,writable=_B,readable=_C,resolve_path=_B,allow_dash=_B,path_type=_A): A.exists=exists;A.file_okay=file_okay;A.dir_okay=dir_okay;A.writable=writable;A.readable=readable;A.resolve_path=resolve_path;A.allow_dash=allow_dash;A.type=path_type if A.file_okay and not A.dir_okay:A.name='file';A.path_type='File' elif A.dir_okay and not A.file_okay:A.name='directory';A.path_type='Directory' else:A.name='path';A.path_type='Path' def coerce_path_result(B,rv): A=rv if B.type is not _A and not isinstance(A,B.type): if B.type is str:A=A.decode(get_filesystem_encoding()) else:A=A.encode(get_filesystem_encoding()) return A def convert(A,value,param,ctx): E=ctx;D=param;B=value;C=B;G=A.file_okay and A.allow_dash and C in(b'-','-') if not G: if A.resolve_path:C=os.path.realpath(C) try:F=os.stat(C) except OSError: if not A.exists:return A.coerce_path_result(C) A.fail(f"{A.path_type} {filename_to_ui(B)!r} does not exist.",D,E) if not A.file_okay and stat.S_ISREG(F.st_mode):A.fail(f"{A.path_type} {filename_to_ui(B)!r} is a file.",D,E) if not A.dir_okay and stat.S_ISDIR(F.st_mode):A.fail(f"{A.path_type} {filename_to_ui(B)!r} is a directory.",D,E) if A.writable and not os.access(B,os.W_OK):A.fail(f"{A.path_type} {filename_to_ui(B)!r} is not writable.",D,E) if A.readable and not os.access(B,os.R_OK):A.fail(f"{A.path_type} {filename_to_ui(B)!r} is not readable.",D,E) return A.coerce_path_result(C) class Tuple(CompositeParamType): def __init__(A,types):A.types=[convert_type(A)for A in types] @property def name(self):return f"<{' '.join((A.name for A in self.types))}>" @property def arity(self):return len(self.types) def convert(A,value,param,ctx): B=value if len(B)!=len(A.types):raise TypeError('It would appear that nargs is set to conflict with the composite type arity.') return tuple((C(D,param,ctx)for(C,D)in zip(A.types,B))) def convert_type(ty,default=_A): B=default;A=ty;C=_B if A is _A and B is not _A: if isinstance(B,tuple):A=tuple(map(type,B)) else:A=type(B) C=_C if isinstance(A,tuple):return Tuple(A) if isinstance(A,ParamType):return A if A is str or A is _A:return STRING if A is int:return INT if A is bool and not C:return BOOL if A is float:return FLOAT if C:return STRING if __debug__: try: if issubclass(A,ParamType):raise AssertionError(f"Attempted to use an uninstantiated parameter type ({A}).") except TypeError:pass return FuncParamType(A) UNPROCESSED=UnprocessedParamType() STRING=StringParamType() INT=IntParamType() FLOAT=FloatParamType() BOOL=BoolParamType() UUID=UUIDParameterType()././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807556.0 dynaconf-3.1.7/dynaconf/vendor/click/utils.py0000644000175000017500000001041000000000000022611 0ustar00rochacbrunorochacbruno_D='strict' _C=True _B=False _A=None import os,sys from ._compat import _default_text_stderr,_default_text_stdout,_find_binary_writer,auto_wrap_for_ansi,binary_streams,filename_to_ui,get_filesystem_encoding,get_strerror,is_bytes,open_stream,should_strip_ansi,strip_ansi,text_streams,WIN from .globals import resolve_color_default 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) except Exception:pass return A def make_str(value): A=value if isinstance(A,bytes): try:return A.decode(get_filesystem_encoding()) except UnicodeError:return A.decode('utf-8','replace') return str(A) def make_default_short_help(help,max_length=45): F=help.split();D=0;A=[];C=_B for B in F: if B[-1:]=='.':C=_C E=1+len(B)if A else len(B) if D+E>max_length:A.append('...');C=_C else: if A:A.append(' ') A.append(B) if C:break D+=E return ''.join(A) class LazyFile: def __init__(A,filename,mode='r',encoding=_A,errors=_D,atomic=_B): E=errors;D=encoding;C=mode;B=filename;A.name=B;A.mode=C;A.encoding=D;A.errors=E;A.atomic=atomic if B=='-':A._f,A.should_close=open_stream(B,C,D,E) else: if'r'in C:open(B,C).close() A._f=_A;A.should_close=_C def __getattr__(A,name):return getattr(A.open(),name) def __repr__(A): if A._f is not _A:return repr(A._f) return f"" def open(A): if A._f is not _A:return A._f try:B,A.should_close=open_stream(A.name,A.mode,A.encoding,A.errors,atomic=A.atomic) except OSError as C:from .exceptions import FileError as D;raise D(A.name,hint=get_strerror(C)) A._f=B;return B def close(A): if A._f is not _A:A._f.close() def close_intelligently(A): if A.should_close:A.close() def __enter__(A):return A def __exit__(A,exc_type,exc_value,tb):A.close_intelligently() def __iter__(A):A.open();return iter(A._f) class KeepOpenFile: def __init__(A,file):A._file=file def __getattr__(A,name):return getattr(A._file,name) def __enter__(A):return A def __exit__(A,exc_type,exc_value,tb):0 def __repr__(A):return repr(A._file) def __iter__(A):return iter(A._file) def echo(message=_A,file=_A,nl=_C,err=_B,color=_A): C=color;B=file;A=message if B is _A: if err:B=_default_text_stderr() else:B=_default_text_stdout() if A is not _A and not isinstance(A,echo_native_types):A=str(A) if nl: A=A or'' if isinstance(A,str):A+='\n' else:A+=b'\n' if A and is_bytes(A): D=_find_binary_writer(B) if D is not _A:B.flush();D.write(A);D.flush();return if A and not is_bytes(A): C=resolve_color_default(C) if should_strip_ansi(B,C):A=strip_ansi(A) elif WIN: if auto_wrap_for_ansi is not _A:B=auto_wrap_for_ansi(B) elif not C:A=strip_ansi(A) if A:B.write(A) B.flush() def get_binary_stream(name): A=binary_streams.get(name) if A is _A:raise TypeError(f"Unknown standard stream '{name}'") return A() def get_text_stream(name,encoding=_A,errors=_D): A=text_streams.get(name) if A is _A:raise TypeError(f"Unknown standard stream '{name}'") return A(encoding,errors) def open_file(filename,mode='r',encoding=_A,errors=_D,lazy=_B,atomic=_B): E=atomic;D=errors;C=encoding;B=filename if lazy:return LazyFile(B,mode,C,D,atomic=E) A,F=open_stream(B,mode,C,D,atomic=E) if not F:A=KeepOpenFile(A) return A def get_os_args():import warnings as A;A.warn("'get_os_args' is deprecated and will be removed in 8.1. Access 'sys.argv[1:]' directly instead.",DeprecationWarning,stacklevel=2);return sys.argv[1:] def format_filename(filename,shorten=_B): A=filename if shorten:A=os.path.basename(A) return filename_to_ui(A) def get_app_dir(app_name,roaming=_C,force_posix=_B): A=app_name if WIN: C='APPDATA'if roaming else'LOCALAPPDATA';B=os.environ.get(C) if B is _A:B=os.path.expanduser('~') return os.path.join(B,A) if force_posix:return os.path.join(os.path.expanduser(f"~/.{_posixify(A)}")) if sys.platform=='darwin':return os.path.join(os.path.expanduser('~/Library/Application Support'),A) return os.path.join(os.environ.get('XDG_CONFIG_HOME',os.path.expanduser('~/.config')),_posixify(A)) class PacifyFlushWrapper: def __init__(A,wrapped):A.wrapped=wrapped def flush(A): try:A.wrapped.flush() except OSError as B: import errno if B.errno!=errno.EPIPE:raise def __getattr__(A,attr):return getattr(A.wrapped,attr)././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1631217935.123678 dynaconf-3.1.7/dynaconf/vendor/dotenv/0000755000175000017500000000000000000000000021315 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807556.0 dynaconf-3.1.7/dynaconf/vendor/dotenv/__init__.py0000644000175000017500000000130200000000000023422 0ustar00rochacbrunorochacbruno_A=None from .compat import IS_TYPE_CHECKING from .main import load_dotenv,get_key,set_key,unset_key,find_dotenv,dotenv_values 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'] if D:A.append('-q %s'%D) if path:A.append('-f %s'%path) if C: A.append(C) if key: A.append(key) if B: if E in B:A.append('"%s"'%B) else:A.append(B) return E.join(A).strip() __all__=['get_cli_string','load_dotenv','dotenv_values','get_key','set_key','unset_key','find_dotenv','load_ipython_extension']././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807556.0 dynaconf-3.1.7/dynaconf/vendor/dotenv/cli.py0000644000175000017500000000435500000000000022445 0ustar00rochacbrunorochacbruno_F='always' _E='key' _D='%s=%s' _C='QUOTE' _B='FILE' _A=True import os,sys from subprocess import Popen try:from dynaconf.vendor import click except ImportError:sys.stderr.write('It seems python-dotenv is not installed with cli option. \nRun pip install "python-dotenv[cli]" to fix this.');sys.exit(1) from .compat import IS_TYPE_CHECKING,to_env from .main import dotenv_values,get_key,set_key,unset_key from .version import __version__ if IS_TYPE_CHECKING:from typing import Any,List,Dict @click.group() @click.option('-f','--file',default=os.path.join(os.getcwd(),'.env'),type=click.Path(exists=_A),help='Location of the .env file, defaults to .env file in current working directory.') @click.option('-q','--quote',default=_F,type=click.Choice([_F,'never','auto']),help='Whether to quote or not the variable values. Default mode is always. This does not affect parsing.') @click.version_option(version=__version__) @click.pass_context def cli(ctx,file,quote):A=ctx;A.obj={};A.obj[_B]=file;A.obj[_C]=quote @cli.command() @click.pass_context def list(ctx): A=ctx.obj[_B];B=dotenv_values(A) for (C,D) in B.items():click.echo(_D%(C,D)) @cli.command() @click.pass_context @click.argument(_E,required=_A) @click.argument('value',required=_A) def set(ctx,key,value): B=value;A=key;C=ctx.obj[_B];D=ctx.obj[_C];E,A,B=set_key(C,A,B,D) if E:click.echo(_D%(A,B)) else:exit(1) @cli.command() @click.pass_context @click.argument(_E,required=_A) def get(ctx,key): B=ctx.obj[_B];A=get_key(B,key) if A:click.echo(_D%(key,A)) else:exit(1) @cli.command() @click.pass_context @click.argument(_E,required=_A) def unset(ctx,key): A=key;B=ctx.obj[_B];C=ctx.obj[_C];D,A=unset_key(B,A,C) if D:click.echo('Successfully removed %s'%A) else:exit(1) @cli.command(context_settings={'ignore_unknown_options':_A}) @click.pass_context @click.argument('commandline',nargs=-1,type=click.UNPROCESSED) def run(ctx,commandline): A=commandline;B=ctx.obj[_B];C={to_env(C):to_env(A)for(C,A)in dotenv_values(B).items()if A is not None} if not A:click.echo('No command given.');exit(1) D=run_command(A,C);exit(D) def run_command(command,env):A=os.environ.copy();A.update(env);B=Popen(command,universal_newlines=_A,bufsize=0,shell=False,env=A);C,C=B.communicate();return B.returncode if __name__=='__main__':cli()././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807556.0 dynaconf-3.1.7/dynaconf/vendor/dotenv/compat.py0000644000175000017500000000073300000000000023155 0ustar00rochacbrunorochacbruno_A='utf-8' import sys PY2=sys.version_info[0]==2 if PY2:from StringIO import StringIO else:from io import StringIO def is_type_checking(): try:from typing import TYPE_CHECKING as A except ImportError:return False return A 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) else:return text def to_text(string): A=string if PY2:return A.decode(_A) else:return A././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807556.0 dynaconf-3.1.7/dynaconf/vendor/dotenv/ipython.py0000644000175000017500000000161600000000000023365 0ustar00rochacbrunorochacbrunofrom __future__ import print_function _A='store_true' from IPython.core.magic import Magics,line_magic,magics_class from IPython.core.magic_arguments import argument,magic_arguments,parse_argstring from .main import find_dotenv,load_dotenv @magics_class class IPythonDotEnv(Magics): @magic_arguments() @argument('-o','--override',action=_A,help='Indicate to override existing variables') @argument('-v','--verbose',action=_A,help='Indicate function calls to be verbose') @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) 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)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807557.0 dynaconf-3.1.7/dynaconf/vendor/dotenv/main.py0000644000175000017500000001163500000000000022621 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import,print_function,unicode_literals _E='.env' _D='always' _C=True _B=False _A=None import io,logging,os,re,shutil,sys,tempfile from collections import OrderedDict from contextlib import contextmanager from .compat import IS_TYPE_CHECKING,PY2,StringIO,to_env from .parser import Binding,parse_stream logger=logging.getLogger(__name__) if IS_TYPE_CHECKING: from typing import Dict,Iterator,Match,Optional,Pattern,Union,Text,IO,Tuple if sys.version_info>=(3,6):_PathLike=os.PathLike else:_PathLike=Text if sys.version_info>=(3,0):_StringIO=StringIO else:_StringIO=StringIO[Text] __posix_variable=re.compile('\n \\$\\{\n (?P[^\\}:]*)\n (?::-\n (?P[^\\}]*)\n )?\n \\}\n ',re.VERBOSE) def with_warn_for_invalid_lines(mappings): for A in mappings: if A.error:logger.warning('Python-dotenv could not parse statement starting at line %s',A.original.line) yield A class DotEnv: def __init__(A,dotenv_path,verbose=_B,encoding=_A,interpolate=_C):A.dotenv_path=dotenv_path;A._dict=_A;A.verbose=verbose;A.encoding=encoding;A.interpolate=interpolate @contextmanager def _get_stream(self): A=self if isinstance(A.dotenv_path,StringIO):yield A.dotenv_path 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) yield StringIO('') def dict(A): if A._dict:return A._dict B=OrderedDict(A.parse());A._dict=resolve_nested_variables(B)if A.interpolate else B;return A._dict def parse(B): with B._get_stream()as C: for A in with_warn_for_invalid_lines(parse_stream(C)): if A.key is not _A:yield(A.key,A.value) def set_as_environment_variables(C,override=_B): for (A,B) in C.dict().items(): if A in os.environ and not override:continue if B is not _A:os.environ[to_env(A)]=to_env(B) return _C def get(A,key): B=key;C=A.dict() if B in C:return C[B] if A.verbose:logger.warning('Key %s not found in %s.',B,A.dotenv_path) return _A def get_key(dotenv_path,key_to_get):return DotEnv(dotenv_path,verbose=_C).get(key_to_get) @contextmanager def rewrite(path): try: with tempfile.NamedTemporaryFile(mode='w+',delete=_B)as A: with io.open(path)as B:yield(B,A) except BaseException: if os.path.isfile(A.name):os.unlink(A.name) 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) 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,'\\"')) else:F=A G='{}={}\n'.format(B,F) with rewrite(C)as(J,D): H=_B for I in with_warn_for_invalid_lines(parse_stream(J)): if I.key==B:D.write(G);H=_C else:D.write(I.original.string) if not H:D.write(G) return _C,B,A def unset_key(dotenv_path,key_to_unset,quote_mode=_D): B=dotenv_path;A=key_to_unset if not os.path.exists(B):logger.warning("Can't delete from %s - it doesn't exist.",B);return _A,A C=_B with rewrite(B)as(E,F): for D in with_warn_for_invalid_lines(parse_stream(E)): if D.key==A:C=_C else:F.write(D.original.string) if not C:logger.warning("Key %s not removed from %s - key doesn't exist.",A,B);return _A,A return C,A def resolve_nested_variables(values): def C(name,default):A=default;A=A if A is not _A else'';C=os.getenv(name,B.get(name,A));return C def D(match):A=match.groupdict();return C(name=A['name'],default=A['default']) B={} for (E,A) in values.items():B[E]=__posix_variable.sub(D,A)if A is not _A else _A return B def _walk_to_root(path): A=path if not os.path.exists(A):raise IOError('Starting path not found') 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() else: A=sys._getframe() if PY2 and not __file__.endswith(H):C=__file__.rsplit('.',1)[0]+H 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) if os.path.isfile(D):return D if raise_error_if_not_found:raise IOError('File not found') return'' def load_dotenv(dotenv_path=_A,stream=_A,verbose=_B,override=_B,interpolate=_C,**A):B=dotenv_path or stream or find_dotenv();return DotEnv(B,verbose=verbose,interpolate=interpolate,**A).set_as_environment_variables(override=override) def dotenv_values(dotenv_path=_A,stream=_A,verbose=_B,interpolate=_C,**A):B=dotenv_path or stream or find_dotenv();return DotEnv(B,verbose=verbose,interpolate=interpolate,**A).dict()././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807557.0 dynaconf-3.1.7/dynaconf/vendor/dotenv/parser.py0000644000175000017500000000750100000000000023166 0ustar00rochacbrunorochacbruno_I='error' _H='original' _G='value' _F='key' _E='Binding' _D='line' _C='string' _B='Original' _A=None import codecs,re from .compat import IS_TYPE_CHECKING,to_text if IS_TYPE_CHECKING:from typing import IO,Iterator,Match,NamedTuple,Optional,Pattern,Sequence,Text,Tuple def make_regex(string,extra_flags=0):return re.compile(to_text(string),re.UNICODE|extra_flags) _newline=make_regex('(\\r\\n|\\n|\\r)') _multiline_whitespace=make_regex('\\s*',extra_flags=re.MULTILINE) _whitespace=make_regex('[^\\S\\r\\n]*') _export=make_regex('(?:export[^\\S\\r\\n]+)?') _single_quoted_key=make_regex("'([^']+)'") _unquoted_key=make_regex('([^=\\#\\s]+)') _equal_sign=make_regex('(=[^\\S\\r\\n]*)') _single_quoted_value=make_regex("'((?:\\\\'|[^'])*)'") _double_quoted_value=make_regex('"((?:\\\\"|[^"])*)"') _unquoted_value_part=make_regex('([^ \\r\\n]*)') _comment=make_regex('(?:[^\\S\\r\\n]*#[^\\r\\n]*)?') _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]) class Position: def __init__(A,chars,line):A.chars=chars;A.line=line @classmethod def start(A):return A(chars=0,line=1) def set(A,other):B=other;A.chars=B.chars;A.line=B.line def advance(A,string):B=string;A.chars+=len(B);A.line+=len(re.findall(_newline,B)) class Error(Exception):0 class Reader: def __init__(A,stream):A.string=stream.read();A.position=Position.start();A.mark=Position.start() def has_next(A):return A.position.chars=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) version_info=_package_data['version_info'] __version__=_package_data['__version__'] try:from .cyaml import *;__with_libyaml__=True except (ImportError,ValueError):__with_libyaml__=_A from dynaconf.vendor.ruamel.yaml.main import *././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807557.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/anchor.py0000644000175000017500000000050600000000000024072 0ustar00rochacbrunorochacbruno_A=False if _A: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 __repr__(A):B=', (always dump)'if A.always_dump else'';return 'Anchor({!r}{})'.format(A.value,B)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807557.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/comments.py0000644000175000017500000004062700000000000024455 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import,print_function _G='_od' _F='CommentedMap' _E='# ' _D=True _C='\n' _B=False _A=None import sys,copy from .compat import ordereddict from .compat import PY2,string_types,MutableSliceableSequence from .scalarstring import ScalarString 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'] comment_attrib='_yaml_comment' format_attrib='_yaml_format' line_col_attrib='_yaml_line_col' merge_attrib='_yaml_merge' tag_attrib='_yaml_tag' class Comment: __slots__='comment','_items','_end','_start';attrib=comment_attrib def __init__(A):A.comment=_A;A._items={};A._end=[] def __str__(A): if bool(A._end):B=',\n end='+str(A._end) else:B='' return 'Comment(comment={0},\n items={1}{2})'.format(A.comment,A._items,B) @property def items(self):return self._items @property def end(self):return self._end @end.setter def end(self,value):self._end=value @property def start(self):return self._start @start.setter def start(self,value):self._start=value def NoComment():0 class Format: __slots__='_flow_style',;attrib=format_attrib def __init__(A):A._flow_style=_A def set_flow_style(A):A._flow_style=_D def set_block_style(A):A._flow_style=_B def flow_style(A,default=_A): if A._flow_style is _A:return default return A._flow_style class LineCol: attrib=line_col_attrib def __init__(A):A.line=_A;A.col=_A;A.data=_A def add_kv_line_col(A,key,data): if A.data is _A:A.data={} A.data[key]=data def key(A,k):return A._kv(k,0,1) def value(A,k):return A._kv(k,2,3) def _kv(A,k,x0,x1): if A.data is _A:return _A B=A.data[k];return B[x0],B[x1] def item(A,idx): if A.data is _A:return _A return A.data[idx][0],A.data[idx][1] def add_idx_line_col(A,key,data): if A.data is _A:A.data={} A.data[key]=data class Tag: __slots__='value',;attrib=tag_attrib def __init__(A):A.value=_A def __repr__(A):return '{0.__class__.__name__}({0.value!r})'.format(A) class CommentedBase: @property def ca(self): A=self if not hasattr(A,Comment.attrib):setattr(A,Comment.attrib,Comment()) return getattr(A,Comment.attrib) def yaml_end_comment_extend(A,comment,clear=_B): B=comment if B is _A:return if clear or A.ca.end is _A:A.ca.end=[] A.ca.end.extend(B) def yaml_key_comment_extend(C,key,comment,clear=_B): A=comment;B=C.ca._items.setdefault(key,[_A,_A,_A,_A]) if clear or B[1]is _A: if A[1]is not _A:assert isinstance(A[1],list) B[1]=A[1] else:B[1].extend(A[0]) B[0]=A[0] def yaml_value_comment_extend(C,key,comment,clear=_B): A=comment;B=C.ca._items.setdefault(key,[_A,_A,_A,_A]) if clear or B[3]is _A: if A[1]is not _A:assert isinstance(A[1],list) B[3]=A[1] else:B[3].extend(A[0]) B[2]=A[0] def yaml_set_start_comment(B,comment,indent=0): 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)) 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) 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] D=I(H);C=J.ca.items.setdefault(key,[_A,[],_A,_A]) if A==_C:C[1].append(F('',D)) elif A: for G in A.split(_C):C[1].append(F(G,D)) if B: D=I(E) if C[3]is _A:C[3]=[] for G in B.split(_C):C[3].append(F(G,D)) @property def fa(self): A=self 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 if B is _A: try:B=C._yaml_get_column(key) except AttributeError:B=0 if A[0]!=H:A=_E+A if B is _A: if A[0]==H: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): A=self if not hasattr(A,LineCol.attrib):setattr(A,LineCol.attrib,LineCol()) return getattr(A,LineCol.attrib) def _yaml_set_line_col(A,line,col):A.lc.line=line;A.lc.col=col def _yaml_set_kv_line_col(A,key,data):A.lc.add_kv_line_col(key,data) def _yaml_set_idx_line_col(A,key,data):A.lc.add_idx_line_col(key,data) @property def anchor(self): A=self if not hasattr(A,Anchor.attrib):setattr(A,Anchor.attrib,Anchor()) return getattr(A,Anchor.attrib) def yaml_anchor(A): if not hasattr(A,Anchor.attrib):return _A return A.anchor def yaml_set_anchor(A,value,always_dump=_B):A.anchor.value=value;A.anchor.always_dump=always_dump @property def tag(self): A=self if not hasattr(A,Tag.attrib):setattr(A,Tag.attrib,Tag()) return getattr(A,Tag.attrib) def yaml_set_tag(A,value):A.tag.value=value def copy_attributes(B,t,memo=_A): for A in [Comment.attrib,Format.attrib,LineCol.attrib,Anchor.attrib,Tag.attrib,merge_attrib]: if hasattr(B,A): if memo is not _A:setattr(t,A,copy.deepcopy(getattr(B,A,memo))) else:setattr(t,A,getattr(B,A)) def _yaml_add_eol_comment(A,comment,key):raise NotImplementedError def _yaml_get_pre_comment(A):raise NotImplementedError 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 __getsingleitem__(A,idx):return list.__getitem__(A,idx) def __setsingleitem__(B,idx,value): C=idx;A=value if C=C:break if D not in A.ca.items:continue B=D if B is not _A:E=A._yaml_get_columnX(B) return E def _yaml_get_pre_comment(A): B=[] if A.ca.comment is _A:A.ca.comment=[_A,B] else:A.ca.comment[1]=B return B def __deepcopy__(A,memo): C=memo;B=A.__class__();C[id(A)]=B for D in A:B.append(copy.deepcopy(D,C));A.copy_attributes(B,memo=C) return B def __add__(A,other):return list.__add__(A,other) def sort(A,key=_A,reverse=_B): C=reverse if key is _A:B=sorted(zip(A,range(len(A))),reverse=C);list.__init__(A,[A[0]for A in B]) else:B=sorted(zip(map(key,list.__iter__(A)),range(len(A))),reverse=C);list.__init__(A,[list.__getitem__(A,C[1])for C in B]) D=A.ca.items;A.ca._items={} for (F,G) in enumerate(B): E=G[1] if E in D:A.ca.items[F]=D[E] def __repr__(A):return list.__repr__(A) class CommentedKeySeq(tuple,CommentedBase): def _yaml_add_comment(A,comment,key=NoComment): B=comment if key is not NoComment:A.yaml_key_comment_extend(key,B) else:A.ca.comment=B def _yaml_add_eol_comment(A,comment,key):A._yaml_add_comment(comment,key=key) def _yaml_get_columnX(A,key):return A.ca.items[key][0].start_mark.column def _yaml_get_column(A,key): C=key;E=_A;B=_A;F,G=C-1,C+1 if F in A.ca.items:B=F elif G in A.ca.items:B=G else: for (D,H) in enumerate(A): if D>=C:break if D not in A.ca.items:continue B=D if B is not _A:E=A._yaml_get_columnX(B) return E def _yaml_get_pre_comment(A): B=[] if A.ca.comment is _A:A.ca.comment=[_A,B] else:A.ca.comment[1]=B return B class CommentedMapView(Sized): __slots__='_mapping', def __init__(A,mapping):A._mapping=mapping def __len__(A):B=len(A._mapping);return B class CommentedMapKeysView(CommentedMapView,Set): __slots__=() @classmethod def _from_iterable(A,it):return set(it) def __contains__(A,key):return key in A._mapping def __iter__(A): for B in A._mapping:yield B class CommentedMapItemsView(CommentedMapView,Set): __slots__=() @classmethod def _from_iterable(A,it):return set(it) def __contains__(A,item): B,C=item try:D=A._mapping[B] except KeyError:return _B else:return D==C def __iter__(A): for B in A._mapping._keys():yield(B,A._mapping[B]) class CommentedMapValuesView(CommentedMapView): __slots__=() def __contains__(A,value): for B in A._mapping: if value==A._mapping[B]:return _D return _B def __iter__(A): 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 _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 if C is not NoComment:A.yaml_value_comment_extend(C,B) else:A.ca.comment=B def _yaml_add_eol_comment(A,comment,key):A._yaml_add_comment(comment,value=key) def _yaml_get_columnX(A,key):return A.ca.items[key][2].start_mark.column def _yaml_get_column(A,key): E=key;H=_A;B=_A;C,F,I=_A,_A,_A for D in A: if C is not _A and D!=E:F=D;break if D==E:C=I I=D if C in A.ca.items:B=C elif F in A.ca.items:B=F else: for G in A: if G>=E:break if G not in A.ca.items:continue B=G if B is not _A:H=A._yaml_get_columnX(B) return H def _yaml_get_pre_comment(A): B=[] if A.ca.comment is _A:A.ca.comment=[_A,B] else:A.ca.comment[1]=B return B def update(B,vals): A=vals try:ordereddict.update(B,A) except TypeError: for C in A:B[C]=A[C] try:B._ok.update(A.keys()) except AttributeError: for C in A:B._ok.add(C[0]) def insert(A,pos,key,value,comment=_A): C=comment;B=key;ordereddict.insert(A,pos,B,value);A._ok.add(B) if C is not _A:A.yaml_add_eol_comment(C,key=B) def mlget(C,key,default=_A,list_ok=_B): D=list_ok;B=default;A=key if not isinstance(A,list):return C.get(A,B) def E(key_list,level,d): B=level;A=key_list if not D:assert isinstance(d,dict) if B>=len(A): if B>len(A):raise IndexError return d[A[B-1]] return E(A,B+1,d[A[B-1]]) try:return E(A,1,C) except KeyError:return B except (TypeError,IndexError): if not D:raise return B def __getitem__(B,key): A=key try:return ordereddict.__getitem__(B,A) except KeyError: for C in getattr(B,merge_attrib,[]): if A in C[1]:return C[1][A] raise def __setitem__(A,key,value): C=value;B=key if B in A: if isinstance(C,string_types)and not isinstance(C,ScalarString)and isinstance(A[B],ScalarString):C=type(A[B])(C) ordereddict.__setitem__(A,B,C);A._ok.add(B) def _unmerged_contains(A,key): if key in A._ok:return _D return _A def __contains__(A,key):return bool(ordereddict.__contains__(A,key)) 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 non_merged_items(A): for B in ordereddict.__iter__(A): if B in A._ok:yield(B,ordereddict.__getitem__(A,B)) def __delitem__(A,key): B=key;A._ok.discard(B);ordereddict.__delitem__(A,B) for C in A._ref:C.update_key_value(B) def __iter__(A): for B in ordereddict.__iter__(A):yield B def _keys(A): for B in ordereddict.__iter__(A):yield B def __len__(A):return int(ordereddict.__len__(A)) def __eq__(A,other):return bool(dict(A)==other) if PY2: def keys(A):return list(A._keys()) def iterkeys(A):return A._keys() def viewkeys(A):return CommentedMapKeysView(A) else: def keys(A):return CommentedMapKeysView(A) if PY2: def _values(A): for B in ordereddict.__iter__(A):yield ordereddict.__getitem__(A,B) def values(A):return list(A._values()) def itervalues(A):return A._values() def viewvalues(A):return CommentedMapValuesView(A) else: def values(A):return CommentedMapValuesView(A) def _items(A): for B in ordereddict.__iter__(A):yield(B,ordereddict.__getitem__(A,B)) if PY2: def items(A):return list(A._items()) def iteritems(A):return A._items() def viewitems(A):return CommentedMapItemsView(A) else: def items(A):return CommentedMapItemsView(A) @property def merge(self): A=self if not hasattr(A,merge_attrib):setattr(A,merge_attrib,[]) return getattr(A,merge_attrib) def copy(A): B=type(A)() for (C,D) in A._items():B[C]=D A.copy_attributes(B);return B def add_referent(A,cm): if cm not in A._ref:A._ref.append(cm) def add_yaml_merge(A,value): C=value for B in C: B[1].add_referent(A) for (D,B) in B[1].items(): if ordereddict.__contains__(A,D):continue ordereddict.__setitem__(A,D,B) A.merge.extend(C) def update_key_value(B,key): A=key if A in B._ok:return for C in B.merge: if A in C[1]:ordereddict.__setitem__(B,A,C[1][A]);return ordereddict.__delitem__(B,A) def __deepcopy__(A,memo): C=memo;B=A.__class__();C[id(A)]=B for D in A:B[D]=copy.deepcopy(A[D],C) A.copy_attributes(B,memo=C);return B @classmethod def raise_immutable(cls,*A,**B):raise TypeError('{} objects are immutable'.format(cls.__name__)) class CommentedKeyMap(CommentedBase,Mapping): __slots__=Comment.attrib,_G def __init__(A,*B,**C): if hasattr(A,_G):raise_immutable(A) try:A._od=ordereddict(*B,**C) except TypeError: if PY2:A._od=ordereddict(B[0].items()) else:raise __delitem__=__setitem__=clear=pop=popitem=setdefault=update=raise_immutable def __getitem__(A,index):return A._od[index] def __iter__(A): for B in A._od.__iter__():yield B def __len__(A):return len(A._od) def __hash__(A):return hash(tuple(A.items())) def __repr__(A): if not hasattr(A,merge_attrib):return A._od.__repr__() return'ordereddict('+repr(list(A._od.items()))+')' @classmethod def fromkeys(A,v=_A):return CommentedKeyMap(dict.fromkeys(A,v)) def _yaml_add_comment(A,comment,key=NoComment): B=comment if key is not NoComment:A.yaml_key_comment_extend(key,B) else:A.ca.comment=B def _yaml_add_eol_comment(A,comment,key):A._yaml_add_comment(comment,key=key) def _yaml_get_columnX(A,key):return A.ca.items[key][0].start_mark.column def _yaml_get_column(A,key): C=key;E=_A;B=_A;F,G=C-1,C+1 if F in A.ca.items:B=F elif G in A.ca.items:B=G else: for (D,H) in enumerate(A): if D>=C:break if D not in A.ca.items:continue B=D if B is not _A:E=A._yaml_get_columnX(B) return E def _yaml_get_pre_comment(A): B=[] if A.ca.comment is _A:A.ca.comment=[_A,B] else:A.ca.comment[1]=B return B class CommentedOrderedMap(CommentedMap):__slots__=Comment.attrib, class CommentedSet(MutableSet,CommentedBase): __slots__=Comment.attrib,'odict' def __init__(A,values=_A): B=values;A.odict=ordereddict();MutableSet.__init__(A) if B is not _A:A|=B 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 if C is not NoComment:A.yaml_value_comment_extend(C,B) else:A.ca.comment=B def _yaml_add_eol_comment(A,comment,key):A._yaml_add_comment(comment,value=key) def add(A,value):A.odict[value]=_A def discard(A,value):del A.odict[value] def __contains__(A,x):return x in A.odict def __iter__(A): for B in A.odict:yield B def __len__(A):return len(A.odict) def __repr__(A):return 'set({0!r})'.format(A.odict.keys()) class TaggedScalar(CommentedBase): def __init__(A,value=_A,style=_A,tag=_A): A.value=value;A.style=style 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): 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): 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)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807557.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/compat.py0000644000175000017500000001056200000000000024106 0ustar00rochacbrunorochacbrunofrom __future__ import print_function _D='RUAMELDEBUG' _C=True _B=False _A=None import sys,os,types,traceback from abc import abstractmethod if _B:from typing import Any,Dict,Optional,List,Union,BinaryIO,IO,Text,Tuple,Optional _DEFAULT_YAML_VERSION=1,2 try:from ruamel.ordereddict import ordereddict except: try:from collections import OrderedDict except ImportError:from ordereddict import OrderedDict class ordereddict(OrderedDict): if not hasattr(OrderedDict,'insert'): def insert(A,pos,key,value): C=value if pos>=len(A):A[key]=C;return B=ordereddict();B.update(A) for E in B:del A[E] for (F,D) in enumerate(B): if pos==F:A[key]=C A[D]=B[D] PY2=sys.version_info[0]==2 PY3=sys.version_info[0]==3 if PY3: def utf8(s):return s def to_str(s):return s def to_unicode(s):return s else: if _B:unicode=str def utf8(s):return s.encode('utf-8') def to_str(s):return str(s) def to_unicode(s):return unicode(s) if PY3:string_types=str;integer_types=int;class_types=type;text_type=str;binary_type=bytes;MAXSIZE=sys.maxsize;unichr=chr;import io;StringIO=io.StringIO;BytesIO=io.BytesIO;no_limit_int=int;from collections.abc import Hashable,MutableSequence,MutableMapping,Mapping else:string_types=basestring;integer_types=int,long;class_types=type,types.ClassType;text_type=unicode;binary_type=str;unichr=unichr;from StringIO import StringIO as _StringIO;StringIO=_StringIO;import cStringIO;BytesIO=cStringIO.StringIO;no_limit_int=long;from collections import Hashable,MutableSequence,MutableMapping,Mapping if _B:StreamType=Any;StreamTextType=StreamType;VersionType=Union[List[int],str,Tuple[int,int]] if PY3:builtins_module='builtins' else:builtins_module='__builtin__' UNICODE_SIZE=4 if sys.maxunicode>65535 else 2 def with_metaclass(meta,*A):return meta('NewBase',A,{}) DBG_TOKEN=1 DBG_EVENT=2 DBG_NODE=4 _debug=_A if _D in os.environ: _debugx=os.environ.get(_D) if _debugx is _A:_debug=0 else:_debug=int(_debugx) if bool(_debug): class ObjectCounter: def __init__(A):A.map={} def __call__(A,k):A.map[k]=A.map.get(k,0)+1 def dump(A): for B in sorted(A.map):sys.stdout.write('{} -> {}'.format(B,A.map[B])) object_counter=ObjectCounter() def dbg(val=_A): global _debug if _debug is _A: A=os.environ.get('YAMLDEBUG') if A is _A:_debug=0 else:_debug=int(A) if val is _A:return _debug return _debug&val 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() if A._max_print is not _A: if A._count is _A:A._count=A._max_print A._count-=1 if A._count==0:C('forced exit\n');traceback.print_stack();B.flush();sys.exit(0) if A._file_name:B.close() def set_max_print(A,i):A._max_print=i;A._count=_A nprint=Nprint() nprintf=Nprint('/var/tmp/ruamel.yaml.log') def check_namespace_char(ch): A=ch if'!'<=A<='~':return _C if'\xa0'<=A<='\ud7ff':return _C if'\ue000'<=A<='�'and A!='\ufeff':return _C if'𐀀'<=A<='\U0010ffff':return _C return _B def check_anchorname_char(ch): if ch in',[]{}':return _B return check_namespace_char(ch) def version_tnf(t1,t2=_A): from dynaconf.vendor.ruamel.yaml import version_info as A if Alen(B):raise TypeError('not enough elements in value {} > {}'.format(E,len(B))) 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) for C in reversed(range(*B.indices(len(A)))):del A[C] @abstractmethod def __getsingleitem__(self,index):raise IndexError @abstractmethod def __setsingleitem__(self,index,value):raise IndexError @abstractmethod def __delsingleitem__(self,index):raise IndexError././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807558.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/composer.py0000644000175000017500000000772700000000000024463 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import,print_function _B='typ' _A=None import warnings from .error import MarkedYAMLError,ReusedAnchorWarning from .compat import utf8,nprint,nprintf from .events import StreamStartEvent,StreamEndEvent,MappingStartEvent,MappingEndEvent,SequenceStartEvent,SequenceEndEvent,AliasEvent,ScalarEvent from .nodes import MappingNode,ScalarNode,SequenceNode if False:from typing import Any,Dict,Optional,List __all__=['Composer','ComposerError'] class ComposerError(MarkedYAMLError):0 class Composer: def __init__(A,loader=_A): A.loader=loader if A.loader is not _A and getattr(A.loader,'_composer',_A)is _A:A.loader._composer=A A.anchors={} @property def parser(self): A=self if hasattr(A.loader,_B):A.loader.parser return A.loader._parser @property def resolver(self): A=self if hasattr(A.loader,_B):A.loader.resolver return A.loader._resolver def check_node(A): if A.parser.check_event(StreamStartEvent):A.parser.get_event() return not A.parser.check_event(StreamEndEvent) def get_node(A): if not A.parser.check_event(StreamEndEvent):return A.compose_document() def get_single_node(A): A.parser.get_event();B=_A if not A.parser.check_event(StreamEndEvent):B=A.compose_document() if not A.parser.check_event(StreamEndEvent):C=A.parser.get_event();raise ComposerError('expected a single document in the stream',B.start_mark,'but found another document',C.start_mark) A.parser.get_event();return B def compose_document(A):A.parser.get_event();B=A.compose_node(_A,_A);A.parser.get_event();A.anchors={};return B def compose_node(A,parent,index): if A.parser.check_event(AliasEvent): C=A.parser.get_event();D=C.anchor if D not in A.anchors:raise ComposerError(_A,_A,'found undefined alias %r'%utf8(D),C.start_mark) return A.anchors[D] C=A.parser.peek_event();B=C.anchor if B is not _A: if B in A.anchors:F='\nfound duplicate anchor {!r}\nfirst occurrence {}\nsecond occurrence {}'.format(B,A.anchors[B].start_mark,C.start_mark);warnings.warn(F,ReusedAnchorWarning) A.resolver.descend_resolver(parent,index) if A.parser.check_event(ScalarEvent):E=A.compose_scalar_node(B) elif A.parser.check_event(SequenceStartEvent):E=A.compose_sequence_node(B) elif A.parser.check_event(MappingStartEvent):E=A.compose_mapping_node(B) A.resolver.ascend_resolver();return E def compose_scalar_node(C,anchor): D=anchor;A=C.parser.get_event();B=A.tag if B is _A or B=='!':B=C.resolver.resolve(ScalarNode,A.value,A.implicit) E=ScalarNode(B,A.value,A.start_mark,A.end_mark,style=A.style,comment=A.comment,anchor=D) if D is not _A:C.anchors[D]=E return E def compose_sequence_node(B,anchor): F=anchor;C=B.parser.get_event();D=C.tag if D is _A or D=='!':D=B.resolver.resolve(SequenceNode,_A,C.implicit) A=SequenceNode(D,[],C.start_mark,_A,flow_style=C.flow_style,comment=C.comment,anchor=F) if F is not _A:B.anchors[F]=A G=0 while not B.parser.check_event(SequenceEndEvent):A.value.append(B.compose_node(A,G));G+=1 E=B.parser.get_event() if A.flow_style is True and E.comment is not _A: if A.comment is not _A:nprint('Warning: unexpected end_event commment in sequence node {}'.format(A.flow_style)) A.comment=E.comment A.end_mark=E.end_mark;B.check_end_doc_comment(E,A);return A def compose_mapping_node(B,anchor): F=anchor;C=B.parser.get_event();D=C.tag if D is _A or D=='!':D=B.resolver.resolve(MappingNode,_A,C.implicit) A=MappingNode(D,[],C.start_mark,_A,flow_style=C.flow_style,comment=C.comment,anchor=F) if F is not _A:B.anchors[F]=A while not B.parser.check_event(MappingEndEvent):G=B.compose_node(A,_A);H=B.compose_node(A,G);A.value.append((G,H)) E=B.parser.get_event() if A.flow_style is True and E.comment is not _A:A.comment=E.comment A.end_mark=E.end_mark;B.check_end_doc_comment(E,A);return A def check_end_doc_comment(C,end_event,node): B=node;A=end_event if A.comment and A.comment[1]: if B.comment is _A:B.comment=[_A,_A] assert not isinstance(B,ScalarEvent);B.comment.append(A.comment[1]);A.comment[1]=_A././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807558.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/configobjwalker.py0000644000175000017500000000037600000000000025773 0ustar00rochacbrunorochacbrunoimport warnings from .util import configobj_walker as new_configobj_walker if False:from typing import Any def configobj_walker(cfg):warnings.warn('configobj_walker has moved to ruamel.yaml.util, please update your code');return new_configobj_walker(cfg)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807558.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/constructor.py0000644000175000017500000011762700000000000025222 0ustar00rochacbrunorochacbrunofrom __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='-' _I='fraction' _H='.' _G=':' _F='0' _E='while constructing a mapping' _D='_' _C=True _B=False _A=None import datetime,base64,binascii,re,sys,types,warnings from .error import MarkedYAMLError,MarkedYAMLFutureWarning,MantissaNoDotYAML1_1Warning from .nodes import * from .nodes import SequenceNode,MappingNode,ScalarNode from .compat import utf8,builtins_module,to_str,PY2,PY3,text_type,nprint,nprintf,version_tnf from .compat import ordereddict,Hashable,MutableSequence from .compat import MutableMapping from .comments import * from .comments import CommentedMap,CommentedOrderedMap,CommentedSet,CommentedKeySeq,CommentedSeq,TaggedScalar,CommentedKeyMap from .scalarstring import SingleQuotedScalarString,DoubleQuotedScalarString,LiteralScalarString,FoldedScalarString,PlainScalarString,ScalarString from .scalarint import ScalarInt,BinaryInt,OctalInt,HexInt,HexCapsInt from .scalarfloat import ScalarFloat from .scalarbool import ScalarBoolean from .timestamp import TimeStamp from .util import RegExp if _B:from typing import Any,Dict,List,Set,Generator,Union,Optional __all__=['BaseConstructor','SafeConstructor','Constructor','ConstructorError','RoundTripConstructor'] class ConstructorError(MarkedYAMLError):0 class DuplicateKeyFutureWarning(MarkedYAMLFutureWarning):0 class DuplicateKeyError(MarkedYAMLFutureWarning):0 class BaseConstructor: yaml_constructors={};yaml_multi_constructors={} def __init__(self,preserve_quotes=_A,loader=_A): self.loader=loader if self.loader is not _A and getattr(self.loader,'_constructor',_A)is _A:self.loader._constructor=self 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 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 return self.loader._resolver def check_data(self):return self.composer.check_node() def get_data(self): if self.composer.check_node():return self.construct_document(self.composer.get_node()) def get_single_data(self): node=self.composer.get_single_node() if node is not _A:return self.construct_document(node) return _A def construct_document(self,node): data=self.construct_object(node) while bool(self.state_generators): state_generators=self.state_generators;self.state_generators=[] for generator in state_generators: for _dummy in generator:0 self.constructed_objects={};self.recursive_objects={};self.deep_construct=_B;return data def construct_object(self,node,deep=_B): if node in self.constructed_objects:return self.constructed_objects[node] if deep:old_deep=self.deep_construct;self.deep_construct=_C if node in self.recursive_objects:return self.recursive_objects[node] self.recursive_objects[node]=_A;data=self.construct_non_recursive_object(node);self.constructed_objects[node]=data;del self.recursive_objects[node] if deep:self.deep_construct=old_deep return data def construct_non_recursive_object(self,node,tag=_A): constructor=_A;tag_suffix=_A if tag is _A:tag=node.tag if tag in self.yaml_constructors:constructor=self.yaml_constructors[tag] else: for tag_prefix in self.yaml_multi_constructors: if tag.startswith(tag_prefix):tag_suffix=tag[len(tag_prefix):];constructor=self.yaml_multi_constructors[tag_prefix];break else: if _A in self.yaml_multi_constructors:tag_suffix=tag;constructor=self.yaml_multi_constructors[_A] elif _A in self.yaml_constructors:constructor=self.yaml_constructors[_A] elif isinstance(node,ScalarNode):constructor=self.__class__.construct_scalar elif isinstance(node,SequenceNode):constructor=self.__class__.construct_sequence elif isinstance(node,MappingNode):constructor=self.__class__.construct_mapping if tag_suffix is _A:data=constructor(self,node) else:data=constructor(self,tag_suffix,node) if isinstance(data,types.GeneratorType): generator=data;data=next(generator) if self.deep_construct: for _dummy in generator:0 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) 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) 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) 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)] for (values,check) in todo: mapping=self.yaml_base_dict_type() for (key_node,value_node) in values: key=self.construct_object(key_node,deep=_C) if not isinstance(key,Hashable): 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) value=self.construct_object(value_node,deep=deep) if check: if self.check_mapping_key(node,key_node,mapping,key,value):mapping[key]=value else:mapping[key]=value total_mapping.update(mapping) return total_mapping def check_mapping_key(self,node,key_node,mapping,key,value): if key in mapping: 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) 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) def construct_pairs(self,node,deep=_B): if not isinstance(node,MappingNode):raise ConstructorError(_A,_A,_P%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 @classmethod def add_constructor(cls,tag,constructor): if'yaml_constructors'not in cls.__dict__:cls.yaml_constructors=cls.yaml_constructors.copy() cls.yaml_constructors[tag]=constructor @classmethod def add_multi_constructor(cls,tag_prefix,multi_constructor): if'yaml_multi_constructors'not in cls.__dict__:cls.yaml_multi_constructors=cls.yaml_multi_constructors.copy() cls.yaml_multi_constructors[tag_prefix]=multi_constructor 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) return BaseConstructor.construct_scalar(self,node) def flatten_mapping(self,node): merge=[];index=0 while index[0-9][0-9][0-9][0-9])\n -(?P[0-9][0-9]?)\n -(?P[0-9][0-9]?)\n (?:((?P[Tt])|[ \\t]+) # explictly not retaining extra spaces\n (?P[0-9][0-9]?)\n :(?P[0-9][0-9])\n :(?P[0-9][0-9])\n (?:\\.(?P[0-9]*))?\n (?:[ \\t]*(?PZ|(?P[-+])(?P[0-9][0-9]?)\n (?::(?P[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) 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 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 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) 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) 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) 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) 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) 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) 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) SafeConstructor.add_constructor(_A,SafeConstructor.construct_undefined) if PY2: class classobj:0 class Constructor(SafeConstructor): def construct_python_str(self,node):return utf8(self.construct_scalar(node)) 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: if hasattr(base64,_s):return base64.decodebytes(value) else:return base64.decodestring(value) except binascii.Error as exc:raise ConstructorError(_A,_A,_a%exc,node.start_mark) def construct_python_long(self,node): val=self.construct_yaml_int(node) if PY3:return val return int(val) 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) try:__import__(name) except ImportError as exc:raise ConstructorError(_e,mark,_AC%(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 _H in name: lname=name.split(_H);lmodule_name=lname;lobject_name=[] while len(lmodule_name)>1: lobject_name.insert(0,lmodule_name.pop());module_name=_H.join(lmodule_name) try:__import__(module_name);break 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) 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) obj=getattr(obj,lobject_name.pop(0)) 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) 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) 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) 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) def set_python_instance_state(self,instance,state): if hasattr(instance,_V):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_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',{}) instance=self.make_python_instance(suffix,node,args,kwds,newobj) if bool(state):self.set_python_instance_state(instance,state) if bool(listitems):instance.extend(listitems) if bool(dictitems): for key in dictitems:instance[key]=dictitems[key] return instance def construct_python_object_new(self,suffix,node):return self.construct_python_object_apply(suffix,node,newobj=_C) Constructor.add_constructor('tag:yaml.org,2002:python/none',Constructor.construct_yaml_null) Constructor.add_constructor('tag:yaml.org,2002:python/bool',Constructor.construct_yaml_bool) Constructor.add_constructor('tag:yaml.org,2002:python/str',Constructor.construct_python_str) Constructor.add_constructor('tag:yaml.org,2002:python/unicode',Constructor.construct_python_unicode) if PY3:Constructor.add_constructor('tag:yaml.org,2002:python/bytes',Constructor.construct_python_bytes) Constructor.add_constructor('tag:yaml.org,2002:python/int',Constructor.construct_yaml_int) Constructor.add_constructor('tag:yaml.org,2002:python/long',Constructor.construct_python_long) Constructor.add_constructor('tag:yaml.org,2002:python/float',Constructor.construct_yaml_float) Constructor.add_constructor('tag:yaml.org,2002:python/complex',Constructor.construct_python_complex) Constructor.add_constructor('tag:yaml.org,2002:python/list',Constructor.construct_yaml_seq) Constructor.add_constructor('tag:yaml.org,2002:python/tuple',Constructor.construct_python_tuple) Constructor.add_constructor('tag:yaml.org,2002:python/dict',Constructor.construct_yaml_map) Constructor.add_multi_constructor('tag:yaml.org,2002:python/name:',Constructor.construct_python_name) Constructor.add_multi_constructor('tag:yaml.org,2002:python/module:',Constructor.construct_python_module) Constructor.add_multi_constructor('tag:yaml.org,2002:python/object:',Constructor.construct_python_object) Constructor.add_multi_constructor('tag:yaml.org,2002:python/object/apply:',Constructor.construct_python_object_apply) Constructor.add_multi_constructor('tag:yaml.org,2002:python/object/new:',Constructor.construct_python_object_new) 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 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] return lss if node.style=='>'and isinstance(node.value,text_type): fold_positions=[];idx=-1 while _C: idx=node.value.find(A,idx+1) if idx<0:break fold_positions.append(idx-len(fold_positions)) fss=FoldedScalarString(node.value.replace(A,''),anchor=node.anchor) if node.comment and node.comment[1]:fss.comment=node.comment[1][0] if fold_positions:fss.fold_pos=fold_positions return fss elif bool(self._preserve_quotes)and isinstance(node.value,text_type): if node.style=="'":return SingleQuotedScalarString(node.value,anchor=node.anchor) if node.style=='"':return DoubleQuotedScalarString(node.value,anchor=node.anchor) if node.anchor:return PlainScalarString(node.value,anchor=node.anchor) return node.value def construct_yaml_int(self,node): width=_A;value_su=to_str(self.construct_scalar(node)) try:sx=value_su.rstrip(_D);underscore=[len(sx)-sx.rindex(_D)-1,_B,_B] 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==_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:]) if underscore is not _A:underscore[1]=value_su[2]==_D;underscore[2]=len(value_su[2:])>1 and value_su[-1]==_D return BinaryInt(sign*int(value_s[2:],2),width=width,underscore=underscore,anchor=node.anchor) elif value_s.startswith('0x'): if self.resolver.processing_version>(1,1)and value_s[2]==_F:width=len(value_s[2:]) hex_fun=HexInt for ch in value_s[2:]: if ch in'ABCDEF':hex_fun=HexCapsInt;break if ch in'abcdef':break if underscore is not _A:underscore[1]=value_su[2]==_D;underscore[2]=len(value_su[2:])>1 and value_su[-1]==_D return hex_fun(sign*int(value_s[2:],16),width=width,underscore=underscore,anchor=node.anchor) elif value_s.startswith('0o'): if self.resolver.processing_version>(1,1)and value_s[2]==_F:width=len(value_s[2:]) if underscore is not _A:underscore[1]=value_su[2]==_D;underscore[2]=len(value_su[2:])>1 and value_su[-1]==_D return OctalInt(sign*int(value_s[2:],8),width=width,underscore=underscore,anchor=node.anchor) elif self.resolver.processing_version!=(1,2)and value_s[0]==_F:return sign*int(value_s,8) elif self.resolver.processing_version!=(1,2)and _G in value_s: digits=[int(part)for part in value_s.split(_G)];digits.reverse();base=1;value=0 for digit in digits:value+=digit*base;base*=60 return sign*value elif self.resolver.processing_version>(1,1)and value_s[0]==_F: if underscore is not _A:underscore[2]=len(value_su)>1 and value_su[-1]==_D return ScalarInt(sign*int(value_s),width=len(value_s),underscore=underscore) elif underscore:underscore[2]=len(value_su)>1 and value_su[-1]==_D;return ScalarInt(sign*int(value_s),width=_A,underscore=underscore,anchor=node.anchor) 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 idx2:seqtyp.yaml_end_comment_extend(node.comment[2],clear=_C) if node.anchor: from dynaconf.vendor.ruamel.yaml.serializer import templated_id if not templated_id(node.anchor):seqtyp.yaml_set_anchor(node.anchor) for (idx,child) in enumerate(node.value): if child.comment:seqtyp._yaml_add_comment(child.comment,key=idx);child.comment=_A ret_val.append(self.construct_object(child,deep=deep));seqtyp._yaml_set_idx_line_col(idx,[child.start_mark.line,child.start_mark.column]) return ret_val def flatten_mapping(self,node): def constructed(value_node): if value_node in self.constructed_objects:value=self.constructed_objects[value_node] else:value=self.construct_object(value_node,deep=_B) return value merge_map_list=[];index=0 while index2:maptyp.yaml_end_comment_extend(node.comment[2],clear=_C) if node.anchor: from dynaconf.vendor.ruamel.yaml.serializer import templated_id if not templated_id(node.anchor):maptyp.yaml_set_anchor(node.anchor) last_key,last_value=_A,self._sentinel for (key_node,value_node) in node.value: key=self.construct_object(key_node,deep=_C) if not isinstance(key,Hashable): if isinstance(key,MutableSequence): key_s=CommentedKeySeq(key) if key_node.flow_style is _C:key_s.fa.set_flow_style() elif key_node.flow_style is _B:key_s.fa.set_block_style() key=key_s elif isinstance(key,MutableMapping): key_m=CommentedKeyMap(key) if key_node.flow_style is _C:key_m.fa.set_flow_style() elif key_node.flow_style is _B:key_m.fa.set_block_style() 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) 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]: if last_value is _A:key_node.comment[0]=key_node.comment.pop(4);maptyp._yaml_add_comment(key_node.comment,value=last_key) else:key_node.comment[2]=key_node.comment.pop(4);maptyp._yaml_add_comment(key_node.comment,key=key) key_node.comment=_A if key_node.comment:maptyp._yaml_add_comment(key_node.comment,key=key) if value_node.comment:maptyp._yaml_add_comment(value_node.comment,value=key) 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 node.comment: typ._yaml_add_comment(node.comment[:2]) if len(node.comment)>2:typ.yaml_end_comment_extend(node.comment[2],clear=_C) if node.anchor: from dynaconf.vendor.ruamel.yaml.serializer import templated_id if not templated_id(node.anchor):typ.yaml_set_anchor(node.anchor) for (key_node,value_node) in node.value: key=self.construct_object(key_node,deep=_C) if not isinstance(key,Hashable): 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) 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) typ.add(key) def construct_yaml_seq(self,node): data=CommentedSeq();data._yaml_set_line_col(node.start_mark.line,node.start_mark.column) if node.comment:data._yaml_add_comment(node.comment) yield data;data.extend(self.construct_rt_sequence(node,data));self.set_collection_style(data,node) def construct_yaml_map(self,node):data=CommentedMap();data._yaml_set_line_col(node.start_mark.line,node.start_mark.column);yield data;self.construct_mapping(node,data,deep=_C);self.set_collection_style(data,node) def set_collection_style(self,data,node): if len(data)==0:return if node.flow_style is _C:data.fa.set_flow_style() 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) 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) if node.flow_style is _C:omap.fa.set_flow_style() elif node.flow_style is _B:omap.fa.set_block_style() yield omap 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) 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) 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) if value_node.comment:omap._yaml_add_comment(value_node.comment,value=key) omap[key]=value def construct_yaml_set(self,node):data=CommentedSet();data._yaml_set_line_col(node.start_mark.line,node.start_mark.column);yield data;self.construct_setting(node,data) def construct_undefined(self,node): try: if isinstance(node,MappingNode): data=CommentedMap();data._yaml_set_line_col(node.start_mark.line,node.start_mark.column) if node.flow_style is _C:data.fa.set_flow_style() elif node.flow_style is _B:data.fa.set_block_style() data.yaml_set_tag(node.tag);yield data if node.anchor:data.yaml_set_anchor(node.anchor) self.construct_mapping(node,data);return elif isinstance(node,ScalarNode): data2=TaggedScalar();data2.value=self.construct_scalar(node);data2.style=node.style;data2.yaml_set_tag(node.tag);yield data2 if node.anchor:data2.yaml_set_anchor(node.anchor,always_dump=_C) return elif isinstance(node,SequenceNode): data3=CommentedSeq();data3._yaml_set_line_col(node.start_mark.line,node.start_mark.column) if node.flow_style is _C:data3.fa.set_flow_style() elif node.flow_style is _B:data3.fa.set_block_style() data3.yaml_set_tag(node.tag);yield data3 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) 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) values=match.groupdict() if not values[_T]:return SafeConstructor.construct_yaml_timestamp(self,node,values) for part in [B,_K,_U,_O]: 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 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 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] data._yaml[A]=tz else: data=TimeStamp(year,month,day,hour,minute,second,fraction) if values[A]:data._yaml[A]=values[A] if values[B]:data._yaml[B]=_C return data def construct_yaml_bool(self,node): 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(_A,RoundTripConstructor.construct_undefined)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807558.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/cyaml.py0000644000175000017500000000627500000000000023736 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import _A=None from _ruamel_yaml import CParser,CEmitter from .constructor import Constructor,BaseConstructor,SafeConstructor from .representer import Representer,SafeRepresenter,BaseRepresenter from .resolver import Resolver,BaseResolver if False:from typing import Any,Union,Optional;from .compat import StreamTextType,StreamType,VersionType __all__=['CBaseLoader','CSafeLoader','CLoader','CBaseDumper','CSafeDumper','CDumper'] class CBaseLoader(CParser,BaseConstructor,BaseResolver): def __init__(A,stream,version=_A,preserve_quotes=_A):CParser.__init__(A,stream);A._parser=A._composer=A;BaseConstructor.__init__(A,loader=A);BaseResolver.__init__(A,loadumper=A) class CSafeLoader(CParser,SafeConstructor,Resolver): def __init__(A,stream,version=_A,preserve_quotes=_A):CParser.__init__(A,stream);A._parser=A._composer=A;SafeConstructor.__init__(A,loader=A);Resolver.__init__(A,loadumper=A) class CLoader(CParser,Constructor,Resolver): def __init__(A,stream,version=_A,preserve_quotes=_A):CParser.__init__(A,stream);A._parser=A._composer=A;Constructor.__init__(A,loader=A);Resolver.__init__(A,loadumper=A) class CBaseDumper(CEmitter,BaseRepresenter,BaseResolver): def __init__(A,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__(A,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);A._emitter=A._serializer=A._representer=A;BaseRepresenter.__init__(A,default_style=default_style,default_flow_style=default_flow_style,dumper=A);BaseResolver.__init__(A,loadumper=A) class CSafeDumper(CEmitter,SafeRepresenter,Resolver): def __init__(A,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):A._emitter=A._serializer=A._representer=A;CEmitter.__init__(A,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);A._emitter=A._serializer=A._representer=A;SafeRepresenter.__init__(A,default_style=default_style,default_flow_style=default_flow_style);Resolver.__init__(A) class CDumper(CEmitter,Representer,Resolver): def __init__(A,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__(A,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);A._emitter=A._serializer=A._representer=A;Representer.__init__(A,default_style=default_style,default_flow_style=default_flow_style);Resolver.__init__(A)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807558.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/dumper.py0000644000175000017500000000667500000000000024131 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import _A=None from .emitter import Emitter from .serializer import Serializer from .representer import Representer,SafeRepresenter,BaseRepresenter,RoundTripRepresenter from .resolver import Resolver,BaseResolver,VersionedResolver if False:from typing import Any,Dict,List,Union,Optional;from .compat import StreamType,VersionType __all__=['BaseDumper','SafeDumper','Dumper','RoundTripDumper'] class BaseDumper(Emitter,Serializer,BaseRepresenter,BaseResolver): def __init__(A,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):Emitter.__init__(A,stream,canonical=canonical,indent=indent,width=width,allow_unicode=allow_unicode,line_break=line_break,block_seq_indent=block_seq_indent,dumper=A);Serializer.__init__(A,encoding=encoding,explicit_start=explicit_start,explicit_end=explicit_end,version=version,tags=tags,dumper=A);BaseRepresenter.__init__(A,default_style=default_style,default_flow_style=default_flow_style,dumper=A);BaseResolver.__init__(A,loadumper=A) class SafeDumper(Emitter,Serializer,SafeRepresenter,Resolver): def __init__(A,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):Emitter.__init__(A,stream,canonical=canonical,indent=indent,width=width,allow_unicode=allow_unicode,line_break=line_break,block_seq_indent=block_seq_indent,dumper=A);Serializer.__init__(A,encoding=encoding,explicit_start=explicit_start,explicit_end=explicit_end,version=version,tags=tags,dumper=A);SafeRepresenter.__init__(A,default_style=default_style,default_flow_style=default_flow_style,dumper=A);Resolver.__init__(A,loadumper=A) class Dumper(Emitter,Serializer,Representer,Resolver): def __init__(A,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):Emitter.__init__(A,stream,canonical=canonical,indent=indent,width=width,allow_unicode=allow_unicode,line_break=line_break,block_seq_indent=block_seq_indent,dumper=A);Serializer.__init__(A,encoding=encoding,explicit_start=explicit_start,explicit_end=explicit_end,version=version,tags=tags,dumper=A);Representer.__init__(A,default_style=default_style,default_flow_style=default_flow_style,dumper=A);Resolver.__init__(A,loadumper=A) class RoundTripDumper(Emitter,Serializer,RoundTripRepresenter,VersionedResolver): def __init__(A,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):Emitter.__init__(A,stream,canonical=canonical,indent=indent,width=width,allow_unicode=allow_unicode,line_break=line_break,block_seq_indent=block_seq_indent,top_level_colon_align=top_level_colon_align,prefix_colon=prefix_colon,dumper=A);Serializer.__init__(A,encoding=encoding,explicit_start=explicit_start,explicit_end=explicit_end,version=version,tags=tags,dumper=A);RoundTripRepresenter.__init__(A,default_style=default_style,default_flow_style=default_flow_style,dumper=A);VersionedResolver.__init__(A,loader=A)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807559.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/emitter.py0000644000175000017500000010603000000000000024270 0ustar00rochacbrunorochacbrunofrom __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='[' _J="'" _I='?' _H='"' _G='!' _F='\n\x85\u2028\u2029' _E='\n' _D=' ' _C=False _B=None _A=True import sys from .error import YAMLError,YAMLStreamError from .events import * from .compat import utf8,text_type,PY2,nprint,dbg,DBG_EVENT,check_anchorname_char if _C:from typing import Any,Dict,List,Union,Text,Tuple,Optional;from .compat import StreamType __all__=['Emitter','EmitterError'] class EmitterError(YAMLError):0 class ScalarAnalysis: def __init__(self,scalar,empty,multiline,allow_flow_plain,allow_block_plain,allow_single_quoted,allow_double_quoted,allow_block):self.scalar=scalar;self.empty=empty;self.multiline=multiline;self.allow_flow_plain=allow_flow_plain;self.allow_block_plain=allow_block_plain;self.allow_single_quoted=allow_single_quoted;self.allow_double_quoted=allow_double_quoted;self.allow_block=allow_block class Indents: def __init__(self):self.values=[] def append(self,val,seq):self.values.append((val,seq)) def pop(self):return self.values.pop()[0] def last_seq(self): try:return self.values[-2][1] except IndexError:return _C def seq_flow_align(self,seq_indent,column): if len(self.values)<2 or not self.values[-1][1]:return 0 base=self.values[-1][0]if self.values[-1][0]is not _B else 0;return base+seq_indent-column-1 def __len__(self):return len(self.values) class Emitter: DEFAULT_TAG_PREFIXES={_G:_G,'tag:yaml.org,2002:':'!!'};MAX_SIMPLE_KEY_LENGTH=128 def __init__(self,stream,canonical=_B,indent=_B,width=_B,allow_unicode=_B,line_break=_B,block_seq_indent=_B,top_level_colon_align=_B,prefix_colon=_B,brace_single_entry_mapping_in_flow_sequence=_B,dumper=_B): self.dumper=dumper if self.dumper is not _B and getattr(self.dumper,'_emitter',_B)is _B:self.dumper._emitter=self self.stream=stream;self.encoding=_B;self.allow_space_break=_B;self.states=[];self.state=self.expect_stream_start;self.events=[];self.event=_B;self.indents=Indents();self.indent=_B;self.flow_context=[];self.root_context=_C;self.sequence_context=_C;self.mapping_context=_C;self.simple_key_context=_C;self.line=0;self.column=0;self.whitespace=_A;self.indention=_A;self.compact_seq_seq=_A;self.compact_seq_map=_A;self.no_newline=_B;self.open_ended=_C;self.colon=':';self.prefixed_colon=self.colon if prefix_colon is _B else prefix_colon+self.colon;self.brace_single_entry_mapping_in_flow_sequence=brace_single_entry_mapping_in_flow_sequence;self.canonical=canonical;self.allow_unicode=allow_unicode;self.unicode_supplementary=sys.maxunicode>65535;self.sequence_dash_offset=block_seq_indent if block_seq_indent else 0;self.top_level_colon_align=top_level_colon_align;self.best_sequence_indent=2;self.requested_indent=indent if indent and 1self.best_sequence_indent*2:self.best_width=width self.best_line_break=_E if line_break in['\r',_E,'\r\n']:self.best_line_break=line_break self.tag_prefixes=_B;self.prepared_anchor=_B;self.prepared_tag=_B;self.analysis=_B;self.style=_B;self.scalar_after_indicator=_A @property def stream(self): try:return self._stream except AttributeError:raise YAMLStreamError('output stream needs to specified') @stream.setter def stream(self,val): if val is _B:return if not hasattr(val,'write'):raise YAMLStreamError('stream argument needs to have a write() method') self._stream=val @property def serializer(self): try: if hasattr(self.dumper,'typ'):return self.dumper.serializer return self.dumper._serializer except AttributeError:return self @property def flow_level(self):return len(self.flow_context) def dispose(self):self.states=[];self.state=_B def emit(self,event): if dbg(DBG_EVENT):nprint(event) self.events.append(event) while not self.need_more_events():self.event=self.events.pop(0);self.state();self.event=_B def need_more_events(self): if not self.events:return _A event=self.events[0] if isinstance(event,DocumentStartEvent):return self.need_events(1) elif isinstance(event,SequenceStartEvent):return self.need_events(2) elif isinstance(event,MappingStartEvent):return self.need_events(3) else:return _C def need_events(self,count): level=0 for event in self.events[1:]: if isinstance(event,(DocumentStartEvent,CollectionStartEvent)):level+=1 elif isinstance(event,(DocumentEndEvent,CollectionEndEvent)):level-=1 elif isinstance(event,StreamEndEvent):level=-1 if level<0:return _C return len(self.events)self.best_width:self.write_indent() 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.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) 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='' 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): 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() else: 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) 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 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) 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) def expect_flow_mapping_simple_value(self):self.write_indicator(self.prefixed_colon,_C);self.states.append(self.expect_flow_mapping_key);self.expect_node(mapping=_A) def expect_flow_mapping_value(self): if self.canonical or self.column>self.best_width:self.write_indent() self.write_indicator(self.prefixed_colon,_A);self.states.append(self.expect_flow_mapping_key);self.expect_node(mapping=_A) def expect_block_sequence(self): if self.mapping_context:indentless=not self.indention else: indentless=_C if not self.compact_seq_seq and self.column!=0:self.write_line_break() self.increase_indent(flow=_C,sequence=_A,indentless=indentless);self.state=self.expect_first_block_sequence_item def expect_first_block_sequence_item(self):return self.expect_block_sequence_item(first=_A) def expect_block_sequence_item(self,first=_C): if not first and isinstance(self.event,SequenceEndEvent): if self.event.comment and self.event.comment[1]:self.write_pre_comment(self.event) self.indent=self.indents.pop();self.state=self.states.pop();self.no_newline=_C else: if self.event.comment and self.event.comment[1]:self.write_pre_comment(self.event) nonl=self.no_newline if self.column==0 else _C;self.write_indent();ind=self.sequence_dash_offset;self.write_indicator(_D*ind+'-',_A,indention=_A) if nonl or self.sequence_dash_offset+2>self.best_sequence_indent:self.no_newline=_A self.states.append(self.expect_block_sequence_item);self.expect_node(sequence=_A) def expect_block_mapping(self): if not self.mapping_context and not(self.compact_seq_map or self.column==0):self.write_line_break() self.increase_indent(flow=_C,sequence=_C);self.state=self.expect_first_block_mapping_key def expect_first_block_mapping_key(self):return self.expect_block_mapping_key(first=_A) def expect_block_mapping_key(self,first=_C): if not first and isinstance(self.event,MappingEndEvent): if self.event.comment and self.event.comment[1]:self.write_pre_comment(self.event) self.indent=self.indents.pop();self.state=self.states.pop() else: if self.event.comment and self.event.comment[1]:self.write_pre_comment(self.event) self.write_indent() if self.check_simple_key(): if not isinstance(self.event,(SequenceStartEvent,MappingStartEvent)): try: if self.event.style==_I:self.write_indicator(_I,_A,indention=_A) except AttributeError:pass self.states.append(self.expect_block_mapping_simple_value);self.expect_node(mapping=_A,simple_key=_A) if isinstance(self.event,AliasEvent):self.stream.write(_D) else:self.write_indicator(_I,_A,indention=_A);self.states.append(self.expect_block_mapping_value);self.expect_node(mapping=_A) def expect_block_mapping_simple_value(self): if getattr(self.event,'style',_B)!=_I: if self.indent==0 and self.top_level_colon_align is not _B:c=_D*(self.top_level_colon_align-self.column)+self.colon else:c=self.prefixed_colon self.write_indicator(c,_C) self.states.append(self.expect_block_mapping_key);self.expect_node(mapping=_A) def expect_block_mapping_value(self):self.write_indent();self.write_indicator(self.prefixed_colon,_A,indention=_A);self.states.append(self.expect_block_mapping_key);self.expect_node(mapping=_A) def check_empty_sequence(self):return isinstance(self.event,SequenceStartEvent)and bool(self.events)and isinstance(self.events[0],SequenceEndEvent) def check_empty_mapping(self):return isinstance(self.event,MappingStartEvent)and bool(self.events)and isinstance(self.events[0],MappingEndEvent) def check_empty_document(self): if not isinstance(self.event,DocumentStartEvent)or not self.events:return _C event=self.events[0];return isinstance(event,ScalarEvent)and event.anchor is _B and event.tag is _B and event.implicit and event.value=='' def check_simple_key(self): length=0 if isinstance(self.event,NodeEvent)and self.event.anchor is not _B: if self.prepared_anchor is _B:self.prepared_anchor=self.prepare_anchor(self.event.anchor) length+=len(self.prepared_anchor) if isinstance(self.event,(ScalarEvent,CollectionStartEvent))and self.event.tag is not _B: if self.prepared_tag is _B:self.prepared_tag=self.prepare_tag(self.event.tag) length+=len(self.prepared_tag) if isinstance(self.event,ScalarEvent): if self.analysis is _B:self.analysis=self.analyze_scalar(self.event.value) length+=len(self.analysis.scalar) return length': if not self.flow_level and not self.simple_key_context and self.analysis.allow_block:return self.event.style if not self.event.style and self.analysis.allow_double_quoted: if _J in self.event.value or _E in self.event.value:return _H if not self.event.style or self.event.style==_J: if self.analysis.allow_single_quoted and not(self.simple_key_context and self.analysis.multiline):return _J return _H def process_scalar(self): if self.analysis is _B:self.analysis=self.analyze_scalar(self.event.value) if self.style is _B:self.style=self.choose_scalar_style() split=not self.simple_key_context if self.sequence_context and not self.flow_level:self.write_indent() if self.style==_H:self.write_double_quoted(self.analysis.scalar,split) elif self.style==_J:self.write_single_quoted(self.analysis.scalar,split) elif self.style=='>':self.write_folded(self.analysis.scalar) elif self.style=='|':self.write_literal(self.analysis.scalar,self.event.comment) else:self.write_plain(self.analysis.scalar,split) self.analysis=_B;self.style=_B if self.event.comment:self.write_post_comment(self.event) def prepare_version(self,version): major,minor=version if major!=1:raise EmitterError('unsupported YAML version: %d.%d'%(major,minor)) return'%d.%d'%(major,minor) def prepare_tag_handle(self,handle): 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))) 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 if self.dumper: version=getattr(self.dumper,_U,(1,2)) if version is _B or version>=(1,2):ch_set+='#' while end=(1,2):ch_set+='#' while end'%suffix_text def prepare_anchor(self,anchor): if not anchor:raise EmitterError('anchor must not be empty') for ch in anchor: if not check_anchorname_char(ch):raise EmitterError('invalid character %r in the anchor: %r'%(utf8(ch),utf8(anchor))) return anchor def analyze_scalar(self,scalar): 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 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\'"%@`':flow_indicators=_A;block_indicators=_A if ch in'?:': if self.serializer.use_version==(1,1):flow_indicators=_A elif len(scalar)==1:flow_indicators=_A if followed_by_whitespace:block_indicators=_A if ch=='-'and followed_by_whitespace:flow_indicators=_A;block_indicators=_A else: if ch in',[]{}':flow_indicators=_A if ch==_I and self.serializer.use_version==(1,1):flow_indicators=_A if ch==':': if followed_by_whitespace:flow_indicators=_A;block_indicators=_A 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 not self.allow_unicode:special_characters=_A else:special_characters=_A if ch==_D: if index==0:leading_space=_A if index==len(scalar)-1:trailing_space=_A if previous_break:break_space=_A previous_space=_A;previous_break=_C elif ch in _F: if index==0:leading_break=_A if index==len(scalar)-1:trailing_break=_A if previous_space:space_break=_A previous_space=_C;previous_break=_A else:previous_space=_C;previous_break=_C index+=1;preceeded_by_whitespace=ch in A;followed_by_whitespace=index+1>=len(scalar)or scalar[index+1]in A allow_flow_plain=_A;allow_block_plain=_A;allow_single_quoted=_A;allow_double_quoted=_A;allow_block=_A if leading_space or leading_break or trailing_space or trailing_break:allow_flow_plain=allow_block_plain=_C if trailing_space:allow_block=_C if break_space:allow_flow_plain=allow_block_plain=allow_single_quoted=_C if special_characters:allow_flow_plain=allow_block_plain=allow_single_quoted=allow_block=_C elif space_break: allow_flow_plain=allow_block_plain=allow_single_quoted=_C if not self.allow_space_break:allow_block=_C if line_breaks:allow_flow_plain=allow_block_plain=_C if flow_indicators:allow_flow_plain=_C if block_indicators:allow_block_plain=_C return ScalarAnalysis(scalar=scalar,empty=_C,multiline=line_breaks,allow_flow_plain=allow_flow_plain,allow_block_plain=allow_block_plain,allow_single_quoted=allow_single_quoted,allow_double_quoted=allow_double_quoted,allow_block=allow_block) 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)) 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 else:data=_D+indicator self.whitespace=whitespace;self.indention=self.indention and indention;self.column+=len(data);self.open_ended=_C if bool(self.encoding):data=data.encode(self.encoding) self.stream.write(data) def write_indent(self): indent=self.indent or 0 if not self.indention or self.column>indent or self.column==indent and not self.whitespace: if bool(self.no_newline):self.no_newline=_C else:self.write_line_break() if self.columnself.best_width and split and start!=0 and end!=len(text):self.write_indent() else: data=text[start:end];self.column+=len(data) if bool(self.encoding):data=data.encode(self.encoding) self.stream.write(data) start=end elif breaks: if ch is _B or ch not in _F: if text[start]==_E:self.write_line_break() for br in text[start:end]: 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: if start=end)and self.column+(end-start)>self.best_width and split: data=text[start:end]+_L if start-1:break if pos>0:indent=self.best_sequence_indent if text[-1]not in _F:indicator='-' elif len(text)==1 or text[-2]in _F:indicator='+' hints+=indicator;return hints,indent,indicator def write_folded(self,text): hints,_indent,_indicator=self.determine_block_hints(text);self.write_indicator('>'+hints,_A) if _indicator=='+':self.open_ended=_A self.write_line_break();leading_space=_A;spaces=_C;breaks=_A;start=end=0 while end<=len(text): ch=_B if endself.best_width:self.write_indent() else: data=text[start:end];self.column+=len(data) if bool(self.encoding):data=data.encode(self.encoding) self.stream.write(data) start=end elif ch is _B or ch in' \n\x85\u2028\u2029\x07': 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 endself.best_width and split:self.write_indent();self.whitespace=_C;self.indention=_C else: data=text[start:end];self.column+=len(data) if self.encoding:data=data.encode(self.encoding) self.stream.write(data) start=end elif breaks: if ch not in _F: if text[start]==_E:self.write_line_break() for br in text[start:end]: 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: data=text[start:end];self.column+=len(data) if self.encoding:data=data.encode(self.encoding) try:self.stream.write(data) except:sys.stdout.write(repr(data)+_E);raise start=end if ch is not _B:spaces=ch==_D;breaks=ch in _F end+=1 def write_comment(self,comment,pre=_C): value=comment.value if not pre and value[-1]==_E:value=value[:-1] try: col=comment.start_mark.column if comment.value and comment.value.startswith(_E):col=self.column elif col0 and A.buffer[B-1]not in J: B-=1 if A.pointer-B>F/2-1:D=K;B+=5;break G='';C=A.pointer while CF/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 def __str__(A): B=A.get_snippet();C=_H%(A.name,A.line+1,A.column+1) if B is not _A:C+=':\n'+B return C class CommentMark: __slots__=_D, def __init__(A,column):A.column=column class YAMLError(Exception):0 class MarkedYAMLError(YAMLError): 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 def __str__(A): B=[] if A.context is not _A:B.append(A.context) if A.context_mark is not _A and(A.problem is _A or A.problem_mark is _A or A.context_mark.name!=A.problem_mark.name or A.context_mark.line!=A.problem_mark.line or A.context_mark.column!=A.problem_mark.column):B.append(str(A.context_mark)) if A.problem is not _A:B.append(A.problem) if A.problem_mark is not _A:B.append(str(A.problem_mark)) if A.note is not _A and A.note:C=textwrap.dedent(A.note);B.append(C) return _B.join(B) class YAMLStreamError(Exception):0 class YAMLWarning(Warning):0 class MarkedYAMLWarning(YAMLWarning): 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 def __str__(A): B=[] if A.context is not _A:B.append(A.context) if A.context_mark is not _A and(A.problem is _A or A.problem_mark is _A or A.context_mark.name!=A.problem_mark.name or A.context_mark.line!=A.problem_mark.line or A.context_mark.column!=A.problem_mark.column):B.append(str(A.context_mark)) if A.problem is not _A:B.append(A.problem) if A.problem_mark is not _A:B.append(str(A.problem_mark)) if A.note is not _A and A.note:C=textwrap.dedent(A.note);B.append(C) if A.warn is not _A and A.warn:D=textwrap.dedent(A.warn);B.append(D) 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) 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) 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 def __str__(A): B=[] if A.context is not _A:B.append(A.context) if A.context_mark is not _A and(A.problem is _A or A.problem_mark is _A or A.context_mark.name!=A.problem_mark.name or A.context_mark.line!=A.problem_mark.line or A.context_mark.column!=A.problem_mark.column):B.append(str(A.context_mark)) if A.problem is not _A:B.append(A.problem) if A.problem_mark is not _A:B.append(str(A.problem_mark)) if A.note is not _A and A.note:C=textwrap.dedent(A.note);B.append(C) if A.warn is not _A and A.warn:D=textwrap.dedent(A.warn);B.append(D) return _B.join(B)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807559.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/events.py0000644000175000017500000000440700000000000024130 0ustar00rochacbrunorochacbruno_H='explicit' _G='style' _F='flow_style' _E='value' _D='anchor' _C='implicit' _B='tag' _A=None if False:from typing import Any,Dict,Optional,List def CommentCheck():0 class Event: __slots__='start_mark','end_mark','comment' def __init__(A,start_mark=_A,end_mark=_A,comment=CommentCheck): B=comment;A.start_mark=start_mark;A.end_mark=end_mark 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]) 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' 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): __slots__='encoding', 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' 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, 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 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__=() class MappingStartEvent(CollectionStartEvent):__slots__=() class MappingEndEvent(CollectionEndEvent):__slots__=()././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807559.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/loader.py0000644000175000017500000000362100000000000024067 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import _A=None from .reader import Reader from .scanner import Scanner,RoundTripScanner from .parser import Parser,RoundTripParser from .composer import Composer from .constructor import BaseConstructor,SafeConstructor,Constructor,RoundTripConstructor from .resolver import VersionedResolver if False:from typing import Any,Dict,List,Union,Optional;from .compat import StreamTextType,VersionType __all__=['BaseLoader','SafeLoader','Loader','RoundTripLoader'] class BaseLoader(Reader,Scanner,Parser,Composer,BaseConstructor,VersionedResolver): def __init__(A,stream,version=_A,preserve_quotes=_A):Reader.__init__(A,stream,loader=A);Scanner.__init__(A,loader=A);Parser.__init__(A,loader=A);Composer.__init__(A,loader=A);BaseConstructor.__init__(A,loader=A);VersionedResolver.__init__(A,version,loader=A) class SafeLoader(Reader,Scanner,Parser,Composer,SafeConstructor,VersionedResolver): def __init__(A,stream,version=_A,preserve_quotes=_A):Reader.__init__(A,stream,loader=A);Scanner.__init__(A,loader=A);Parser.__init__(A,loader=A);Composer.__init__(A,loader=A);SafeConstructor.__init__(A,loader=A);VersionedResolver.__init__(A,version,loader=A) class Loader(Reader,Scanner,Parser,Composer,Constructor,VersionedResolver): def __init__(A,stream,version=_A,preserve_quotes=_A):Reader.__init__(A,stream,loader=A);Scanner.__init__(A,loader=A);Parser.__init__(A,loader=A);Composer.__init__(A,loader=A);Constructor.__init__(A,loader=A);VersionedResolver.__init__(A,version,loader=A) class RoundTripLoader(Reader,RoundTripScanner,RoundTripParser,Composer,RoundTripConstructor,VersionedResolver): def __init__(A,stream,version=_A,preserve_quotes=_A):Reader.__init__(A,stream,loader=A);RoundTripScanner.__init__(A,loader=A);RoundTripParser.__init__(A,loader=A);Composer.__init__(A,loader=A);RoundTripConstructor.__init__(A,preserve_quotes=preserve_quotes,loader=A);VersionedResolver.__init__(A,version,loader=A)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807559.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/main.py0000644000175000017500000006740300000000000023555 0ustar00rochacbrunorochacbrunofrom __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' _H='{}.__init__() takes no positional argument but at least one was given ({!r})' _G='yaml_tag' _F='open' _E='rt' _D='_' _C=True _B=False _A=None import sys,os,warnings,glob from importlib import import_module import dynaconf.vendor.ruamel as ruamel from .error import UnsafeLoaderWarning,YAMLError from .tokens import * from .events import * from .nodes import * from .loader import BaseLoader,SafeLoader,Loader,RoundTripLoader from .dumper import BaseDumper,SafeDumper,Dumper,RoundTripDumper from .compat import StringIO,BytesIO,with_metaclass,PY3,nprint from .resolver import VersionedResolver,Resolver from .representer import BaseRepresenter,SafeRepresenter,Representer,RoundTripRepresenter from .constructor import BaseConstructor,SafeConstructor,Constructor,RoundTripConstructor from .loader import Loader as UnsafeLoader if _B: from typing import List,Set,Dict,Union,Any,Callable,Optional,Text;from .compat import StreamType,StreamTextType,VersionType if PY3:from pathlib import Path else:Path=Any try:from _ruamel_yaml import CParser,CEmitter except:CParser=CEmitter=_A enforce=object() class YAML: def __init__(self,_kw=enforce,typ=_A,pure=_B,output=_A,plug_ins=_A): if _kw is not enforce:raise TypeError(_H.format(self.__class__.__name__,_kw)) self.typ=[_E]if typ is _A else typ if isinstance(typ,list)else[typ];self.pure=pure;self._output=output;self._context_manager=_A;self.plug_ins=[] for pu in ([]if plug_ins is _A else plug_ins)+self.official_plug_ins():file_name=pu.replace(os.sep,'.');self.plug_ins.append(import_module(file_name)) 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'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 for module in self.plug_ins: if getattr(module,_K,_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): try:return self._reader except AttributeError:self._reader=self.Reader(_A,loader=self);return self._reader @property def scanner(self): try:return self._scanner except AttributeError:self._scanner=self.Scanner(loader=self);return self._scanner @property def parser(self): 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 else:setattr(self,attr,CParser(self._stream)) return getattr(self,attr) @property def composer(self): attr=_D+sys._getframe().f_code.co_name if not hasattr(self,attr):setattr(self,attr,self.Composer(loader=self)) return getattr(self,attr) @property def constructor(self): attr=_D+sys._getframe().f_code.co_name if not hasattr(self,attr):cnst=self.Constructor(preserve_quotes=self.preserve_quotes,loader=self);cnst.allow_duplicate_keys=self.allow_duplicate_keys;setattr(self,attr,cnst) return getattr(self,attr) @property def resolver(self): attr=_D+sys._getframe().f_code.co_name if not hasattr(self,attr):setattr(self,attr,self.Resolver(version=self.version,loader=self)) return getattr(self,attr) @property def emitter(self): attr=_D+sys._getframe().f_code.co_name if not hasattr(self,attr): if self.Emitter is not CEmitter: _emitter=self.Emitter(_A,canonical=self.canonical,indent=self.old_indent,width=self.width,allow_unicode=self.allow_unicode,line_break=self.line_break,prefix_colon=self.prefix_colon,brace_single_entry_mapping_in_flow_sequence=self.brace_single_entry_mapping_in_flow_sequence,dumper=self);setattr(self,attr,_emitter) if self.map_indent is not _A:_emitter.best_map_indent=self.map_indent if self.sequence_indent is not _A:_emitter.best_sequence_indent=self.sequence_indent if self.sequence_dash_offset is not _A:_emitter.sequence_dash_offset=self.sequence_dash_offset 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 return _A return getattr(self,attr) @property def serializer(self): attr=_D+sys._getframe().f_code.co_name if not hasattr(self,attr):setattr(self,attr,self.Serializer(encoding=self.encoding,explicit_start=self.explicit_start,explicit_end=self.explicit_end,version=self.version,tags=self.tags,dumper=self)) return getattr(self,attr) @property def representer(self): attr=_D+sys._getframe().f_code.co_name if not hasattr(self,attr): repres=self.Representer(default_style=self.default_style,default_flow_style=self.default_flow_style,dumper=self) if self.sort_base_mapping_type_on_output is not _A:repres.sort_base_mapping_type_on_output=self.sort_base_mapping_type_on_output setattr(self,attr,repres) return getattr(self,attr) def load(self,stream): if not hasattr(stream,_M)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() finally: parser.dispose() try:self._reader.reset_reader() except AttributeError:pass try:self._scanner.reset_scanner() 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): with stream.open('r')as fp: for d in self.load_all(fp,_kw=enforce):yield d return constructor,parser=self.get_constructor_parser(stream) try: while constructor.check_data():yield constructor.get_data() finally: parser.dispose() try:self._reader.reset_reader() except AttributeError:pass try:self._scanner.reset_scanner() except AttributeError:pass def get_constructor_parser(self,stream): if self.Parser is not CParser: if self.Reader is _A:self.Reader=ruamel.yaml.reader.Reader if self.Scanner is _A:self.Scanner=ruamel.yaml.scanner.Scanner self.reader.stream=stream elif self.Reader is not _A: if self.Scanner is _A:self.Scanner=ruamel.yaml.scanner.Scanner self.Parser=ruamel.yaml.parser.Parser;self.reader.stream=stream elif self.Scanner is not _A: if self.Reader is _A:self.Reader=ruamel.yaml.reader.Reader self.Parser=ruamel.yaml.parser.Parser;self.reader.stream=stream else: rslvr=self.Resolver class XLoader(self.Parser,self.Constructor,rslvr): def __init__(selfx,stream,version=self.version,preserve_quotes=_A):CParser.__init__(selfx,stream);selfx._parser=selfx._composer=selfx;self.Constructor.__init__(selfx,loader=selfx);selfx.allow_duplicate_keys=self.allow_duplicate_keys;rslvr.__init__(selfx,version=version,loadumper=selfx) self._stream=stream;loader=XLoader(stream);return loader,loader return self.constructor,self.parser def dump(self,data,stream=_A,_kw=enforce,transform=_A): if self._context_manager: if not self._output:raise TypeError('Missing output stream while dumping from context manager') if _kw is not enforce:raise TypeError('{}.dump() takes one positional argument but at least two were given ({!r})'.format(self.__class__.__name__,_kw)) if transform is not _A:raise TypeError('{}.dump() in the context manager cannot have transform keyword '.format(self.__class__.__name__)) self._context_manager.dump(data) else: if stream is _A:raise TypeError('Need a stream argument when not dumping from context manager') 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)) 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): 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 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: fstream=stream if self.encoding is _A:stream=StringIO() else:stream=BytesIO() serializer,representer,emitter=self.get_serializer_representer_emitter(stream,tlca) try: self.serializer.open() for data in documents: try:self.representer.represent(data) except AttributeError:raise self.serializer.close() finally: try:self.emitter.dispose() except AttributeError:raise delattr(self,_P);delattr(self,_Q) if transform: val=stream.getvalue() if self.encoding:val=val.decode(self.encoding) if fstream is _A:transform(val) else:fstream.write(transform(val)) return _A def get_serializer_representer_emitter(self,stream,tlca): if self.Emitter is not CEmitter: if self.Serializer is _A:self.Serializer=ruamel.yaml.serializer.Serializer 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 if self.Serializer is not _A: 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 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 def map(self,**kw): 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) 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__) try:self.representer.add_representer(cls,cls.to_yaml) except AttributeError: def t_y(representer,data):return representer.represent_yaml_object(tag,data,cls,flow_style=representer.default_flow_style) self.representer.add_representer(cls,t_y) try:self.constructor.add_constructor(tag,cls.from_yaml) except AttributeError: def f_y(constructor,node):return constructor.construct_yaml_object(node,cls) self.constructor.add_constructor(tag,f_y) return cls def parse(self,stream): _,parser=self.get_constructor_parser(stream) try: while parser.check_event():yield parser.get_event() finally: parser.dispose() try:self._reader.reset_reader() except AttributeError:pass try:self._scanner.reset_scanner() except AttributeError:pass def __enter__(self):self._context_manager=YAMLContextManager(self);return self def __exit__(self,typ,value,traceback): if typ:nprint(_K,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 if sequence is not _A:self.sequence_indent=sequence if offset is not _A:self.sequence_dash_offset=offset @property def indent(self):return self._indent @indent.setter def indent(self,val):self.old_indent=val @property def block_seq_indent(self):return self.sequence_dash_offset @block_seq_indent.setter def block_seq_indent(self,val):self.sequence_dash_offset=val def compact(self,seq_seq=_A,seq_map=_A):self.compact_seq_seq=seq_seq;self.compact_seq_map=seq_map 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 self._transform is not _A: self._fstream=self._output if self._yaml.encoding is _A:self._output=StringIO() else:self._output=BytesIO() def teardown_output(self): if self._output_inited:self._yaml.serializer.close() else:return try:self._yaml.emitter.dispose() except AttributeError:raise try:delattr(self._yaml,_P);delattr(self._yaml,_Q) except AttributeError:raise if self._transform: val=self._output.getvalue() if self._yaml.encoding:val=val.decode(self._yaml.encoding) if self._fstream is _A:self._transform(val) else:self._fstream.write(self._transform(val));self._fstream.flush();self._output=self._fstream if self._output_path is not _A:self._output.close() def init_output(self,first_data): if self._yaml.top_level_colon_align is _C:tlca=max([len(str(x))for x in first_data]) else:tlca=self._yaml.top_level_colon_align self._yaml.get_serializer_representer_emitter(self._output,tlca);self._yaml.serializer.open();self._output_inited=_C def dump(self,data): if not self._output_inited:self.init_output(data) try:self._yaml.representer.represent(data) except AttributeError:raise def yaml_object(yml): def yo_deco(cls): tag=getattr(cls,_G,'!'+cls.__name__) try:yml.representer.add_representer(cls,cls.to_yaml) except AttributeError: def t_y(representer,data):return representer.represent_yaml_object(tag,data,cls,flow_style=representer.default_flow_style) yml.representer.add_representer(cls,t_y) try:yml.constructor.add_constructor(tag,cls.from_yaml) except AttributeError: def f_y(constructor,node):return constructor.construct_yaml_object(node,cls) yml.constructor.add_constructor(tag,f_y) return cls return yo_deco def scan(stream,Loader=Loader): loader=Loader(stream) try: while loader.scanner.check_token():yield loader.scanner.get_token() finally:loader._parser.dispose() def parse(stream,Loader=Loader): loader=Loader(stream) try: while loader._parser.check_event():yield loader._parser.get_event() finally:loader._parser.dispose() def compose(stream,Loader=Loader): loader=Loader(stream) try:return loader.get_single_node() finally:loader.dispose() def compose_all(stream,Loader=Loader): loader=Loader(stream) try: while loader.check_node():yield loader._composer.get_node() finally:loader._parser.dispose() def load(stream,Loader=_A,version=_A,preserve_quotes=_A): if Loader is _A:warnings.warn(UnsafeLoaderWarning.text,UnsafeLoaderWarning,stacklevel=2);Loader=UnsafeLoader loader=Loader(stream,version,preserve_quotes=preserve_quotes) try:return loader._constructor.get_single_data() finally: loader._parser.dispose() try:loader._reader.reset_reader() except AttributeError:pass try:loader._scanner.reset_scanner() except AttributeError:pass def load_all(stream,Loader=_A,version=_A,preserve_quotes=_A): if Loader is _A:warnings.warn(UnsafeLoaderWarning.text,UnsafeLoaderWarning,stacklevel=2);Loader=UnsafeLoader loader=Loader(stream,version,preserve_quotes=preserve_quotes) try: while loader._constructor.check_data():yield loader._constructor.get_data() finally: loader._parser.dispose() try:loader._reader.reset_reader() except AttributeError:pass try:loader._scanner.reset_scanner() except AttributeError:pass def safe_load(stream,version=_A):return load(stream,SafeLoader,version) def safe_load_all(stream,version=_A):return load_all(stream,SafeLoader,version) def round_trip_load(stream,version=_A,preserve_quotes=_A):return load(stream,RoundTripLoader,version,preserve_quotes=preserve_quotes) def round_trip_load_all(stream,version=_A,preserve_quotes=_A):return load_all(stream,RoundTripLoader,version,preserve_quotes=preserve_quotes) def emit(events,stream=_A,Dumper=Dumper,canonical=_A,indent=_A,width=_A,allow_unicode=_A,line_break=_A): getvalue=_A if stream is _A:stream=StringIO();getvalue=stream.getvalue dumper=Dumper(stream,canonical=canonical,indent=indent,width=width,allow_unicode=allow_unicode,line_break=line_break) try: for event in events:dumper.emit(event) finally: try:dumper._emitter.dispose() except AttributeError:raise;dumper.dispose() if getvalue is not _A:return getvalue() enc=_A if PY3 else _J 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: if encoding is _A:stream=StringIO() else:stream=BytesIO() getvalue=stream.getvalue dumper=Dumper(stream,canonical=canonical,indent=indent,width=width,allow_unicode=allow_unicode,line_break=line_break,encoding=encoding,version=version,tags=tags,explicit_start=explicit_start,explicit_end=explicit_end) try: dumper._serializer.open() for node in nodes:dumper.serialize(node) dumper._serializer.close() finally: try:dumper._emitter.dispose() except AttributeError:raise;dumper.dispose() if getvalue is not _A:return getvalue() def serialize(node,stream=_A,Dumper=Dumper,**kwds):return serialize_all([node],stream,Dumper=Dumper,**kwds) def dump_all(documents,stream=_A,Dumper=Dumper,default_style=_A,default_flow_style=_A,canonical=_A,indent=_A,width=_A,allow_unicode=_A,line_break=_A,encoding=enc,explicit_start=_A,explicit_end=_A,version=_A,tags=_A,block_seq_indent=_A,top_level_colon_align=_A,prefix_colon=_A): getvalue=_A if top_level_colon_align is _C:top_level_colon_align=max([len(str(x))for x in documents[0]]) if stream is _A: if encoding is _A:stream=StringIO() else:stream=BytesIO() getvalue=stream.getvalue dumper=Dumper(stream,default_style=default_style,default_flow_style=default_flow_style,canonical=canonical,indent=indent,width=width,allow_unicode=allow_unicode,line_break=line_break,encoding=encoding,explicit_start=explicit_start,explicit_end=explicit_end,version=version,tags=tags,block_seq_indent=block_seq_indent,top_level_colon_align=top_level_colon_align,prefix_colon=prefix_colon) try: dumper._serializer.open() for data in documents: try:dumper._representer.represent(data) except AttributeError:raise dumper._serializer.close() finally: try:dumper._emitter.dispose() except AttributeError:raise;dumper.dispose() if getvalue is not _A:return getvalue() return _A def dump(data,stream=_A,Dumper=Dumper,default_style=_A,default_flow_style=_A,canonical=_A,indent=_A,width=_A,allow_unicode=_A,line_break=_A,encoding=enc,explicit_start=_A,explicit_end=_A,version=_A,tags=_A,block_seq_indent=_A):return dump_all([data],stream,Dumper=Dumper,default_style=default_style,default_flow_style=default_flow_style,canonical=canonical,indent=indent,width=width,allow_unicode=allow_unicode,line_break=line_break,encoding=encoding,explicit_start=explicit_start,explicit_end=explicit_end,version=version,tags=tags,block_seq_indent=block_seq_indent) def safe_dump_all(documents,stream=_A,**kwds):return dump_all(documents,stream,Dumper=SafeDumper,**kwds) def safe_dump(data,stream=_A,**kwds):return dump_all([data],stream,Dumper=SafeDumper,**kwds) def round_trip_dump(data,stream=_A,Dumper=RoundTripDumper,default_style=_A,default_flow_style=_A,canonical=_A,indent=_A,width=_A,allow_unicode=_A,line_break=_A,encoding=enc,explicit_start=_A,explicit_end=_A,version=_A,tags=_A,block_seq_indent=_A,top_level_colon_align=_A,prefix_colon=_A):allow_unicode=_C if allow_unicode is _A else allow_unicode;return dump_all([data],stream,Dumper=Dumper,default_style=default_style,default_flow_style=default_flow_style,canonical=canonical,indent=indent,width=width,allow_unicode=allow_unicode,line_break=line_break,encoding=encoding,explicit_start=explicit_start,explicit_end=explicit_end,version=version,tags=tags,block_seq_indent=block_seq_indent,top_level_colon_align=top_level_colon_align,prefix_colon=prefix_colon) def add_implicit_resolver(tag,regexp,first=_A,Loader=_A,Dumper=_A,resolver=Resolver): A='add_implicit_resolver' if Loader is _A and Dumper is _A:resolver.add_implicit_resolver(tag,regexp,first);return if Loader: if hasattr(Loader,A):Loader.add_implicit_resolver(tag,regexp,first) elif issubclass(Loader,(BaseLoader,SafeLoader,ruamel.yaml.loader.Loader,RoundTripLoader)):Resolver.add_implicit_resolver(tag,regexp,first) else:raise NotImplementedError if Dumper: if hasattr(Dumper,A):Dumper.add_implicit_resolver(tag,regexp,first) elif issubclass(Dumper,(BaseDumper,SafeDumper,ruamel.yaml.dumper.Dumper,RoundTripDumper)):Resolver.add_implicit_resolver(tag,regexp,first) else:raise NotImplementedError def add_path_resolver(tag,path,kind=_A,Loader=_A,Dumper=_A,resolver=Resolver): A='add_path_resolver' if Loader is _A and Dumper is _A:resolver.add_path_resolver(tag,path,kind);return if Loader: if hasattr(Loader,A):Loader.add_path_resolver(tag,path,kind) elif issubclass(Loader,(BaseLoader,SafeLoader,ruamel.yaml.loader.Loader,RoundTripLoader)):Resolver.add_path_resolver(tag,path,kind) else:raise NotImplementedError if Dumper: if hasattr(Dumper,A):Dumper.add_path_resolver(tag,path,kind) elif issubclass(Dumper,(BaseDumper,SafeDumper,ruamel.yaml.dumper.Dumper,RoundTripDumper)):Resolver.add_path_resolver(tag,path,kind) else:raise NotImplementedError def add_constructor(tag,object_constructor,Loader=_A,constructor=Constructor): if Loader is _A:constructor.add_constructor(tag,object_constructor) else: if hasattr(Loader,'add_constructor'):Loader.add_constructor(tag,object_constructor);return if issubclass(Loader,BaseLoader):BaseConstructor.add_constructor(tag,object_constructor) elif issubclass(Loader,SafeLoader):SafeConstructor.add_constructor(tag,object_constructor) elif issubclass(Loader,Loader):Constructor.add_constructor(tag,object_constructor) elif issubclass(Loader,RoundTripLoader):RoundTripConstructor.add_constructor(tag,object_constructor) else:raise NotImplementedError def add_multi_constructor(tag_prefix,multi_constructor,Loader=_A,constructor=Constructor): if Loader is _A:constructor.add_multi_constructor(tag_prefix,multi_constructor) else: if _B and hasattr(Loader,'add_multi_constructor'):Loader.add_multi_constructor(tag_prefix,constructor);return if issubclass(Loader,BaseLoader):BaseConstructor.add_multi_constructor(tag_prefix,multi_constructor) elif issubclass(Loader,SafeLoader):SafeConstructor.add_multi_constructor(tag_prefix,multi_constructor) elif issubclass(Loader,ruamel.yaml.loader.Loader):Constructor.add_multi_constructor(tag_prefix,multi_constructor) elif issubclass(Loader,RoundTripLoader):RoundTripConstructor.add_multi_constructor(tag_prefix,multi_constructor) else:raise NotImplementedError def add_representer(data_type,object_representer,Dumper=_A,representer=Representer): if Dumper is _A:representer.add_representer(data_type,object_representer) else: if hasattr(Dumper,'add_representer'):Dumper.add_representer(data_type,object_representer);return if issubclass(Dumper,BaseDumper):BaseRepresenter.add_representer(data_type,object_representer) elif issubclass(Dumper,SafeDumper):SafeRepresenter.add_representer(data_type,object_representer) elif issubclass(Dumper,Dumper):Representer.add_representer(data_type,object_representer) elif issubclass(Dumper,RoundTripDumper):RoundTripRepresenter.add_representer(data_type,object_representer) else:raise NotImplementedError def add_multi_representer(data_type,multi_representer,Dumper=_A,representer=Representer): if Dumper is _A:representer.add_multi_representer(data_type,multi_representer) else: if hasattr(Dumper,'add_multi_representer'):Dumper.add_multi_representer(data_type,multi_representer);return if issubclass(Dumper,BaseDumper):BaseRepresenter.add_multi_representer(data_type,multi_representer) elif issubclass(Dumper,SafeDumper):SafeRepresenter.add_multi_representer(data_type,multi_representer) elif issubclass(Dumper,Dumper):Representer.add_multi_representer(data_type,multi_representer) elif issubclass(Dumper,RoundTripDumper):RoundTripRepresenter.add_multi_representer(data_type,multi_representer) else:raise NotImplementedError class YAMLObjectMetaclass(type): def __init__(cls,name,bases,kwds): super(YAMLObjectMetaclass,cls).__init__(name,bases,kwds) if _G in kwds and kwds[_G]is not _A:cls.yaml_constructor.add_constructor(cls.yaml_tag,cls.from_yaml);cls.yaml_representer.add_representer(cls,cls.to_yaml) class YAMLObject(with_metaclass(YAMLObjectMetaclass)): __slots__=();yaml_constructor=Constructor;yaml_representer=Representer;yaml_tag=_A;yaml_flow_style=_A @classmethod def from_yaml(cls,constructor,node):return constructor.construct_yaml_object(node,cls) @classmethod def to_yaml(cls,representer,data):return representer.represent_yaml_object(cls.yaml_tag,data,cls,flow_style=cls.yaml_flow_style)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807560.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/nodes.py0000644000175000017500000000347200000000000023735 0ustar00rochacbrunorochacbrunofrom __future__ import print_function _A=None import sys from .compat import string_types if False:from typing import Dict,Any,Text class Node: __slots__='tag','value','start_mark','end_mark','comment','anchor' 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 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)) 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)) for C in A.value: if isinstance(C,tuple): for E in C:E.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): __slots__='style',;id='scalar' def __init__(A,tag,value,start_mark=_A,end_mark=_A,style=_A,comment=_A,anchor=_A):Node.__init__(A,tag,value,start_mark,end_mark,comment=comment,anchor=anchor);A.style=style class CollectionNode(Node): __slots__='flow_style', def __init__(A,tag,value,start_mark=_A,end_mark=_A,flow_style=_A,comment=_A,anchor=_A):Node.__init__(A,tag,value,start_mark,end_mark,comment=comment);A.flow_style=flow_style;A.anchor=anchor class SequenceNode(CollectionNode):__slots__=();id='sequence' class MappingNode(CollectionNode): __slots__='merge',;id='mapping' def __init__(A,tag,value,start_mark=_A,end_mark=_A,flow_style=_A,comment=_A,anchor=_A):CollectionNode.__init__(A,tag,value,start_mark,end_mark,flow_style,comment,anchor);A.merge=_A././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807560.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/parser.py0000644000175000017500000004112300000000000024114 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import _F='expected , but found %r' _E='typ' _D='!' _C=True _B=False _A=None from .error import MarkedYAMLError from .tokens import * from .events import * from .scanner import Scanner,RoundTripScanner,ScannerError from .compat import utf8,nprint,nprintf 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:'} 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 self.reset_parser() def reset_parser(self):self.current_event=_A;self.tag_handles={};self.states=[];self.marks=[];self.state=self.parse_stream_start def dispose(self):self.reset_parser() @property def scanner(self): if hasattr(self.loader,_E):return self.loader.scanner return self.loader._scanner @property def resolver(self): if hasattr(self.loader,_E):return self.loader.resolver return self.loader._resolver def check_event(self,*choices): if self.current_event is _A: if self.state:self.current_event=self.state() if self.current_event is not _A: if not choices:return _C for choice in choices: if isinstance(self.current_event,choice):return _C return _B def peek_event(self): if self.current_event is _A: if self.state:self.current_event=self.state() return self.current_event def get_event(self): if self.current_event is _A: if self.state:self.current_event=self.state() value=self.current_event;self.current_event=_A;return value def parse_stream_start(self):token=self.scanner.get_token();token.move_comment(self.scanner.peek_token());event=StreamStartEvent(token.start_mark,token.end_mark,encoding=token.encoding);self.state=self.parse_implicit_document_start;return event def parse_implicit_document_start(self): if not self.scanner.check_token(DirectiveToken,DocumentStartToken,StreamEndToken):self.tag_handles=self.DEFAULT_TAGS;token=self.scanner.peek_token();start_mark=end_mark=token.start_mark;event=DocumentStartEvent(start_mark,end_mark,explicit=_B);self.states.append(self.parse_document_end);self.state=self.parse_block_node;return event else:return self.parse_document_start() def parse_document_start(self): while self.scanner.check_token(DocumentEndToken):self.scanner.get_token() if not self.scanner.check_token(StreamEndToken): token=self.scanner.peek_token();start_mark=token.start_mark;version,tags=self.process_directives() if not self.scanner.check_token(DocumentStartToken):raise ParserError(_A,_A,"expected '', but found %r"%self.scanner.peek_token().id,self.scanner.peek_token().start_mark) token=self.scanner.get_token();end_mark=token.end_mark;event=DocumentStartEvent(start_mark,end_mark,explicit=_C,version=version,tags=tags);self.states.append(self.parse_document_end);self.state=self.parse_document_content else:token=self.scanner.get_token();event=StreamEndEvent(token.start_mark,token.end_mark,comment=token.comment);assert not self.states;assert not self.marks;self.state=_A return event def parse_document_end(self): token=self.scanner.peek_token();start_mark=end_mark=token.start_mark;explicit=_B if self.scanner.check_token(DocumentEndToken):token=self.scanner.get_token();end_mark=token.end_mark;explicit=_C event=DocumentEndEvent(start_mark,end_mark,explicit=explicit) if self.resolver.processing_version==(1,1):self.state=self.parse_document_start else:self.state=self.parse_implicit_document_start return event def parse_document_content(self): if self.scanner.check_token(DirectiveToken,DocumentStartToken,DocumentEndToken,StreamEndToken):event=self.process_empty_scalar(self.scanner.peek_token().start_mark);self.state=self.states.pop();return event else:return self.parse_block_node() def process_directives(self): yaml_version=_A;self.tag_handles={} while self.scanner.check_token(DirectiveToken): token=self.scanner.get_token() if token.name=='YAML': if yaml_version is not _A:raise ParserError(_A,_A,'found duplicate YAML directive',token.start_mark) major,minor=token.value if major!=1:raise ParserError(_A,_A,'found incompatible YAML document (version 1.* is required)',token.start_mark) yaml_version=token.value elif token.name=='TAG': handle,prefix=token.value if handle in self.tag_handles:raise ParserError(_A,_A,'duplicate tag handle %r'%utf8(handle),token.start_mark) self.tag_handles[handle]=prefix if bool(self.tag_handles):value=yaml_version,self.tag_handles.copy() else:value=yaml_version,_A if self.loader is not _A and hasattr(self.loader,'tags'): self.loader.version=yaml_version if self.loader.tags is _A:self.loader.tags={} for k in self.tag_handles:self.loader.tags[k]=self.tag_handles[k] for key in self.DEFAULT_TAGS: if key not in self.tag_handles:self.tag_handles[key]=self.DEFAULT_TAGS[key] return value def parse_block_node(self):return self.parse_node(block=_C) def parse_flow_node(self):return self.parse_node() def parse_block_node_or_indentless_sequence(self):return self.parse_node(block=_C,indentless_sequence=_C) def transform_tag(self,handle,suffix):return self.tag_handles[handle]+suffix def parse_node(self,block=_B,indentless_sequence=_B): if self.scanner.check_token(AliasToken):token=self.scanner.get_token();event=AliasEvent(token.value,token.start_mark,token.end_mark);self.state=self.states.pop();return event anchor=_A;tag=_A;start_mark=end_mark=tag_mark=_A if self.scanner.check_token(AnchorToken): token=self.scanner.get_token();start_mark=token.start_mark;end_mark=token.end_mark;anchor=token.value if self.scanner.check_token(TagToken):token=self.scanner.get_token();tag_mark=token.start_mark;end_mark=token.end_mark;tag=token.value elif self.scanner.check_token(TagToken): token=self.scanner.get_token();start_mark=tag_mark=token.start_mark;end_mark=token.end_mark;tag=token.value if self.scanner.check_token(AnchorToken):token=self.scanner.get_token();start_mark=tag_mark=token.start_mark;end_mark=token.end_mark;anchor=token.value if tag is not _A: handle,suffix=tag if handle is not _A: if handle not in self.tag_handles:raise ParserError('while parsing a node',start_mark,'found undefined tag handle %r'%utf8(handle),tag_mark) 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 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 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() elif self.scanner.check_token(FlowSequenceStartToken):pt=self.scanner.peek_token();end_mark=pt.end_mark;event=SequenceStartEvent(anchor,tag,implicit,start_mark,end_mark,flow_style=_C,comment=pt.comment);self.state=self.parse_flow_sequence_first_entry elif self.scanner.check_token(FlowMappingStartToken):pt=self.scanner.peek_token();end_mark=pt.end_mark;event=MappingStartEvent(anchor,tag,implicit,start_mark,end_mark,flow_style=_C,comment=pt.comment);self.state=self.parse_flow_mapping_first_key elif block and self.scanner.check_token(BlockSequenceStartToken): end_mark=self.scanner.peek_token().start_mark;pt=self.scanner.peek_token();comment=pt.comment if comment is _A or comment[1]is _A:comment=pt.split_comment() event=SequenceStartEvent(anchor,tag,implicit,start_mark,end_mark,flow_style=_B,comment=comment);self.state=self.parse_block_sequence_first_entry elif block and self.scanner.check_token(BlockMappingStartToken):end_mark=self.scanner.peek_token().start_mark;comment=self.scanner.peek_token().comment;event=MappingStartEvent(anchor,tag,implicit,start_mark,end_mark,flow_style=_B,comment=comment);self.state=self.parse_block_mapping_first_key elif anchor is not _A or tag is not _A:event=ScalarEvent(anchor,tag,(implicit,_B),'',start_mark,end_mark);self.state=self.states.pop() else: if block:node='block' else:node='flow' token=self.scanner.peek_token();raise ParserError('while parsing a %s node'%node,start_mark,'expected the node content, but found %r'%token.id,token.start_mark) return event def parse_block_sequence_first_entry(self):token=self.scanner.get_token();self.marks.append(token.start_mark);return self.parse_block_sequence_entry() def parse_block_sequence_entry(self): if self.scanner.check_token(BlockEntryToken): 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) 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): token=self.scanner.get_token();token.move_comment(self.scanner.peek_token()) if not self.scanner.check_token(BlockEntryToken,KeyToken,ValueToken,BlockEndToken):self.states.append(self.parse_indentless_sequence_entry);return self.parse_block_node() else:self.state=self.parse_indentless_sequence_entry;return self.process_empty_scalar(token.end_mark) token=self.scanner.peek_token();event=SequenceEndEvent(token.start_mark,token.start_mark,comment=token.comment);self.state=self.states.pop();return event def parse_block_mapping_first_key(self):token=self.scanner.get_token();self.marks.append(token.start_mark);return self.parse_block_mapping_key() def parse_block_mapping_key(self): if self.scanner.check_token(KeyToken): token=self.scanner.get_token();token.move_comment(self.scanner.peek_token()) 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) 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): token=self.scanner.get_token() if self.scanner.check_token(ValueToken):token.move_comment(self.scanner.peek_token()) elif not self.scanner.check_token(KeyToken):token.move_comment(self.scanner.peek_token(),empty=_C) if not self.scanner.check_token(KeyToken,ValueToken,BlockEndToken):self.states.append(self.parse_block_mapping_key);return self.parse_block_node_or_indentless_sequence() else: self.state=self.parse_block_mapping_key;comment=token.comment if comment is _A: token=self.scanner.peek_token();comment=token.comment if comment:token._comment=[_A,comment[1]];comment=[comment[0],_A] return self.process_empty_scalar(token.end_mark,comment=comment) else:self.state=self.parse_block_mapping_key;token=self.scanner.peek_token();return self.process_empty_scalar(token.start_mark) def parse_flow_sequence_first_entry(self):token=self.scanner.get_token();self.marks.append(token.start_mark);return self.parse_flow_sequence_entry(first=_C) def parse_flow_sequence_entry(self,first=_B): if not self.scanner.check_token(FlowSequenceEndToken): if not first: if self.scanner.check_token(FlowEntryToken):self.scanner.get_token() else:token=self.scanner.peek_token();raise ParserError('while parsing a flow sequence',self.marks[-1],"expected ',' or ']', but got %r"%token.id,token.start_mark) if self.scanner.check_token(KeyToken):token=self.scanner.peek_token();event=MappingStartEvent(_A,_A,_C,token.start_mark,token.end_mark,flow_style=_C);self.state=self.parse_flow_sequence_entry_mapping_key;return event elif not self.scanner.check_token(FlowSequenceEndToken):self.states.append(self.parse_flow_sequence_entry);return self.parse_flow_node() 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_flow_sequence_entry_mapping_key(self): token=self.scanner.get_token() if not self.scanner.check_token(ValueToken,FlowEntryToken,FlowSequenceEndToken):self.states.append(self.parse_flow_sequence_entry_mapping_value);return self.parse_flow_node() else:self.state=self.parse_flow_sequence_entry_mapping_value;return self.process_empty_scalar(token.end_mark) def parse_flow_sequence_entry_mapping_value(self): if self.scanner.check_token(ValueToken): token=self.scanner.get_token() if not self.scanner.check_token(FlowEntryToken,FlowSequenceEndToken):self.states.append(self.parse_flow_sequence_entry_mapping_end);return self.parse_flow_node() else:self.state=self.parse_flow_sequence_entry_mapping_end;return self.process_empty_scalar(token.end_mark) else:self.state=self.parse_flow_sequence_entry_mapping_end;token=self.scanner.peek_token();return self.process_empty_scalar(token.start_mark) def parse_flow_sequence_entry_mapping_end(self):self.state=self.parse_flow_sequence_entry;token=self.scanner.peek_token();return MappingEndEvent(token.start_mark,token.start_mark) def parse_flow_mapping_first_key(self):token=self.scanner.get_token();self.marks.append(token.start_mark);return self.parse_flow_mapping_key(first=_C) def parse_flow_mapping_key(self,first=_B): if not self.scanner.check_token(FlowMappingEndToken): if not first: if self.scanner.check_token(FlowEntryToken):self.scanner.get_token() else:token=self.scanner.peek_token();raise ParserError('while parsing a flow mapping',self.marks[-1],"expected ',' or '}', but got %r"%token.id,token.start_mark) if self.scanner.check_token(KeyToken): token=self.scanner.get_token() if not self.scanner.check_token(ValueToken,FlowEntryToken,FlowMappingEndToken):self.states.append(self.parse_flow_mapping_value);return self.parse_flow_node() else:self.state=self.parse_flow_mapping_value;return self.process_empty_scalar(token.end_mark) elif self.resolver.processing_version>(1,1)and self.scanner.check_token(ValueToken):self.state=self.parse_flow_mapping_value;return self.process_empty_scalar(self.scanner.peek_token().end_mark) elif not self.scanner.check_token(FlowMappingEndToken):self.states.append(self.parse_flow_mapping_empty_value);return self.parse_flow_node() token=self.scanner.get_token();event=MappingEndEvent(token.start_mark,token.end_mark,comment=token.comment);self.state=self.states.pop();self.marks.pop();return event def parse_flow_mapping_value(self): if self.scanner.check_token(ValueToken): token=self.scanner.get_token() if not self.scanner.check_token(FlowEntryToken,FlowMappingEndToken):self.states.append(self.parse_flow_mapping_key);return self.parse_flow_node() else:self.state=self.parse_flow_mapping_key;return self.process_empty_scalar(token.end_mark) else:self.state=self.parse_flow_mapping_key;token=self.scanner.peek_token();return self.process_empty_scalar(token.start_mark) def parse_flow_mapping_empty_value(self):self.state=self.parse_flow_mapping_key;return self.process_empty_scalar(self.scanner.peek_token().start_mark) def process_empty_scalar(self,mark,comment=_A):return ScalarEvent(_A,_A,(_C,_B),'',mark,mark,comment=comment) class RoundTripParser(Parser): def transform_tag(self,handle,suffix): if handle=='!!'and suffix in('null','bool','int','float','binary','timestamp','omap','pairs','set','str','seq','map'):return Parser.transform_tag(self,handle,suffix) return handle+suffix././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807560.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/reader.py0000644000175000017500000001165500000000000024071 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import _F='\ufeff' _E='\x00' _D=False _C='ascii' _B='\n' _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 __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 def __str__(A): if isinstance(A.character,binary_type):return'\'%s\' codec can\'t decode byte #x%02x: %s\n in "%s", position %d'%(A.encoding,ord(A.character),A.reason,A.name,A.position) else:return'unacceptable character #x%04x: %s\n in "%s", position %d'%(A.character,A.reason,A.name,A.position) class Reader: def __init__(A,stream,loader=_A): A.loader=loader if A.loader is not _A and getattr(A.loader,'_reader',_A)is _A:A.loader._reader=A A.reset_reader();A.stream=stream def reset_reader(A):A.name=_A;A.stream_pointer=0;A.eof=True;A.buffer='';A.pointer=0;A.raw_buffer=_A;A.raw_decode=_A;A.encoding=_A;A.index=0;A.line=0;A.column=0 @property def stream(self): try:return self._stream except AttributeError:raise YAMLStreamError('input stream needs to specified') @stream.setter def stream(self,val): B=val;A=self if B is _A:return A._stream=_A if isinstance(B,text_type):A.name='';A.check_printable(B);A.buffer=B+_E elif isinstance(B,binary_type):A.name='';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','');A.eof=_D;A.raw_buffer=_A;A.determine_encoding() def peek(A,index=0): B=index try:return A.buffer[A.pointer+B] except IndexError:A.update(B+1);return A.buffer[A.pointer+B] def prefix(A,length=1): B=length if A.pointer+B>=len(A.buffer):A.update(B) return A.buffer[A.pointer:A.pointer+B] def forward_1_1(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 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 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 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) else:return FileMark(A.name,A.index,A.line,A.column) def determine_encoding(A): while not A.eof and(A.raw_buffer is _A or len(A.raw_buffer)<2):A.update_raw() if isinstance(A.raw_buffer,binary_type): if A.raw_buffer.startswith(codecs.BOM_UTF16_LE):A.raw_decode=codecs.utf_16_le_decode;A.encoding='utf-16-le' elif A.raw_buffer.startswith(codecs.BOM_UTF16_BE):A.raw_decode=codecs.utf_16_be_decode;A.encoding='utf-16-be' else:A.raw_decode=codecs.utf_8_decode;A.encoding='utf-8' 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) @classmethod def _get_non_printable_ascii(D,data): A=data.encode(_C);B=A.translate(_A,D._printable_ascii) if not B:return _A C=B[:1];return A.index(C),C.decode(_C) @classmethod def _get_non_printable_regex(B,data): A=B.NON_PRINTABLE.search(data) if not bool(A):return _A return A.start(),A.group() @classmethod def _get_non_printable(A,data): try:return A._get_non_printable_ascii(data) except UnicodeEncodeError:return A._get_non_printable_regex(data) def check_printable(A,data): B=A._get_non_printable(data) if B is not _A:C,D=B;E=A.index+(len(A.buffer)-A.pointer)+C;raise ReaderError(A.name,E,ord(D),'unicode','special characters are not allowed') def update(A,length): if A.raw_buffer is _A:return A.buffer=A.buffer[A.pointer:];A.pointer=0 while len(A.buffer)': comment=getattr(value,_F,_A) if comment:comment=[_A,[comment]] node=ScalarNode(tag,value,style=style,comment=comment,anchor=anchor) if self.alias_key is not _A:self.represented_objects[self.alias_key]=node return node def represent_sequence(self,tag,sequence,flow_style=_A): value=[];node=SequenceNode(tag,value,flow_style=flow_style) if self.alias_key is not _A:self.represented_objects[self.alias_key]=node best_style=_B for item in sequence: node_item=self.represent_data(item) if not(isinstance(node_item,ScalarNode)and not node_item.style):best_style=_C value.append(node_item) if flow_style is _A: if self.default_flow_style is not _A:node.flow_style=self.default_flow_style else:node.flow_style=best_style return node def represent_omap(self,tag,omap,flow_style=_A): value=[];node=SequenceNode(tag,value,flow_style=flow_style) if self.alias_key is not _A:self.represented_objects[self.alias_key]=node best_style=_B for item_key in omap:item_val=omap[item_key];node_item=self.represent_data({item_key:item_val});value.append(node_item) if flow_style is _A: if self.default_flow_style is not _A:node.flow_style=self.default_flow_style else:node.flow_style=best_style return node def represent_mapping(self,tag,mapping,flow_style=_A): value=[];node=MappingNode(tag,value,flow_style=flow_style) if self.alias_key is not _A:self.represented_objects[self.alias_key]=node best_style=_B if hasattr(mapping,'items'): mapping=list(mapping.items()) if self.sort_base_mapping_type_on_output: try:mapping=sorted(mapping) except TypeError:pass for (item_key,item_value) in mapping: node_key=self.represent_key(item_key);node_value=self.represent_data(item_value) if not(isinstance(node_key,ScalarNode)and not node_key.style):best_style=_C if not(isinstance(node_value,ScalarNode)and not node_value.style):best_style=_C value.append((node_key,node_value)) if flow_style is _A: if self.default_flow_style is not _A:node.flow_style=self.default_flow_style else:node.flow_style=best_style return node def ignore_aliases(self,data):return _C class SafeRepresenter(BaseRepresenter): def ignore_aliases(self,data): 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) 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) 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 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): try:value=self.dumper.boolean_representation[bool(data)] except AttributeError: if data:value='true' else:value='false' return self.represent_scalar('tag:yaml.org,2002:bool',value,anchor=anchor) def represent_int(self,data):return self.represent_scalar(_G,text_type(data)) if PY2: def represent_long(self,data):return self.represent_scalar(_G,text_type(data)) 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 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) 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) def represent_yaml_object(self,tag,data,cls,flow_style=_A): if hasattr(data,_a):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,)) SafeRepresenter.add_representer(type(_A),SafeRepresenter.represent_none) SafeRepresenter.add_representer(str,SafeRepresenter.represent_str) if PY2:SafeRepresenter.add_representer(unicode,SafeRepresenter.represent_unicode) else:SafeRepresenter.add_representer(bytes,SafeRepresenter.represent_binary) SafeRepresenter.add_representer(bool,SafeRepresenter.represent_bool) SafeRepresenter.add_representer(int,SafeRepresenter.represent_int) if PY2:SafeRepresenter.add_representer(long,SafeRepresenter.represent_long) SafeRepresenter.add_representer(float,SafeRepresenter.represent_float) SafeRepresenter.add_representer(list,SafeRepresenter.represent_list) SafeRepresenter.add_representer(tuple,SafeRepresenter.represent_list) SafeRepresenter.add_representer(dict,SafeRepresenter.represent_dict) SafeRepresenter.add_representer(set,SafeRepresenter.represent_set) SafeRepresenter.add_representer(ordereddict,SafeRepresenter.represent_ordereddict) if sys.version_info>=(2,7):import collections;SafeRepresenter.add_representer(collections.OrderedDict,SafeRepresenter.represent_ordereddict) SafeRepresenter.add_representer(datetime.date,SafeRepresenter.represent_date) SafeRepresenter.add_representer(datetime.datetime,SafeRepresenter.represent_datetime) SafeRepresenter.add_representer(_A,SafeRepresenter.represent_undefined) class Representer(SafeRepresenter): if PY2: def represent_str(self,data): 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 return self.represent_scalar(tag,data,style=style) def represent_unicode(self,data): tag=_A try:data.encode(_E);tag='tag:yaml.org,2002:python/unicode' except UnicodeEncodeError:tag=_D return self.represent_scalar(tag,data) def represent_long(self,data): tag=_G 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 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__) 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 if hasattr(data,'__getinitargs__'):args=list(data.__getinitargs__()) if hasattr(data,_a):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) value={} if bool(args):value[_c]=args value[_d]=state;return self.represent_mapping(_R+class_name,value) def represent_object(self,data): cls=type(data) if cls in copyreg.dispatch_table:reduce=copyreg.dispatch_table[cls](data) elif hasattr(data,'__reduce_ex__'):reduce=data.__reduce_ex__(2) elif hasattr(data,'__reduce__'):reduce=data.__reduce__() else:raise RepresenterError('cannot represent object: %r'%(data,)) reduce=(list(reduce)+[_A]*5)[:5];function,args,state,listitems,dictitems=reduce;args=list(args) 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 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) 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 listitems:value['listitems']=listitems if dictitems:value['dictitems']=dictitems return self.represent_mapping(tag+function_name,value) if PY2:Representer.add_representer(str,Representer.represent_str);Representer.add_representer(unicode,Representer.represent_unicode);Representer.add_representer(long,Representer.represent_long) Representer.add_representer(complex,Representer.represent_complex) Representer.add_representer(tuple,Representer.represent_tuple) Representer.add_representer(type,Representer.represent_name) if PY2:Representer.add_representer(types.ClassType,Representer.represent_name) Representer.add_representer(types.FunctionType,Representer.represent_name) Representer.add_representer(types.BuiltinFunctionType,Representer.represent_name) Representer.add_representer(types.ModuleType,Representer.represent_module) if PY2:Representer.add_multi_representer(types.InstanceType,Representer.represent_instance) Representer.add_multi_representer(object,Representer.represent_object) 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 SafeRepresenter.__init__(self,default_style=default_style,default_flow_style=default_flow_style,dumper=dumper) def ignore_aliases(self,data): try: if data.anchor is not _A and data.anchor.value is not _A:return _C 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,'') def represent_literal_scalarstring(self,data): tag=_A;style=_J;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 def represent_folded_scalarstring(self,data): tag=_A;style='>';anchor=data.yaml_anchor(any=_B) for fold_pos in reversed(getattr(data,'fold_pos',[])): if data[fold_pos]==' 'and(fold_pos>0 and not data[fold_pos-1].isspace())and(fold_pos0:sl.insert(pos,A);pos-=underscore[0] s=''.join(sl) if underscore[1]:s=A+s if underscore[2]:s+=A return self.represent_scalar(_G,prefix+s,anchor=anchor) def represent_scalar_int(self,data): if data._width is not _A:s='{:0{}d}'.format(data,data._width) else:s=format(data,'d') anchor=data.yaml_anchor(any=_B);return self.insert_underscore('',s,data._underscore,anchor=anchor) def represent_binary_int(self,data): if data._width is not _A:s='{:0{}b}'.format(data,data._width) else:s=format(data,'b') anchor=data.yaml_anchor(any=_B);return self.insert_underscore('0b',s,data._underscore,anchor=anchor) def represent_octal_int(self,data): if data._width is not _A:s='{:0{}o}'.format(data,data._width) else:s=format(data,'o') anchor=data.yaml_anchor(any=_B);return self.insert_underscore('0o',s,data._underscore,anchor=anchor) def represent_hex_int(self,data): if data._width is not _A:s='{:0{}x}'.format(data,data._width) else:s=format(data,'x') anchor=data.yaml_anchor(any=_B);return self.insert_underscore('0x',s,data._underscore,anchor=anchor) def represent_hex_caps_int(self,data): if data._width is not _A:s='{:0{}X}'.format(data,data._width) 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) 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) while len(value)0 else data._width+1 if data<0:w+=1 m=m[:w];e=int(es);m1,m2=m.split(_H) while len(m1)+len(m2)=0 else 0):m2+=A if data._m_sign and data>0:m1=C+m1 esgn=C 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)0:m2=A*(data._m_lead0-1)+m1+m2;m1=A;m2=m2[:-data._m_lead0];e+=data._m_lead0 while len(m1)=len(node.comment):continue nc=node.comment[idx] 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) return SafeRepresenter.represent_key(self,data) def represent_mapping(self,tag,mapping,flow_style=_A): value=[] try:flow_style=mapping.fa.flow_style(flow_style) except AttributeError:flow_style=flow_style try:anchor=mapping.yaml_anchor() except AttributeError:anchor=_A node=MappingNode(tag,value,flow_style=flow_style,anchor=anchor) if self.alias_key is not _A:self.represented_objects[self.alias_key]=node best_style=_B try: comment=getattr(mapping,comment_attrib);node.comment=comment.comment if node.comment and node.comment[1]: for ct in node.comment[1]:ct.reset() item_comments=comment.items for v in item_comments.values(): if v and v[1]: for ct in v[1]:ct.reset() try:node.comment.append(comment.end) except AttributeError:pass except AttributeError:item_comments={} merge_list=[m[1]for m in getattr(mapping,merge_attrib,[])] try:merge_pos=getattr(mapping,merge_attrib,[[0]])[0][0] except IndexError:merge_pos=0 item_count=0 if bool(merge_list):items=mapping.non_merged_items() else:items=mapping.items() for (item_key,item_value) in items: item_count+=1;node_key=self.represent_key(item_key);node_value=self.represent_data(item_value);item_comment=item_comments.get(item_key) if item_comment: assert getattr(node_key,_F,_A)is _A;node_key.comment=item_comment[:2];nvc=getattr(node_value,_F,_A) if nvc is not _A:nvc[0]=item_comment[2];nvc[1]=item_comment[3] else:node_value.comment=item_comment[2:] if not(isinstance(node_key,ScalarNode)and not node_key.style):best_style=_C if not(isinstance(node_value,ScalarNode)and not node_value.style):best_style=_C value.append((node_key,node_value)) if flow_style is _A: if(item_count!=0 or bool(merge_list))and self.default_flow_style is not _A:node.flow_style=self.default_flow_style else:node.flow_style=best_style if bool(merge_list): if len(merge_list)==1:arg=self.represent_data(merge_list[0]) else:arg=self.represent_data(merge_list);arg.flow_style=_B value.insert(merge_pos,(ScalarNode('tag:yaml.org,2002:merge','<<'),arg)) return node def represent_omap(self,tag,omap,flow_style=_A): value=[] try:flow_style=omap.fa.flow_style(flow_style) except AttributeError:flow_style=flow_style try:anchor=omap.yaml_anchor() except AttributeError:anchor=_A node=SequenceNode(tag,value,flow_style=flow_style,anchor=anchor) if self.alias_key is not _A:self.represented_objects[self.alias_key]=node best_style=_B try: comment=getattr(omap,comment_attrib);node.comment=comment.comment if node.comment and node.comment[1]: for ct in node.comment[1]:ct.reset() item_comments=comment.items for v in item_comments.values(): if v and v[1]: for ct in v[1]:ct.reset() try:node.comment.append(comment.end) except AttributeError:pass except AttributeError:item_comments={} for item_key in omap: item_val=omap[item_key];node_item=self.represent_data({item_key:item_val});item_comment=item_comments.get(item_key) if item_comment: if item_comment[1]:node_item.comment=[_A,item_comment[1]] assert getattr(node_item.value[0][0],_F,_A)is _A;node_item.value[0][0].comment=[item_comment[0],_A];nvc=getattr(node_item.value[0][1],_F,_A) if nvc is not _A:nvc[0]=item_comment[2];nvc[1]=item_comment[3] else:node_item.value[0][1].comment=item_comment[2:] value.append(node_item) if flow_style is _A: if self.default_flow_style is not _A:node.flow_style=self.default_flow_style 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) try:anchor=setting.yaml_anchor() except AttributeError:anchor=_A node=MappingNode(tag,value,flow_style=flow_style,anchor=anchor) if self.alias_key is not _A:self.represented_objects[self.alias_key]=node best_style=_B try: comment=getattr(setting,comment_attrib);node.comment=comment.comment if node.comment and node.comment[1]: for ct in node.comment[1]:ct.reset() item_comments=comment.items for v in item_comments.values(): if v and v[1]: for ct in v[1]:ct.reset() try:node.comment.append(comment.end) except AttributeError:pass except AttributeError:item_comments={} for item_key in setting.odict: node_key=self.represent_key(item_key);node_value=self.represent_data(_A);item_comment=item_comments.get(item_key) if item_comment:assert getattr(node_key,_F,_A)is _A;node_key.comment=item_comment[:2] node_key.style=node_value.style='?' if not(isinstance(node_key,ScalarNode)and not node_key.style):best_style=_C if not(isinstance(node_value,ScalarNode)and not node_value.style):best_style=_C value.append((node_key,node_value)) best_style=best_style;return node def represent_dict(self,data): try:t=data.tag.value except AttributeError:t=_A if t: if t.startswith('!!'):tag=_e+t[2:] else:tag=t else:tag=_P 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:] else:tag=t else:tag=_O 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 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)) def represent_tagged_scalar(self,data): try:tag=data.tag.value except AttributeError:tag=_A try:anchor=data.yaml_anchor() except AttributeError:anchor=_A return self.represent_scalar(tag,data.value,style=data.style,anchor=anchor) def represent_scalar_bool(self,data): try:anchor=data.yaml_anchor() except AttributeError:anchor=_A return SafeRepresenter.represent_bool(self,data,anchor=anchor) RoundTripRepresenter.add_representer(type(_A),RoundTripRepresenter.represent_none) RoundTripRepresenter.add_representer(LiteralScalarString,RoundTripRepresenter.represent_literal_scalarstring) RoundTripRepresenter.add_representer(FoldedScalarString,RoundTripRepresenter.represent_folded_scalarstring) RoundTripRepresenter.add_representer(SingleQuotedScalarString,RoundTripRepresenter.represent_single_quoted_scalarstring) RoundTripRepresenter.add_representer(DoubleQuotedScalarString,RoundTripRepresenter.represent_double_quoted_scalarstring) RoundTripRepresenter.add_representer(PlainScalarString,RoundTripRepresenter.represent_plain_scalarstring) RoundTripRepresenter.add_representer(ScalarInt,RoundTripRepresenter.represent_scalar_int) RoundTripRepresenter.add_representer(BinaryInt,RoundTripRepresenter.represent_binary_int) RoundTripRepresenter.add_representer(OctalInt,RoundTripRepresenter.represent_octal_int) RoundTripRepresenter.add_representer(HexInt,RoundTripRepresenter.represent_hex_int) RoundTripRepresenter.add_representer(HexCapsInt,RoundTripRepresenter.represent_hex_caps_int) RoundTripRepresenter.add_representer(ScalarFloat,RoundTripRepresenter.represent_scalar_float) RoundTripRepresenter.add_representer(ScalarBoolean,RoundTripRepresenter.represent_scalar_bool) RoundTripRepresenter.add_representer(CommentedSeq,RoundTripRepresenter.represent_list) RoundTripRepresenter.add_representer(CommentedMap,RoundTripRepresenter.represent_dict) RoundTripRepresenter.add_representer(CommentedOrderedMap,RoundTripRepresenter.represent_ordereddict) if sys.version_info>=(2,7):import collections;RoundTripRepresenter.add_representer(collections.OrderedDict,RoundTripRepresenter.represent_ordereddict) RoundTripRepresenter.add_representer(CommentedSet,RoundTripRepresenter.represent_set) RoundTripRepresenter.add_representer(TaggedScalar,RoundTripRepresenter.represent_tagged_scalar) RoundTripRepresenter.add_representer(TimeStamp,RoundTripRepresenter.represent_datetime)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807560.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/resolver.py0000644000175000017500000002252700000000000024470 0ustar00rochacbrunorochacbrunofrom __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 _B=False _A=None import re if _B:from typing import Any,Dict,List,Union,Text,Optional;from .compat import VersionType from .compat import string_types,_DEFAULT_YAML_VERSION 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('!&*'))] 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={} def __init__(self,loadumper=_A): self.loadumper=loadumper if self.loadumper is not _A and getattr(self.loadumper,'_resolver',_A)is _A:self.loadumper._resolver=self.loadumper self._loader_version=_A;self.resolver_exact_paths=[];self.resolver_prefix_paths=[] @property def parser(self): if self.loadumper is not _A: if hasattr(self.loadumper,_I):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 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 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)) @classmethod def add_path_resolver(cls,tag,path,kind=_A): if'yaml_path_resolvers'not in cls.__dict__:cls.yaml_path_resolvers=cls.yaml_path_resolvers.copy() new_path=[] 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 else:raise ResolverError('Invalid path element: %s'%(element,)) else:node_check=_A;index_check=element if node_check is str:node_check=ScalarNode elif node_check is list:node_check=SequenceNode elif node_check is dict:node_check=MappingNode elif node_check not in[ScalarNode,SequenceNode,MappingNode]and not isinstance(node_check,string_types)and node_check is not _A:raise ResolverError('Invalid node checker: %s'%(node_check,)) if not isinstance(index_check,(string_types,int))and index_check is not _A:raise ResolverError('Invalid index checker: %s'%(index_check,)) new_path.append((node_check,index_check)) if kind is str:kind=ScalarNode elif kind is list:kind=SequenceNode elif kind is dict:kind=MappingNode elif kind not in[ScalarNode,SequenceNode,MappingNode]and kind is not _A:raise ResolverError('Invalid node kind: %s'%(kind,)) cls.yaml_path_resolvers[tuple(new_path),kind]=tag def descend_resolver(self,current_node,current_index): if not self.yaml_path_resolvers:return exact_paths={};prefix_paths=[] if current_node: depth=len(self.resolver_prefix_paths) for (path,kind) in self.resolver_prefix_paths[-1]: if self.check_resolver_prefix(depth,path,kind,current_node,current_index): if len(path)>depth:prefix_paths.append((path,kind)) else:exact_paths[kind]=self.yaml_path_resolvers[path,kind] else: for (path,kind) in self.yaml_path_resolvers: if not path:exact_paths[kind]=self.yaml_path_resolvers[path,kind] else:prefix_paths.append((path,kind)) self.resolver_exact_paths.append(exact_paths);self.resolver_prefix_paths.append(prefix_paths) def ascend_resolver(self): if not self.yaml_path_resolvers:return self.resolver_exact_paths.pop();self.resolver_prefix_paths.pop() def check_resolver_prefix(self,depth,path,kind,current_node,current_index): node_check,index_check=path[depth-1] if isinstance(node_check,string_types): 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 _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 def resolve(self,kind,value,implicit): if kind is ScalarNode and implicit[0]: if value=='':resolvers=self.yaml_implicit_resolvers.get('',[]) else:resolvers=self.yaml_implicit_resolvers.get(value[0],[]) resolvers+=self.yaml_implicit_resolvers.get(_A,[]) for (tag,regexp) in resolvers: if regexp.match(value):return tag implicit=implicit[1] if bool(self.yaml_path_resolvers): exact_paths=self.resolver_exact_paths[-1] if kind in exact_paths:return exact_paths[kind] if _A in exact_paths:return exact_paths[_A] if kind is ScalarNode:return self.DEFAULT_SCALAR_TAG elif kind is SequenceNode:return self.DEFAULT_SEQUENCE_TAG elif kind is MappingNode:return self.DEFAULT_MAPPING_TAG @property def processing_version(self):return _A class Resolver(BaseResolver):0 for ir in implicit_resolvers: if(1,2)in ir[0]:Resolver.add_implicit_resolver_base(*ir[1:]) class VersionedResolver(BaseResolver): def __init__(self,version=_A,loader=_A,loadumper=_A): if loader is _A and loadumper is not _A:loader=loadumper BaseResolver.__init__(self,loader);self._loader_version=self.get_loader_version(version);self._version_implicit_resolver={} def add_version_implicit_resolver(self,version,tag,regexp,first): if first is _A:first=[_A] impl_resolver=self._version_implicit_resolver.setdefault(version,{}) for ch in first:impl_resolver.setdefault(ch,[]).append((tag,regexp)) def get_loader_version(self,version): if version is _A or isinstance(version,tuple):return version if isinstance(version,list):return tuple(version) return tuple(map(int,version.split('.'))) @property def versioned_resolver(self): version=self.processing_version if version not in self._version_implicit_resolver: for x in implicit_resolvers: if version in x[0]:self.add_version_implicit_resolver(version,x[1],x[2],x[3]) return self._version_implicit_resolver[version] def resolve(self,kind,value,implicit): if kind is ScalarNode and implicit[0]: if value=='':resolvers=self.versioned_resolver.get('',[]) else:resolvers=self.versioned_resolver.get(value[0],[]) resolvers+=self.versioned_resolver.get(_A,[]) for (tag,regexp) in resolvers: if regexp.match(value):return tag implicit=implicit[1] if bool(self.yaml_path_resolvers): exact_paths=self.resolver_exact_paths[-1] if kind in exact_paths:return exact_paths[kind] if _A in exact_paths:return exact_paths[_A] if kind is ScalarNode:return self.DEFAULT_SCALAR_TAG elif kind is SequenceNode:return self.DEFAULT_SEQUENCE_TAG elif kind is MappingNode:return self.DEFAULT_MAPPING_TAG @property def processing_version(self): try:version=self.loadumper._scanner.yaml_version except AttributeError: try: if hasattr(self.loadumper,_I):version=self.loadumper.version else:version=self.loadumper._serializer.use_version except AttributeError:version=_A if version is _A: version=self._loader_version if version is _A:version=_DEFAULT_YAML_VERSION return version././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807561.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/scalarbool.py0000644000175000017500000000133100000000000024736 0ustar00rochacbrunorochacbrunofrom __future__ import print_function,absolute_import,division,unicode_literals _B=False _A=None from .anchor import Anchor 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) if B is not _A:C.yaml_set_anchor(B,always_dump=True) return C @property def anchor(self): A=self if not hasattr(A,Anchor.attrib):setattr(A,Anchor.attrib,Anchor()) return getattr(A,Anchor.attrib) def yaml_anchor(A,any=_B): if not hasattr(A,Anchor.attrib):return _A if any or A.anchor.always_dump:return A.anchor return _A def yaml_set_anchor(A,value,always_dump=_B):A.anchor.value=value;A.anchor.always_dump=always_dump././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807561.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/scalarfloat.py0000644000175000017500000000442600000000000025120 0ustar00rochacbrunorochacbrunofrom __future__ import print_function,absolute_import,division,unicode_literals _B=False _A=None import sys from .compat import no_limit_int from .anchor import Anchor 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 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 def __ifloordiv__(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 def __imul__(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;B._prec=A._prec;return B def __ipow__(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 def __isub__(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 @property def anchor(self): A=self if not hasattr(A,Anchor.attrib):setattr(A,Anchor.attrib,Anchor()) return getattr(A,Anchor.attrib) def yaml_anchor(A,any=_B): if not hasattr(A,Anchor.attrib):return _A if any or A.anchor.always_dump:return A.anchor return _A def yaml_set_anchor(A,value,always_dump=_B):A.anchor.value=value;A.anchor.always_dump=always_dump def dump(A,out=sys.stdout):out.write('ScalarFloat({}| w:{}, p:{}, s:{}, lz:{}, _:{}|{}, w:{}, s:{})\n'.format(A,A._width,A._prec,A._m_sign,A._m_lead0,A._underscore,A._exp,A._e_width,A._e_sign)) class ExponentialFloat(ScalarFloat): def __new__(A,value,width=_A,underscore=_A):return ScalarFloat.__new__(A,value,width=width,underscore=underscore) class ExponentialCapsFloat(ScalarFloat): def __new__(A,value,width=_A,underscore=_A):return ScalarFloat.__new__(A,value,width=width,underscore=underscore)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807561.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/scalarint.py0000644000175000017500000000447200000000000024606 0ustar00rochacbrunorochacbrunofrom __future__ import print_function,absolute_import,division,unicode_literals _B=False _A=None from .compat import no_limit_int from .anchor import Anchor 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 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 def __ifloordiv__(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 def __imul__(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 def __ipow__(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 def __isub__(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 @property def anchor(self): A=self if not hasattr(A,Anchor.attrib):setattr(A,Anchor.attrib,Anchor()) return getattr(A,Anchor.attrib) def yaml_anchor(A,any=_B): if not hasattr(A,Anchor.attrib):return _A if any or A.anchor.always_dump:return A.anchor return _A def yaml_set_anchor(A,value,always_dump=_B):A.anchor.value=value;A.anchor.always_dump=always_dump class BinaryInt(ScalarInt): def __new__(A,value,width=_A,underscore=_A,anchor=_A):return ScalarInt.__new__(A,value,width=width,underscore=underscore,anchor=anchor) class OctalInt(ScalarInt): def __new__(A,value,width=_A,underscore=_A,anchor=_A):return ScalarInt.__new__(A,value,width=width,underscore=underscore,anchor=anchor) class HexInt(ScalarInt): def __new__(A,value,width=_A,underscore=_A,anchor=_A):return ScalarInt.__new__(A,value,width=width,underscore=underscore,anchor=anchor) class HexCapsInt(ScalarInt): def __new__(A,value,width=_A,underscore=_A,anchor=_A):return ScalarInt.__new__(A,value,width=width,underscore=underscore,anchor=anchor) class DecimalInt(ScalarInt): def __new__(A,value,width=_A,underscore=_A,anchor=_A):return ScalarInt.__new__(A,value,width=width,underscore=underscore,anchor=anchor)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807561.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/scalarstring.py0000644000175000017500000000455600000000000025325 0ustar00rochacbrunorochacbrunofrom __future__ import print_function,absolute_import,division,unicode_literals _D='comment' _C='\n' _B=False _A=None from .compat import text_type from .anchor import Anchor if _B:from typing import Text,Any,Dict,List __all__=['ScalarString','LiteralScalarString','FoldedScalarString','SingleQuotedScalarString','DoubleQuotedScalarString','PlainScalarString','PreservedScalarString'] class ScalarString(text_type): __slots__=Anchor.attrib def __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)) @property def anchor(self): A=self if not hasattr(A,Anchor.attrib):setattr(A,Anchor.attrib,Anchor()) return getattr(A,Anchor.attrib) def yaml_anchor(A,any=_B): if not hasattr(A,Anchor.attrib):return _A if any or A.anchor.always_dump:return A.anchor 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='|' def __new__(A,value,anchor=_A):return ScalarString.__new__(A,value,anchor=anchor) PreservedScalarString=LiteralScalarString class FoldedScalarString(ScalarString): __slots__='fold_pos',_D;style='>' def __new__(A,value,anchor=_A):return ScalarString.__new__(A,value,anchor=anchor) class SingleQuotedScalarString(ScalarString): __slots__=();style="'" def __new__(A,value,anchor=_A):return ScalarString.__new__(A,value,anchor=anchor) class DoubleQuotedScalarString(ScalarString): __slots__=();style='"' def __new__(A,value,anchor=_A):return ScalarString.__new__(A,value,anchor=anchor) 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 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 isinstance(A,G): for F in A: C=A[F] if isinstance(C,E): for B in map: if B in C:A[F]=map[B](C);break else:walk_tree(C) elif isinstance(A,H): for (I,D) in enumerate(A): if isinstance(D,E): for B in map: if B in D:A[I]=map[B](D);break else:walk_tree(D)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807561.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/scanner.py0000644000175000017500000007753000000000000024264 0ustar00rochacbrunorochacbrunofrom __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="'" _I='\x00' _H='!' _G='while scanning a directive' _F='#' _E='\n' _D=' ' _C=None _B=False _A=True from .error import MarkedYAMLError from .tokens import * from .compat import utf8,unichr,PY3,check_anchorname_char,nprint if _B:from typing import Any,Dict,Optional,List,Union,Text;from .compat import VersionType __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 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 class Scanner: def __init__(self,loader=_C): self.loader=loader if self.loader is not _C and getattr(self.loader,'_scanner',_C)is _C:self.loader._scanner=self self.reset_scanner();self.first_time=_B;self.yaml_version=_C @property def flow_level(self):return len(self.flow_context) def reset_scanner(self):self.done=_B;self.flow_context=[];self.tokens=[];self.fetch_stream_start();self.tokens_taken=0;self.indent=-1;self.indents=[];self.allow_simple_key=_A;self.possible_simple_keys={} @property def reader(self): try:return self._scanner_reader except AttributeError: if hasattr(self.loader,_c):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 return self.loader.processing_version def check_token(self,*choices): while self.need_more_tokens():self.fetch_more_tokens() if bool(self.tokens): if not choices:return _A for choice in choices: if isinstance(self.tokens[0],choice):return _A return _B def peek_token(self): while self.need_more_tokens():self.fetch_more_tokens() if bool(self.tokens):return self.tokens[0] def get_token(self): while self.need_more_tokens():self.fetch_more_tokens() if bool(self.tokens):self.tokens_taken+=1;return self.tokens.pop(0) def need_more_tokens(self): if self.done:return _B if not self.tokens:return _A self.stale_possible_simple_keys() if self.next_possible_simple_key()==self.tokens_taken:return _A return _B def fetch_comment(self,comment):raise NotImplementedError def fetch_more_tokens(self): comment=self.scan_to_next_token() if comment is not _C:return self.fetch_comment(comment) 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_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_key():return self.fetch_key() if ch==_O 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 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): min_token_number=_C for level in self.possible_simple_keys: key=self.possible_simple_keys[level] if min_token_number is _C or key.token_number1024: if key.required:raise ScannerError(_d,key.mark,_e,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 if self.allow_simple_key:self.remove_possible_simple_key();token_number=self.tokens_taken+len(self.tokens);key=SimpleKey(token_number,required,self.reader.index,self.reader.line,self.reader.column,self.reader.get_mark());self.possible_simple_keys[self.flow_level]=key 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()) del self.possible_simple_keys[self.flow_level] def unwind_indent(self,column): if bool(self.flow_level):return while self.indent>column:mark=self.reader.get_mark();self.indent=self.indents.pop();self.tokens.append(BlockEndToken(mark,mark)) def add_indent(self,column): if self.indent', 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: if ch==_H:use_handle=_A;break length+=1;ch=srp(length) handle=_H if use_handle:handle=self.scan_tag_handle(A,start_mark) 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()) 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 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 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 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 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 not breaks:chunks.append(_D) else:chunks.append(line_break) else:break trailing=[] if chomping in[_C,_A]:chunks.append(line_break) if chomping is _A:chunks.extend(breaks) elif chomping in[_C,_B]:trailing.extend(breaks) token=ScalarToken(''.join(chunks),_B,start_mark,end_mark,style) if block_scalar_comment is not _C:token.add_pre_comments([block_scalar_comment]) if len(trailing)>0: comment=self.scan_to_next_token() while comment:trailing.append(_D*comment[1].column+comment[0]);comment=self.scan_to_next_token() 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 else:chomping=_B self.reader.forward();ch=srp() if ch in C: increment=int(ch) if increment==0:raise ScannerError(_W,start_mark,D,self.reader.get_mark()) self.reader.forward() elif ch in C: increment=int(ch) if increment==0:raise ScannerError(_W,start_mark,D,self.reader.get_mark()) self.reader.forward();ch=srp() if ch in A: if ch==B: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()) return chomping,increment def scan_block_scalar_ignored_line(self,start_mark): srp=self.reader.peek;srf=self.reader.forward;prefix='';comment=_C while srp()==_D:prefix+=srp();srf() if srp()==_F: 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()) 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: if srp()!=_D:chunks.append(self.scan_line_break());end_mark=self.reader.get_mark() else: srf() if self.reader.column>max_indent:max_indent=self.reader.column return chunks,max_indent,end_mark 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(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) if length!=0:chunks.append(self.reader.prefix(length));self.reader.forward(length);length=0 if not chunks:raise ScannerError('while parsing a %s'%(name,),start_mark,'expected URI, but found %r'%utf8(ch),self.reader.get_mark()) return ''.join(chunks) def scan_uri_escapes(self,name,start_mark): A='utf-8';srp=self.reader.peek;srf=self.reader.forward;code_bytes=[];mark=self.reader.get_mark() 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 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) 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) else:self.reader.forward() return _E elif ch in _o:self.reader.forward();return ch return'' class RoundTripScanner(Scanner): def check_token(self,*choices): while self.need_more_tokens():self.fetch_more_tokens() self._gather_comments() if bool(self.tokens): if not choices:return _A for choice in choices: if isinstance(self.tokens[0],choice):return _A return _B def peek_token(self): while self.need_more_tokens():self.fetch_more_tokens() self._gather_comments() if bool(self.tokens):return self.tokens[0] return _C def _gather_comments(self): comments=[] if not self.tokens:return comments if isinstance(self.tokens[0],CommentToken):comment=self.tokens.pop(0);self.tokens_taken+=1;comments.append(comment) while self.need_more_tokens(): self.fetch_more_tokens() if not self.tokens:return comments if isinstance(self.tokens[0],CommentToken):self.tokens_taken+=1;comment=self.tokens.pop(0);comments.append(comment) if len(comments)>=1:self.tokens[0].add_pre_comments(comments) if not self.done and len(self.tokens)<2:self.fetch_more_tokens() def get_token(self): while self.need_more_tokens():self.fetch_more_tokens() self._gather_comments() if bool(self.tokens): if len(self.tokens)>1 and isinstance(self.tokens[0],(ScalarToken,ValueToken,FlowSequenceEndToken,FlowMappingEndToken))and isinstance(self.tokens[1],CommentToken)and self.tokens[0].end_mark.line==self.tokens[1].start_mark.line: self.tokens_taken+=1;c=self.tokens.pop(1);self.fetch_more_tokens() while len(self.tokens)>1 and isinstance(self.tokens[1],CommentToken):self.tokens_taken+=1;c1=self.tokens.pop(1);c.value=c.value+_D*c1.start_mark.column+c1.value;self.fetch_more_tokens() self.tokens[0].add_post_comment(c) elif len(self.tokens)>1 and isinstance(self.tokens[0],ScalarToken)and isinstance(self.tokens[1],CommentToken)and self.tokens[0].end_mark.line!=self.tokens[1].start_mark.line: self.tokens_taken+=1;c=self.tokens.pop(1);c.value=_E*(c.start_mark.line-self.tokens[0].end_mark.line)+_D*c.start_mark.column+c.value;self.tokens[0].add_post_comment(c);self.fetch_more_tokens() while len(self.tokens)>1 and isinstance(self.tokens[1],CommentToken):self.tokens_taken+=1;c1=self.tokens.pop(1);c.value=c.value+_D*c1.start_mark.column+c1.value;self.fetch_more_tokens() self.tokens_taken+=1;return self.tokens.pop(0) return _C def fetch_comment(self,comment): value,start_mark,end_mark=comment while value and value[-1]==_D:value=value[:-1] 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() found=_B while not found: while srp()==_D:srf() ch=srp() if ch==_F: start_mark=self.reader.get_mark();comment=ch;srf() while ch not in _THE_END: ch=srp() if ch==_I:comment+=_E;break comment+=ch;srf() ch=self.scan_line_break() while len(ch)>0:comment+=ch;ch=self.scan_line_break() end_mark=self.reader.get_mark() if not self.flow_level:self.allow_simple_key=_A return comment,start_mark,end_mark if bool(self.scan_line_break()): start_mark=self.reader.get_mark() if not self.flow_level:self.allow_simple_key=_A ch=srp() if ch==_E: start_mark=self.reader.get_mark();comment='' while ch:ch=self.scan_line_break(empty_line=_A);comment+=ch if srp()==_F:comment=comment.rsplit(_E,1)[0]+_E end_mark=self.reader.get_mark();return comment,start_mark,end_mark else:found=_A 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) else:self.reader.forward() return _E elif ch in _o: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)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807561.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/serializer.py0000644000175000017500000001002400000000000024765 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import _F='serializer is not opened' _E='serializer is closed' _D='typ' _C=False _B=True _A=None from .error import YAMLError from .compat import nprint,DBG_NODE,dbg,string_types,nprintf from .util import RegExp from .events import StreamStartEvent,StreamEndEvent,MappingStartEvent,MappingEndEvent,SequenceStartEvent,SequenceEndEvent,AliasEvent,ScalarEvent,DocumentStartEvent,DocumentEndEvent from .nodes import MappingNode,ScalarNode,SequenceNode if _C:from typing import Any,Dict,Union,Text,Optional;from .compat import VersionType __all__=['Serializer','SerializerError'] class SerializerError(YAMLError):0 class Serializer: ANCHOR_TEMPLATE='id%03d';ANCHOR_RE=RegExp('id(?!000$)\\d{3,}') def __init__(A,encoding=_A,explicit_start=_A,explicit_end=_A,version=_A,tags=_A,dumper=_A): B=version;A.dumper=dumper if A.dumper is not _A:A.dumper._serializer=A A.use_encoding=encoding;A.use_explicit_start=explicit_start;A.use_explicit_end=explicit_end if isinstance(B,string_types):A.use_version=tuple(map(int,B.split('.'))) else:A.use_version=B A.use_tags=tags;A.serialized_nodes={};A.anchors={};A.last_anchor_id=0;A.closed=_A;A._templated_id=_A @property def emitter(self): A=self if hasattr(A.dumper,_D):return A.dumper.emitter return A.dumper._emitter @property def resolver(self): A=self if hasattr(A.dumper,_D):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) else:raise SerializerError('serializer is already opened') def close(A): if A.closed is _A:raise SerializerError(_F) 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) 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 if A in B.anchors: if B.anchors[A]is _A:B.anchors[A]=B.generate_anchor(A) else: C=_A try: if A.anchor.always_dump:C=A.anchor.value except:pass B.anchors[A]=C if isinstance(A,SequenceNode): for D in A.value:B.anchor_node(D) elif isinstance(A,MappingNode): for (E,F) in A.value:B.anchor_node(E);B.anchor_node(F) def generate_anchor(A,node): try:B=node.anchor.value except:B=_A if B is _A:A.last_anchor_id+=1;return A.ANCHOR_TEMPLATE%A.last_anchor_id return B def serialize_node(B,node,parent,index): F=index;A=node;G=B.anchors[A] if A in B.serialized_nodes:B.emitter.emit(AliasEvent(G)) else: B.serialized_nodes[A]=_B;B.resolver.descend_resolver(parent,F) if isinstance(A,ScalarNode):K=B.resolver.resolve(ScalarNode,A.value,(_B,_C));L=B.resolver.resolve(ScalarNode,A.value,(_C,_B));E=A.tag==K,A.tag==L,A.tag.startswith('tag:yaml.org,2002:');B.emitter.emit(ScalarEvent(G,A.tag,E,A.value,style=A.style,comment=A.comment)) elif isinstance(A,SequenceNode): E=A.tag==B.resolver.resolve(SequenceNode,A.value,_B);C=A.comment;D=_A;H=_A if A.flow_style is _B: if C:H=C[0] if C and len(C)>2:D=C[2] else:D=_A B.emitter.emit(SequenceStartEvent(G,A.tag,E,flow_style=A.flow_style,comment=A.comment));F=0 for M in A.value:B.serialize_node(M,A,F);F+=1 B.emitter.emit(SequenceEndEvent(comment=[H,D])) elif isinstance(A,MappingNode): E=A.tag==B.resolver.resolve(MappingNode,A.value,_B);C=A.comment;D=_A;I=_A if A.flow_style is _B: if C:I=C[0] if C and len(C)>2:D=C[2] B.emitter.emit(MappingStartEvent(G,A.tag,E,flow_style=A.flow_style,comment=A.comment,nr_items=len(A.value))) for (J,N) in A.value:B.serialize_node(J,A,_A);B.serialize_node(N,A,J) B.emitter.emit(MappingEndEvent(comment=[I,D])) B.resolver.ascend_resolver() def templated_id(s):return Serializer.ANCHOR_RE.match(s)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807562.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/setup.py0000644000175000017500000004511300000000000023763 0ustar00rochacbrunorochacbrunofrom __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' _M='DVDEBUG' _L='LICENSE' _K='Jython' _J='install' _I='full_package_name' _H='__init__.py' _G='python' _F='setup.py' _E='utf-8' _D=True _C=False _B='.' _A=None import sys,os,datetime,traceback sys.path=[path for path in sys.path if path not in[os.getcwd(),'']] import platform from _ast import * from ast import parse from setuptools import setup,Extension,Distribution from setuptools.command import install_lib from setuptools.command.sdist import sdist as _sdist try:from setuptools.namespaces import Installer as NameSpaceInstaller except ImportError:msg='You should use the latest setuptools. The namespaces.py file that this setup.py uses was added in setuptools 28.7.0 (Oct 2016)';print(msg);sys.exit() if __name__!='__main__':raise NotImplementedError('should never include setup.py') full_package_name=_A if sys.version_info<(3,):string_type=basestring else:string_type=str if sys.version_info<(3,4): class Bytes:0 class NameConstant:0 if sys.version_info>=(3,8):from ast import Str,Num,Bytes,NameConstant if sys.version_info<(3,):open_kw=dict() else:open_kw=dict(encoding=_E) if sys.version_info<(2,7)or platform.python_implementation()==_K: class Set:0 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) def literal_eval(node_or_string): _safe_names={'None':_A,_N:_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') def _convert(node): if isinstance(node,Str): if sys.version_info<(3,)and not isinstance(node.s,unicode):return node.s.decode(_E) return node.s elif isinstance(node,Bytes):return node.s elif isinstance(node,Num):return node.n elif isinstance(node,Tuple):return tuple(map(_convert,node.elts)) elif isinstance(node,List):return list(map(_convert,node.elts)) elif isinstance(node,Set):return set(map(_convert,node.elts)) elif isinstance(node,Dict):return dict(((_convert(k),_convert(v))for(k,v)in zip(node.keys,node.values))) elif isinstance(node,NameConstant):return node.value elif sys.version_info<(3,4)and isinstance(node,Name): if node.id in _safe_names:return _safe_names[node.id] elif isinstance(node,UnaryOp)and isinstance(node.op,(UAdd,USub))and isinstance(node.operand,(Num,UnaryOp,BinOp)): operand=_convert(node.operand) if isinstance(node.op,UAdd):return+operand else:return-operand elif isinstance(node,BinOp)and isinstance(node.op,(Add,Sub))and isinstance(node.right,(Num,UnaryOp,BinOp))and isinstance(node.left,(Num,UnaryOp,BinOp)): left=_convert(node.left);right=_convert(node.right) if isinstance(node.op,Add):return left+right else:return left-right elif isinstance(node,Call): 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]) err=SyntaxError('malformed node or string: '+repr(node));err.filename='';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): data={} with open(fn,**open_kw)as fp: parsing=_C;lines=[] for line in fp.readlines(): if sys.version_info<(3,):line=line.decode(_E) if line.startswith('_package_data'): if'dict('in line:parsing=_G;lines.append('dict(\n') elif line.endswith('= {\n'):parsing=_G;lines.append('{\n') else:raise NotImplementedError continue if not parsing:continue if parsing==_G: if line.startswith(')')or line.startswith('}'): lines.append(line) try:data=literal_eval(''.join(lines)) except SyntaxError as e: context=2;from_line=e.lineno-(context+1);to_line=e.lineno+(context-1);w=len(str(to_line)) for (index,line) in enumerate(lines): if from_line<=index<=to_line: print('{0:{1}}: {2}'.format(index,w,line).encode(_E),end='') if index==e.lineno-1:print('{0:{1}} {2}^--- {3}'.format(' ',w,' '*e.offset,e.node)) raise break lines.append(line) else:raise NotImplementedError return data pkg_data=_package_data(__file__.replace(_F,_H)) exclude_files=[_F] def _check_convert_version(tup): ret_val=str(tup[0]);next_sep=_B;nr_digits=0;post_dev=_C for x in tup[1:]: if isinstance(x,int): nr_digits+=1 if nr_digits>2:raise ValueError('too many consecutive digits after '+ret_val) ret_val+=next_sep+str(x);next_sep=_B;continue first_letter=x[0].lower();next_sep='' if first_letter in'abcr': if post_dev:raise ValueError('release level specified after post/dev: '+x) nr_digits=0;ret_val+='rc'if first_letter=='r'else first_letter elif first_letter in'pd':nr_digits=1;post_dev=_D;ret_val+='.post'if first_letter=='p'else'.dev' else:raise ValueError('First letter of "'+x+'" not recognised') if nr_digits==1 and post_dev:ret_val+='0' return ret_val version_info=pkg_data['version_info'] version_str=_check_convert_version(version_info) class MyInstallLib(install_lib.install_lib): def install(self): fpp=pkg_data[_I].split(_B);full_exclude_files=[os.path.join(*fpp+[x])for x in exclude_files];alt_files=[];outfiles=install_lib.install_lib.install(self) for x in outfiles: for full_exclude_file in full_exclude_files: if full_exclude_file in x:os.remove(x);break else:alt_files.append(x) 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) 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_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) 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 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 else:Distribution.is_pure=lambda *args:_C for x in sys.argv: if x[0]=='-'or x==_F:continue self.command=x;break def pn(self,s): if sys.version_info<(3,)and isinstance(s,unicode):return s.encode(_E) return s @property def split(self): skip=[] if self._split is _A: fpn=self.full_package_name.split(_B);self._split=[] while fpn:self._split.insert(0,_B.join(fpn));fpn=fpn[:-1] for d in sorted(os.listdir(_B)): if not os.path.isdir(d)or d==self._split[0]or d[0]in'._':continue x=os.path.join(d,_H) if os.path.exists(x): pd=_package_data(x) if pd.get(_R,_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 return self._split @property def namespace_packages(self):return self.split[:self.depth] def namespace_directories(self,depth=_A): res=[] for (index,d) in enumerate(self.split[:depth]): if index>0:d=os.path.join(*d.split(_B)) res.append(_B+d) return res @property def package_dir(self): d={self.full_package_name:_B} if _T 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): directories=self.namespace_directories(self.depth) if not directories:return if not os.path.exists(directories[0]): for d in directories: os.mkdir(d) with open(os.path.join(d,_H),'w')as fp:fp.write('import pkg_resources\npkg_resources.declare_namespace(__name__)\n') def python_version(self): supported=self._pkg_data.get('supported') if supported is _A:return if len(supported)==1:minimum=supported[0] else: for x in supported: if x[0]==sys.version_info[0]:minimum=x;break else:return if sys.version_info>>>>> LICENSE file not found <<<<<\n\n') if self._pkg_data.get(_S):fp.write('[bdist_wheel]\nuniversal = 1\n') try:setup(**kw) except Exception:raise finally:os.remove(file_name) return _D def main(): A='tarfmt';dump_kw='--dump-kw' if dump_kw in sys.argv:import wheel,distutils,setuptools;print('python: ',sys.version);print('setuptools:',setuptools.__version__);print('distutils: ',distutils.__version__);print('wheel: ',wheel.__version__) 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 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): 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: with open('README.rst')as fp:kw['long_description']=fp.read();kw['long_description_content_type']='text/x-rst' except Exception:pass if nsp.wheel(kw,setup):return for x in ['-c','egg_info','--egg-base','pip-egg-info']: if x not in sys.argv:break else: for p in nsp.install_pre: import subprocess;setup_path=os.path.join(*p.split(_B)+[_F]);try_dir=os.path.dirname(sys.executable) while len(try_dir)>1: full_path_setup_py=os.path.join(try_dir,setup_path) if os.path.exists(full_path_setup_py):pip=sys.executable.replace(_G,'pip');cmd=[pip,_J,os.path.dirname(full_path_setup_py)];subprocess.check_output(cmd);break try_dir=os.path.dirname(try_dir) setup(**kw) main()././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807562.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/timestamp.py0000644000175000017500000000067300000000000024630 0ustar00rochacbrunorochacbrunofrom __future__ import print_function,absolute_import,division,unicode_literals _A=False import datetime,copy if _A: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 __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././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807562.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/tokens.py0000644000175000017500000000747300000000000024135 0ustar00rochacbrunorochacbrunofrom __future__ import unicode_literals _F=', line: ' _E='pre_done' _D=False _C='value' _B='_comment' _A=None if _D:from typing import Text,Any,Dict,Optional,List;from .error import StreamMark SHOWLINES=True class Token: __slots__='start_mark','end_mark',_B def __init__(A,start_mark,end_mark):A.start_mark=start_mark;A.end_mark=end_mark def __repr__(A): C=[B for B in A.__slots__ if not B.endswith('_mark')];C.sort();B=', '.join(['%s=%r'%(B,getattr(A,B))for B in C]) if SHOWLINES: try:B+=_F+str(A.start_mark.line) except:pass try:B+=', comment: '+str(A._comment) except:pass return '{}({})'.format(A.__class__.__name__,B) def add_post_comment(A,comment): if not hasattr(A,_B):A._comment=[_A,_A] A._comment[0]=comment def add_pre_comments(A,comments): if not hasattr(A,_B):A._comment=[_A,_A] assert A._comment[1]is _A;A._comment[1]=comments def get_comment(A):return getattr(A,_B,_A) @property def comment(self):return getattr(self,_B,_A) def move_comment(C,target,empty=_D): D=target;A=C.comment if A is _A:return if isinstance(D,(StreamEndToken,DocumentStartToken)):return delattr(C,_B);B=D.comment if not B: if empty:A=[A[0],A[1],_A,_A,A[0]] D._comment=A;return C if A[0]and B[0]or A[1]and B[1]:raise NotImplementedError('overlap in comment %r %r'%(A,B)) if A[0]:B[0]=A[0] if A[1]:B[1]=A[1] return C def split_comment(B): A=B.comment if A is _A or A[0]is _A:return _A C=[A[0],_A] if A[1]is _A:delattr(B,_B) return C class DirectiveToken(Token): __slots__='name',_C;id='' def __init__(A,name,value,start_mark,end_mark):Token.__init__(A,start_mark,end_mark);A.name=name;A.value=value class DocumentStartToken(Token):__slots__=();id='' class DocumentEndToken(Token):__slots__=();id='' class StreamStartToken(Token): __slots__='encoding',;id='' def __init__(A,start_mark=_A,end_mark=_A,encoding=_A):Token.__init__(A,start_mark,end_mark);A.encoding=encoding class StreamEndToken(Token):__slots__=();id='' class BlockSequenceStartToken(Token):__slots__=();id='' class BlockMappingStartToken(Token):__slots__=();id='' class BlockEndToken(Token):__slots__=();id='' class FlowSequenceStartToken(Token):__slots__=();id='[' class FlowMappingStartToken(Token):__slots__=();id='{' class FlowSequenceEndToken(Token):__slots__=();id=']' class FlowMappingEndToken(Token):__slots__=();id='}' class KeyToken(Token):__slots__=();id='?' class ValueToken(Token):__slots__=();id=':' class BlockEntryToken(Token):__slots__=();id='-' class FlowEntryToken(Token):__slots__=();id=',' class AliasToken(Token): __slots__=_C,;id='' def __init__(A,value,start_mark,end_mark):Token.__init__(A,start_mark,end_mark);A.value=value class AnchorToken(Token): __slots__=_C,;id='' def __init__(A,value,start_mark,end_mark):Token.__init__(A,start_mark,end_mark);A.value=value class TagToken(Token): __slots__=_C,;id='' def __init__(A,value,start_mark,end_mark):Token.__init__(A,start_mark,end_mark);A.value=value class ScalarToken(Token): __slots__=_C,'plain','style';id='' def __init__(A,value,plain,start_mark,end_mark,style=_A):Token.__init__(A,start_mark,end_mark);A.value=value;A.plain=plain;A.style=style class CommentToken(Token): __slots__=_C,_E;id='' def __init__(A,value,start_mark,end_mark):Token.__init__(A,start_mark,end_mark);A.value=value def reset(A): if hasattr(A,_E):delattr(A,_E) def __repr__(A): B='{!r}'.format(A.value) if SHOWLINES: try:B+=_F+str(A.start_mark.line);B+=', col: '+str(A.start_mark.column) except:pass return 'CommentToken({})'.format(B) def __eq__(A,other): B=other if A.start_mark!=B.start_mark:return _D if A.end_mark!=B.end_mark:return _D if A.value!=B.value:return _D return True def __ne__(A,other):return not A.__eq__(other)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807562.0 dynaconf-3.1.7/dynaconf/vendor/ruamel/yaml/util.py0000644000175000017500000000402300000000000023573 0ustar00rochacbrunorochacbrunofrom __future__ import absolute_import,print_function _B='lazy_self' _A=' ' 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 __getattribute__(B,name): A=object.__getattribute__(B,_B) if name==_B:return A return getattr(A(),name) def __setattr__(A,name,value):setattr(A.lazy_self(),name,value) RegExp=partial(LazyEval,re.compile) 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 AE:G=A-E if J.endswith(':'): I=K(C);A=0 while C[A]==_A:A+=1 E=A;continue E=B if H is B and G is not B:H=G return O(F,**N),H,L def configobj_walker(cfg): B=cfg;from configobj import ConfigObj as D;assert isinstance(B,D) for A in B.initial_comment: if A.strip():yield A for C in _walk_section(B): if C.strip():yield C 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 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 E='{0}{1}: {2}'.format(D,A,C);B=s.inline_comments[A] if B:E+=_A+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 yield E for K in _walk_section(s[A],level=F+1):yield K././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1631217935.1303446 dynaconf-3.1.7/dynaconf/vendor/toml/0000755000175000017500000000000000000000000020771 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807563.0 dynaconf-3.1.7/dynaconf/vendor/toml/__init__.py0000644000175000017500000000111200000000000023075 0ustar00rochacbrunorochacbrunofrom . import encoder,decoder __version__='0.10.1' _spec_='0.5.0' load=decoder.load loads=decoder.loads TomlDecoder=decoder.TomlDecoder TomlDecodeError=decoder.TomlDecodeError TomlPreserveCommentDecoder=decoder.TomlPreserveCommentDecoder dump=encoder.dump dumps=encoder.dumps TomlEncoder=encoder.TomlEncoder TomlArraySeparatorEncoder=encoder.TomlArraySeparatorEncoder TomlPreserveInlineDictEncoder=encoder.TomlPreserveInlineDictEncoder TomlNumpyEncoder=encoder.TomlNumpyEncoder TomlPreserveCommentEncoder=encoder.TomlPreserveCommentEncoder TomlPathlibEncoder=encoder.TomlPathlibEncoder././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807562.0 dynaconf-3.1.7/dynaconf/vendor/toml/decoder.py0000644000175000017500000004005500000000000022754 0ustar00rochacbrunorochacbruno_W='Reserved escape sequence used' _V='\\U' _U='false' _T='true' _S='\t' _R='}' _Q='+' _P='_' _O='-' _N=',' _M=']' _L=' ' _K='{' _J='=' _I='[' _H='\\' _G='\n' _F='.' _E=None _D="'" _C='"' _B=True _A=False import datetime,io from os import linesep import re,sys from .tz import TomlTz if sys.version_info<(3,):_range=xrange else:unicode=str;_range=range;basestring=str;unichr=chr def _detect_pathlib_path(p): if(3,4)<=sys.version_info: import pathlib as A if isinstance(p,A.PurePath):return _B return _A def _ispath(p): if isinstance(p,(bytes,basestring)):return _B return _detect_pathlib_path(p) def _getpath(p): if(3,6)<=sys.version_info:import os;return os.fspath(p) if _detect_pathlib_path(p):return str(p) return p try:FNFError=FileNotFoundError except NameError:FNFError=IOError TIME_RE=re.compile('([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.([0-9]{3,6}))?') class TomlDecodeError(ValueError): def __init__(A,msg,doc,pos):C=doc;B=pos;D=C.count(_G,0,B)+1;E=B-C.rfind(_G,0,B);F='{} (line {} column {} char {})'.format(msg,D,E,B);ValueError.__init__(A,F);A.msg=msg;A.doc=C;A.pos=B;A.lineno=D;A.colno=E _number_with_underscores=re.compile('([0-9])(_([0-9]))*') class CommentValue: def __init__(A,val,comment,beginline,_dict):A.val=val;B=_G if beginline else _L;A.comment=B+comment;A._dict=_dict def __getitem__(A,key):return A.val[key] def __setitem__(A,key,value):A.val[key]=value def dump(A,dump_value_func): B=dump_value_func(A.val) if isinstance(A.val,A._dict):return A.comment+_G+unicode(B) else:return unicode(B)+A.comment 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'_.'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: n=n[1:] if len(n)>1 and n[0]=='0'and n[1]!=_F:return _A if'__'in n:return _A return _B def load(f,_dict=dict,decoder=_E): B=_dict;A=decoder if _ispath(f): with io.open(_getpath(f),encoding='utf-8')as G:return loads(G.read(),B,A) elif isinstance(f,list): from os import path as D;from warnings import warn if not[A for A in f if D.exists(A)]:C='Load expects a list to contain filenames only.';C+=linesep;C+='The list needs to contain the path of at least one existing file.';raise FNFError(C) if A is _E:A=TomlDecoder(B) E=A.get_empty_table() for F in f: if D.exists(F):E.update(load(F,B,A)) else:warn('Non-existent filename in list with at least one valid filename') return E else: try:return loads(f.read(),B,A) 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=[] 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') if not isinstance(s,unicode):s=s.decode('utf8') I=s;B=list(s);b=0;J=_A;Q='';D=_A;L=_A;V=_B;U=_A;W=_A;O=0;c='';j='';k=1 for (A,E) in enumerate(B): if E=='\r'and B[A+1]==_G:B[A]=_L;continue if O: c+=E if E==_G:raise TomlDecodeError('Key name found without value. Reached end of line.',I,A) if J: if E==Q: S=_A;F=1 while A>=F and B[A-F]==_H:S=not S;F+=1 if not S:O=2;J=_A;Q='' continue 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 W and B[A-1]==_F and(E==_C or E==_D):J=_B;Q=E;continue elif O==2: if E.isspace(): if W: X=B[A+1] if not X.isspace()and X!=_F:O=1 continue if E==_F: W=_B;X=B[A+1] if not X.isspace()and X!=_F:O=1 continue if E==_J:O=0;j=c[:-1].rstrip();c='';W=_A else:raise TomlDecodeError("Found invalid character in key name: '"+E+"'. Try quoting the key name.",I,A) if E==_D and Q!=_C: F=1 try: while B[A-F]==_D: F+=1 if F==3:break except IndexError:pass if F==3:D=not D;J=D else:J=not J if J:Q=_D else:Q='' if E==_C and Q!=_D: S=_A;F=1;f=_A try: while B[A-F]==_C: F+=1 if F==3:f=_B;break if F==1 or F==3 and f: while B[A-F]==_H:S=not S;F+=1 except IndexError:pass if not S: if f:D=not D;J=D else:J=not J if J:Q=_C else:Q='' if E=='#'and(not J and not U and not L): R=A;l='' try: while B[R]!=_G:l+=s[R];B[R]=_L;R+=1 except IndexError:break if not b:K.preserve_comment(k,j,l,V) if E==_I and(not J and not U and not L): if V: if len(B)>A+1 and B[A+1]==_I:L=_B else:U=_B else:b+=1 if E==_M and not J: if U:U=_A elif L: if B[A-1]==_M:L=_A else:b-=1 if E==_G: if J or D: if not D:raise TomlDecodeError('Unbalanced quotes',I,A) if(B[A-1]==_D or B[A-1]==_C)and B[A-2]==B[A-1]: B[A]=B[A-1] if B[A-3]==B[A-1]:B[A-3]=_L elif b:B[A]=_L else:V=_B k+=1 elif V and B[A]!=_L and B[A]!=_S: V=_A if not U and not L: if B[A]==_J:raise TomlDecodeError('Found empty keyname. ',I,A) O=1;c+=E if O:raise TomlDecodeError('Key name found without value. Reached end of file.',I,len(s)) if J:raise TomlDecodeError('Unterminated string found. Reached end of file.',I,len(s)) s=''.join(B);s=s.split(_G);T=_E;D='';P=_A;N=0 for (g,C) in enumerate(s): if g>0:N+=len(s[g-1])+1 K.embed_comments(g,G) if not D or P or _G not in D:C=C.strip() if C==''and(not T or P):continue if T: if P:D+=C else:D+=C P=_A;h=_A 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) except ValueError as Y:raise TomlDecodeError(str(Y),I,N) G[T]=o;T=_E;D='' else: F=len(D)-1 while F>-1 and D[F]==_H:P=not P;F-=1 if P:D=D[:-1] else:D+=_G continue if C[0]==_I: L=_A 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: if not i and Z in m:break A+=m.count(Z);i=not i C=C.split(Z,A) if len(C)0 and(H[A][0]==_C or H[A][0]==_D): 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) 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) A+=1 G=e for A in _range(len(H)): M=H[A] if M=='':raise TomlDecodeError("Can't have a keygroup with an empty name",I,N) try: G[M] if A==len(H)-1: if M in d: d.remove(M) if L:raise TomlDecodeError("An implicitly defined table can't be an array",I,N) elif L:G[M].append(K.get_empty_table()) else:raise TomlDecodeError('What? '+M+' already exists?'+str(G),I,N) except TypeError: G=G[-1] if M not in G: G[M]=K.get_empty_table() if A==len(H)-1 and L:G[M]=[K.get_empty_table()] except KeyError: if A!=len(H)-1:d.append(M) G[M]=K.get_empty_table() if A==len(H)-1 and L:G[M]=[K.get_empty_table()] G=G[M] if L: 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) try:K.load_inline_object(C,G,T,P) except ValueError as Y:raise TomlDecodeError(str(Y),I,N) elif _J in C: try:n=K.load_line(C,G,T,P) except ValueError as Y:raise TomlDecodeError(str(Y),I,N) if n is not _E:T,D,P=n return e def _load_date(val): I='Z';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 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:] 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 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) except ValueError:return _E return H def _load_unicode_escapes(v,hexbytes,prefix): G='Invalid escape sequence: ';E=prefix;C=_A;A=len(v)-1 while A>-1 and v[A]==_H:C=not C;A-=1 for D in hexbytes: if C: C=_A;A=len(D)-1 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 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] _escape_to_escapedchars=dict(zip(_escapes,_escapedchars)) def _unescape(v): A=0;B=_A while A0: C=B.pop(0) 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) elif len(B)>0:B[0]=C+_N+B[0] else:raise ValueError('Invalid inline table value encountered') for F in D: G=E.load_line(F,currentlevel,multikey,multibackslash) if G is not _E:break def _get_split_on_quotes(F,line): A=line.split(_C);D=_A;C=[] if len(A)>1 and _D in A[0]: B=A[0].split(_D);A=A[1:] while len(B)%2==0 and len(A): B[-1]+=_C+A[0];A=A[1:] if _D in B[-1]:B=B[:-1]+B[-1].split(_D) C+=B for E in A: if D:C.append(E) 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 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): 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') if N:N=_strictly_valid_num(A[-1]) A=[_J.join(A[:-1]).strip(),A[-1].strip()] if _F in A[0]: if _C in A[0]or _D in A[0]: M=E._get_split_on_quotes(A[0]);C=_A;B=[] for F in M: if C:B.append(F) else:B+=[A.strip()for A in F.split(_F)] C=not C else:B=A[0].split(_F) while B[-1]=='':B=B[:-1] for I in B[:-1]: if I=='':continue if I not in D:D[I]=E.get_empty_table() 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]) if J>-1: while J>-1 and A[1][J+Q]==_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) except KeyError: if L:return L,O,G else:D[A[0]]=R def _load_line_multiline_str(C,p): B=0 if len(p)<3:return-1,B if p[0]==_I and(p.strip()[-1]!=_M and C._load_array_isstrarray(p)): A=p[1:].strip().split(_N) while len(A)>1 and A[-1][0]!=_C and A[-1][0]!=_D:A=A[:-2]+[A[-2]+_N+A[-1]] A=A[-1];B=len(p)-len(A);p=A if p[0]!=_C and p[0]!=_D:return-1,B if p[1]!=p[0]or p[2]!=p[0]:return-1,B 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' if not v:raise ValueError('Empty value is invalid') if v==_T:return _B,Y elif v==_U:return _A,Y 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 I=_A for J in B: if J=='': if G:H+=1 else:I=_B else: K=_A try: A=-1;N=J[A] while N==_H:K=not K;A-=1;N=J[A] except IndexError:pass if not K: if I:raise ValueError('Found tokens after a closed '+'string. Invalid TOML.') 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: 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 C:C=_A for L in ['\\u',_V]: 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' 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() 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) if S:return 0-v,D return v,D def bounded_string(C,s): if len(s)==0:return _B if s[-1]!=s[0]:return _A A=-2;B=_A while len(s)+A>0: if s[A]==_H:B=not B;A-=1 else:break return not B def _load_array_isstrarray(A,a): a=a[1:-1].strip() if a!=''and(a[0]==_C or a[0]==_D):return _B return _A def load_array(H,a): I=_E;N=[];a=a.strip() if _I not in a[1:-1]or''!=a[1:-1].split(_I)[0].strip(): Q=H._load_array_isstrarray(a) if not a[1:-1].strip().startswith(_K):a=a[1:-1].split(_N) else: O=[];E=1;A=2;J=1 if a[E]==_K else 0;F=_A while A-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 A+=1;O.append(a[E:A]);E=A+1 while E2 and C[0]==C[1]==C[2]and C[-2]!=C[0]and C[-3]!=C[0]: a[B]=a[B]+_N+a[B+1];C=a[B].strip() if B=(3,):unicode=str def dump(o,f,encoder=_A): if not f.write:raise TypeError('You can only dump an object to a file descriptor') A=dumps(o,encoder=encoder);f.write(A);return A def dumps(o,encoder=_A): C=encoder;A='' if C is _A:C=TomlEncoder(o.__class__) B,D=C.dump_sections(o,'');A+=B;G=[id(o)] while D: H=[id(A)for A in D] for K in G: if K in H:raise ValueError('Circular reference detected') G+=H;I=C.get_empty_table() 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 B:A+=B for J in F:I[E+_B+J]=F[J] D=I return A def _dump_str(v): G="'";F='\\';C='"' 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,'\\"') 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) 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 get_empty_table(A):return A._dict() def dump_list(B,v): A=_C 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) C+='{ '+', '.join(D)+' }\n';return C else:return unicode(B.dump_value(A)) def dump_value(B,v): A=B.dump_funcs.get(type(v)) if A is _A and hasattr(v,'__iter__'):A=B.dump_funcs[list] 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 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 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) if I: if I[0]==_C: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] 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]) 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=','): 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 for A in v:B.append(D.dump_value(A)) while B!=[]: E=[] for A in B: if isinstance(A,list): for F in A:E.append(F) else:C+=' '+unicode(A)+D.separator 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 _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) class TomlPathlibEncoder(TomlEncoder): def _dump_pathlib_path(A,v):return _dump_str(str(v)) def dump_value(A,v): if(3,4)<=sys.version_info: import pathlib as B if isinstance(v,B.PurePath):v=str(v) return super(TomlPathlibEncoder,A).dump_value(v)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807563.0 dynaconf-3.1.7/dynaconf/vendor/toml/ordered.py0000644000175000017500000000045300000000000022771 0ustar00rochacbrunorochacbrunofrom collections import OrderedDict from . import TomlEncoder from . import TomlDecoder class TomlOrderedDecoder(TomlDecoder): def __init__(A):super(A.__class__,A).__init__(_dict=OrderedDict) class TomlOrderedEncoder(TomlEncoder): def __init__(A):super(A.__class__,A).__init__(_dict=OrderedDict)././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1629807563.0 dynaconf-3.1.7/dynaconf/vendor/toml/tz.py0000644000175000017500000000066300000000000022005 0ustar00rochacbrunorochacbrunofrom datetime import tzinfo,timedelta class TomlTz(tzinfo): def __init__(A,toml_offset): B=toml_offset if B=='Z':A._raw_offset='+00:00' else:A._raw_offset=B A._sign=-1 if A._raw_offset[0]=='-'else 1;A._hours=int(A._raw_offset[1:3]);A._minutes=int(A._raw_offset[4:6]) def tzname(A,dt):return'UTC'+A._raw_offset def utcoffset(A,dt):return A._sign*timedelta(hours=A._hours,minutes=A._minutes) def dst(A,dt):return timedelta(0)././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1631217935.113678 dynaconf-3.1.7/dynaconf.egg-info/0000755000175000017500000000000000000000000020213 5ustar00rochacbrunorochacbruno././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631217934.0 dynaconf-3.1.7/dynaconf.egg-info/PKG-INFO0000644000175000017500000001661000000000000021314 0ustar00rochacbrunorochacbrunoMetadata-Version: 2.1 Name: dynaconf Version: 3.1.7 Summary: The dynamic configurator for your Python Project Home-page: https://github.com/rochacbruno/dynaconf Author: Bruno Rocha Author-email: rochacbruno@gmail.com License: MIT Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Framework :: Django Classifier: Framework :: Flask Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English 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: Topic :: Utilities Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.7 Description-Content-Type: text/markdown Provides-Extra: redis Provides-Extra: vault Provides-Extra: yaml Provides-Extra: toml Provides-Extra: ini Provides-Extra: configobj Provides-Extra: all License-File: LICENSE [![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&utm_medium=referral&utm_content=rochacbruno/dynaconf&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) [![Foo](https://xscode.com/assets/promo-banner.svg)](https://xscode.com/rochacbruno/dynaconf) ## Features - Inspired by the [12-factor application guide](https://12factor.net/config) - Settings management (default values, validation, parsing, templating) - Protection of sensitive information (passwords/tokens) - Multiple file formats `toml|yaml|json|ini|py` and also customizable loaders. - Full support for environment variables to override existing settings (dotenv support included). - Optional layered system for multi environments `[default, development, testing, production]` - Built-in support for Hashicorp Vault and Redis as settings and secrets storage. - Built-in extensions for **Django** and **Flask** web frameworks. - 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 $ pip install dynaconf ``` #### Initialize Dynaconf on project root directory ```plain $ cd path/to/your/project/ $ dynaconf init -f toml ⚙️ Configuring your Dynaconf environment ------------------------------------------ 🐍 The file `config.py` was generated. 🎛️ settings.toml created to hold your settings. 🔑 .secrets.toml created to hold your secrets. 🙈 the .secrets.* is also included in `.gitignore` beware to not push your secrets to a public repo. 🎉 Dynaconf is configured! read more on https://dynaconf.com ``` > **TIP:** You can select `toml|yaml|json|ini|py` on `dynaconf init -f ` **toml** is the default and also the most recommended format for configuration. #### Dynaconf init creates the following files ```plain . ├── 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) ``` On the file `config.py` Dynaconf init generates the following boilerpate ```py from dynaconf import Dynaconf settings = Dynaconf( envvar_prefix="DYNACONF", # export envvars with `export DYNACONF_FOO=bar`. settings_files=['settings.yaml', '.secrets.yaml'], # Load files in the given order. ) ``` > **TIP:** You can create the files yourself instead of using the `init` command as shown above and you can give any name you want instead of the default `config.py` (the file must be in your importable python path) - See more options that you can pass to `Dynaconf` class initializer on https://dynaconf.com #### Using Dynaconf Put your settings on `settings.{toml|yaml|ini|json|py}` ```toml username = "admin" port = 5555 database = {name='mydb', schema='main'} ``` Put sensitive information on `.secrets.{toml|yaml|ini|json|py}` ```toml password = "secret123" ``` > **IMPORTANT:** `dynaconf init` command puts the `.secrets.*` in your `.gitignore` to avoid it to be exposed on public repos but it is your responsibility to keep it safe in your local environment, also the recommendation for production environments is to use the built-in support for Hashicorp Vault service for password and tokens. Optionally you can now use environment variables to override values per execution or per environment. ```bash # override `port` from settings.toml file and automatically casts as `int` value. export DYNACONF_PORT=9900 ``` On your code import the `settings` object ```py from path.to.project.config import settings # Reading the settings settings.username == "admin" # dot notation with multi nesting support settings.PORT == 9900 # case insensitive settings['password'] == "secret123" # dict like access settings.get("nonexisting", "default value") # Default values just like a dict settings.databases.name == "mydb" # Nested key traversing settings['databases.schema'] == "main" # Nested key traversing ``` ## More - Settings Schema Validation - Custom Settings Loaders - Vault Services - Template substitutions - etc... 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) ## more If you are looking for something similar to Dynaconf to use in your Rust projects: https://github.com/rubik/hydroconf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631217935.0 dynaconf-3.1.7/dynaconf.egg-info/SOURCES.txt0000644000175000017500000000677300000000000022114 0ustar00rochacbrunorochacbruno3.x-release-notes.md CHANGELOG.md CONTRIBUTING.md LICENSE MANIFEST.in README.md setup.cfg setup.py dynaconf/VERSION dynaconf/__init__.py dynaconf/base.py dynaconf/cli.py dynaconf/constants.py dynaconf/default_settings.py dynaconf/test_settings.py dynaconf/validator.py dynaconf/validator_conditions.py dynaconf.egg-info/PKG-INFO dynaconf.egg-info/SOURCES.txt dynaconf.egg-info/dependency_links.txt dynaconf.egg-info/entry_points.txt dynaconf.egg-info/not-zip-safe dynaconf.egg-info/requires.txt dynaconf.egg-info/top_level.txt dynaconf/contrib/__init__.py dynaconf/contrib/django_dynaconf_v2.py dynaconf/contrib/flask_dynaconf.py dynaconf/loaders/__init__.py dynaconf/loaders/base.py dynaconf/loaders/env_loader.py dynaconf/loaders/ini_loader.py dynaconf/loaders/json_loader.py dynaconf/loaders/py_loader.py dynaconf/loaders/redis_loader.py dynaconf/loaders/toml_loader.py dynaconf/loaders/vault_loader.py dynaconf/loaders/yaml_loader.py dynaconf/strategies/__init__.py dynaconf/strategies/filtering.py dynaconf/utils/__init__.py dynaconf/utils/boxing.py dynaconf/utils/files.py dynaconf/utils/functional.py dynaconf/utils/parse_conf.py dynaconf/vendor/__init__.py dynaconf/vendor/box/__init__.py dynaconf/vendor/box/box.py dynaconf/vendor/box/box_list.py dynaconf/vendor/box/config_box.py dynaconf/vendor/box/converters.py dynaconf/vendor/box/exceptions.py dynaconf/vendor/box/from_file.py dynaconf/vendor/box/shorthand_box.py dynaconf/vendor/click/__init__.py dynaconf/vendor/click/_bashcomplete.py dynaconf/vendor/click/_compat.py dynaconf/vendor/click/_termui_impl.py dynaconf/vendor/click/_textwrap.py dynaconf/vendor/click/_unicodefun.py dynaconf/vendor/click/_winconsole.py dynaconf/vendor/click/core.py dynaconf/vendor/click/decorators.py dynaconf/vendor/click/exceptions.py dynaconf/vendor/click/formatting.py dynaconf/vendor/click/globals.py dynaconf/vendor/click/parser.py dynaconf/vendor/click/termui.py dynaconf/vendor/click/testing.py dynaconf/vendor/click/types.py dynaconf/vendor/click/utils.py dynaconf/vendor/dotenv/__init__.py dynaconf/vendor/dotenv/cli.py dynaconf/vendor/dotenv/compat.py dynaconf/vendor/dotenv/ipython.py dynaconf/vendor/dotenv/main.py dynaconf/vendor/dotenv/parser.py dynaconf/vendor/dotenv/version.py dynaconf/vendor/ruamel/__init__.py dynaconf/vendor/ruamel/yaml/__init__.py dynaconf/vendor/ruamel/yaml/anchor.py dynaconf/vendor/ruamel/yaml/comments.py dynaconf/vendor/ruamel/yaml/compat.py dynaconf/vendor/ruamel/yaml/composer.py dynaconf/vendor/ruamel/yaml/configobjwalker.py dynaconf/vendor/ruamel/yaml/constructor.py dynaconf/vendor/ruamel/yaml/cyaml.py dynaconf/vendor/ruamel/yaml/dumper.py dynaconf/vendor/ruamel/yaml/emitter.py dynaconf/vendor/ruamel/yaml/error.py dynaconf/vendor/ruamel/yaml/events.py dynaconf/vendor/ruamel/yaml/loader.py dynaconf/vendor/ruamel/yaml/main.py dynaconf/vendor/ruamel/yaml/nodes.py dynaconf/vendor/ruamel/yaml/parser.py dynaconf/vendor/ruamel/yaml/reader.py dynaconf/vendor/ruamel/yaml/representer.py dynaconf/vendor/ruamel/yaml/resolver.py dynaconf/vendor/ruamel/yaml/scalarbool.py dynaconf/vendor/ruamel/yaml/scalarfloat.py dynaconf/vendor/ruamel/yaml/scalarint.py dynaconf/vendor/ruamel/yaml/scalarstring.py dynaconf/vendor/ruamel/yaml/scanner.py dynaconf/vendor/ruamel/yaml/serializer.py dynaconf/vendor/ruamel/yaml/setup.py dynaconf/vendor/ruamel/yaml/timestamp.py dynaconf/vendor/ruamel/yaml/tokens.py dynaconf/vendor/ruamel/yaml/util.py 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././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631217934.0 dynaconf-3.1.7/dynaconf.egg-info/dependency_links.txt0000644000175000017500000000000100000000000024261 0ustar00rochacbrunorochacbruno ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631217934.0 dynaconf-3.1.7/dynaconf.egg-info/entry_points.txt0000644000175000017500000000006000000000000023505 0ustar00rochacbrunorochacbruno[console_scripts] dynaconf = dynaconf.cli:main ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631217934.0 dynaconf-3.1.7/dynaconf.egg-info/not-zip-safe0000644000175000017500000000000100000000000022441 0ustar00rochacbrunorochacbruno ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631217934.0 dynaconf-3.1.7/dynaconf.egg-info/requires.txt0000644000175000017500000000026000000000000022611 0ustar00rochacbrunorochacbruno [:python_version < "3.5"] typing [all] redis ruamel.yaml configobj hvac [configobj] configobj [ini] configobj [redis] redis [toml] toml [vault] hvac [yaml] ruamel.yaml ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631217934.0 dynaconf-3.1.7/dynaconf.egg-info/top_level.txt0000644000175000017500000000001100000000000022735 0ustar00rochacbrunorochacbrunodynaconf ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1631217935.1303446 dynaconf-3.1.7/setup.cfg0000644000175000017500000000052600000000000016544 0ustar00rochacbrunorochacbruno[bdist_wheel] universal = 1 [mypy] ignore_missing_imports = True [mypy-*.vendor.*] ignore_errors = True [mypy-tests.*] ignore_errors = True [mypy-example.*] ignore_errors = True [mypy-*.contrib.*] ignore_errors = True [mypy-*.utils.*] ignore_errors = True [mypy-*.loaders.*] ignore_errors = True [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1631217908.0 dynaconf-3.1.7/setup.py0000644000175000017500000000535400000000000016441 0ustar00rochacbrunorochacbrunoimport io import os import sys from setuptools import find_packages from setuptools import setup def read(*names, **kwargs): """Read a file.""" content = "" with io.open( os.path.join(os.path.dirname(__file__), *names), encoding=kwargs.get("encoding", "utf8"), ) as open_file: content = open_file.read().strip() return content setup( name="dynaconf", version=read("dynaconf", "VERSION"), url="https://github.com/rochacbruno/dynaconf", license="MIT", author="Bruno Rocha", author_email="rochacbruno@gmail.com", description="The dynamic configurator for your Python Project", long_description=read("README.md"), long_description_content_type="text/markdown", packages=find_packages( exclude=[ "tests", "tests.*", "example", "example.*", "docs", "legacy_docs", "legacy_docs.*", "docs.*", "build", "build.*", "dynaconf.vendor_src", "dynaconf/vendor_src", "dynaconf.vendor_src.*", "dynaconf/vendor_src/*", ] ), 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", ], extras_require={ "redis": ["redis"], "vault": ["hvac"], "yaml": ["ruamel.yaml"], "toml": ["toml"], "ini": ["configobj"], "configobj": ["configobj"], "all": ["redis", "ruamel.yaml", "configobj", "hvac"], }, python_requires=">=3.7", entry_points={"console_scripts": ["dynaconf=dynaconf.cli:main"]}, setup_requires=["setuptools>=38.6.0"], classifiers=[ "Development Status :: 5 - Production/Stable", "Framework :: Django", "Framework :: Flask", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "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", "Topic :: Utilities", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", ], )