Skip to content

Feature - Inspect and CLI#939

Merged
pedro-psb merged 29 commits intodynaconf:masterfrom
pedro-psb:feature/inspect
Jun 14, 2023
Merged

Feature - Inspect and CLI#939
pedro-psb merged 29 commits intodynaconf:masterfrom
pedro-psb:feature/inspect

Conversation

@pedro-psb
Copy link
Copy Markdown
Member

@pedro-psb pedro-psb commented May 26, 2023

Inspect functionality (related to #837).
The goal is to provide a way for the users to visualize the "loading-history" of any config key-path.

Changes

  • Replace Settings._loaded_by_loaders key type from str to SourceMetadata<NamedTuple> to store more data about each load, namely:
    • loader: the loader type (envvar_global, yaml, redis, vault..)
    • identifier: a loader identifier (eg, for file types it is the filename), for other it may be unique.
    • env: the env in which the data was loaded
    • merged: if the data was processed with some merge operation.
  • Replace old loader_identifier format (str) with the new one (SourceMetadata) in most data-loading processes (calls to set).
  • Implement inspecting utilities: inspect_setting (dumping) and get_history (direct access to python data).
  • Implement new CLI command inspect, which basically ports inspect_settings to CLI.

Tasks

  • compatibility decision: old loaded_by_loaders (dict[str, dict]) won't be kept, unless someone requests
  • preliminary tests/implementation of inspect:
  • refine inspect output:
    • parametrize output stream (eg, stdout or regular file)
    • transform DynaBox and BoxList into regular dict|list (for pretty-dumping)
    • parametrize output format/dumper (yaml, toml, python, etc)
  • Instance tests:
    • get_history (cover mixing of envvar, file, validators and merges)
    • inspect_settings
    • integration tests (redis/vault).
  • CLI
    • define it's usage/interface.
    • implement and test (just basic usability, behaviour is covered in instance tests).
    • fix test isolation and tmp_files setup (works running individually but not running the suite)
    • handle errors properly
  • Write docs (inspect_settings and CLI)
  • Test coverage misses

Related ideas:

  • star out secrets (vault, .secrets, any other?)
  • inspect_settings env filter will always include values from default env in active_value. It would be better to filter those out from active_value too.
  • file ovewrite safe-check (disable overwrite by accident): for inspect_settings (overwrite flag param)
  • Report .env specific file identifier (it is loaded as env_global).

Sample output

header:
  filters:
    env: None
    key: foo
    history_ordering: ascending
  active_value: from_environ
history:
- loader: yaml
  identifier: /tmp/pytest-of-pedro-psb/pytest-84/test_inspect_print_key0/a.yaml
  env: default
  merged: false
  value:
    FOO: from_yaml
- loader: env_global
  identifier: unique
  env: global
  merged: false
  value:
    FOO: from_environ
    BAR: environ_only

CLI usage

#939 (comment)

Obs

  • The new SourceMetadata should use more memory than the previous one, because it stores all data from all sources. It may be worth taking a look into that.
  • get_history: envs that are no built-in names (default, development, global) won't be loaded if it is not the current env. Eg, a value from env production won't show in history unless production is the current env or is activated (with settings.from_env or similar). This is because of how env loading works.

Testing

Current tests:

pytest tests/test_inspect.py -svk [testname]
pytest tests/test_cli.py -svk [testname]

@netlify
Copy link
Copy Markdown

netlify bot commented May 26, 2023

Deploy Preview for dynaconf ready!

Name Link
🔨 Latest commit 5d073e2
🔍 Latest deploy log https://app.netlify.com/sites/dynaconf/deploys/6489f1e633d4d0000835e456
😎 Deploy Preview https://deploy-preview-939--dynaconf.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 29, 2023

Codecov Report

Merging #939 (5d073e2) into master (ab71181) will decrease coverage by 0.10%.
The diff coverage is 99.37%.

❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more.

@@            Coverage Diff             @@
##           master     #939      +/-   ##
==========================================
- Coverage   99.89%   99.79%   -0.10%     
==========================================
  Files          21       22       +1     
  Lines        1844     1976     +132     
==========================================
+ Hits         1842     1972     +130     
- Misses          2        4       +2     
Impacted Files Coverage Δ
dynaconf/validator.py 99.49% <83.33%> (-0.51%) ⬇️
dynaconf/__init__.py 100.00% <100.00%> (ø)
dynaconf/base.py 99.80% <100.00%> (-0.20%) ⬇️
dynaconf/cli.py 99.28% <100.00%> (+0.04%) ⬆️
dynaconf/loaders/base.py 100.00% <100.00%> (ø)
dynaconf/loaders/env_loader.py 100.00% <100.00%> (ø)
dynaconf/loaders/py_loader.py 100.00% <100.00%> (ø)
dynaconf/loaders/yaml_loader.py 100.00% <100.00%> (ø)
dynaconf/utils/inspect.py 100.00% <100.00%> (ø)

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@rochacbruno
Copy link
Copy Markdown
Member

Dynaconf inspect CLI sub-command takes a key name (or dotted path) and outputs,
we have to keep it in conformity with existing CLI commands such as list so the options you listed are right.

$ dynaconf inspect --help
Usage: dynaconf inspect [OPTIONS]

Inspect the current value and loading history for settings.

Options:
    -k, --key TEXT            Filters a single key
    -e, --env string          filter by environement. Eg: development
    -f, --format string       output format: json, yaml, table (default: table)
                              "table": prints the output to stdout     
    --help                    Show this message and exit.
$ dynaconf inspect -k foo -f json
{
    "current": ...,
    "history": ...,
}

To save a file users can pipe the results or redirect stdout

dynaconf inspect -k foo -f json | jq
dynaconf inspect -k foo -f json > file.json

If -k is omitted then it dumps all defined keys, this would be useful to grep for filenames.


Programmatically the inspect function can take key as optional, if not passed it may dump all the keys.

Also we must rename inspect to avoid conflict with python inspect module.

import inspect

So it is better to rename

from dynaconf.utils import inspect_settings

data = inspect_settings(settings)  # a full dict with all keys included
foo_data = inspect_settings(settings, "foo")  # a full dict with only "foo" history

@pedro-psb
Copy link
Copy Markdown
Member Author

@rochacbruno what does the "table" format means exactly? Could you provide a snippet of how the following should be rendered?

header:
  filters:
    env: None
    key: foo
    history_ordering: ascending
  active_value: from_environ
history:
- loader: yaml
  identifier: /tmp/pytest-of-pedro-psb/pytest-84/test_inspect_print_key0/a.yaml
  env: default
  merged: false
  value:
    FOO: from_yaml

@rochacbruno
Copy link
Copy Markdown
Member

Hey @pedro-psb it is just a printed output that can be read in the terminal, in future we can use rich.Table but for now it is enough to just print data, so I think you can just by default output the YAML format directly to the stdout.

@rochacbruno
Copy link
Copy Markdown
Member

On list subcommand we are not doing any special treatment on secrets, that is understood that the person running this CLI has full access to the settings environment so we can output secrets or maybe if possible add an option like --hide-secrets to replace with *****

I am not sure it is easy to detect if a variable is a secret, maybe we can by detecting the source being .secrets. or vault.

@pedro-psb
Copy link
Copy Markdown
Member Author

I guess it would be good to star them out, as someone may want to share this report or something. Not very likely, but this should be easy to do by tracking .secrets or vault loader source.

@pedro-psb pedro-psb marked this pull request as ready for review June 12, 2023 18:27
@pedro-psb pedro-psb requested a review from rochacbruno June 12, 2023 18:29
@rochacbruno
Copy link
Copy Markdown
Member

Does not work with a custom loader

dynaconf onfeature/inspect [$] via 🐍 v3.8.13 (.venv) 
❯ cd tests_functional/custom_loader

dynaconf/tests_functional/custom_loader onfeature/inspect [$] via 🐍 v3.8.13 (.venv) 
❯ cat settings.sff                 
# Stupid File Format
KEYS:name;email;message
VALUES:Bruno Rocha;bruno@rocha.com;Dont use this sff format!

dynaconf/tests_functional/custom_loader onfeature/inspect [$] via 🐍 v3.8.13 (.venv) 
❯ dynaconf -i app.settings list -k NAME   
Working in development environment 
NAME<str> 'Bruno Rocha'

dynaconf/tests_functional/custom_loader onfeature/inspect [$] via 🐍 v3.8.13 (.venv) 621msdynaconf -i app.settings inspect -k NAME
The requested key was not found: 'NAME'

@pedro-psb
Copy link
Copy Markdown
Member Author

Does not work with a custom loader

@rochacbruno I've cheked the example at tests_functional/custom_loader/ and the custom loader doesn't use BaseLoader, so it would have to copy how BaseLoader implements history recording (creating a SourceMetadata and passing to the obj set or update method).

# tests_functional/custom_loader/my_custom_loader/sff_loader.py:load
+ source_metadata = SourceMetadata('sff', found_file, env)

if key:
    value = data.get(key.lower())  # sff format have lower case keys
+    obj.set(key, value, loader_identifier=source_metadata)
-    obj.set(key, value)
else:
+    obj.update(data, loader_identifier=source_metadata)
-    obj.update(data)

We could:

  • Update the example in the docs and in the test to support history.
  • Create a custom loader functional_test using BaseLoader (which should work, as builtins use it) and present it as the preferred way in the docs as well.

What do you think?

@rochacbruno
Copy link
Copy Markdown
Member

I think we need to update the docs and test to support history, there are projects out there using custom loaders based on the docs example, so we can point people on how to adjust their loaders to save history.

Copy link
Copy Markdown
Member

@rochacbruno rochacbruno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 lets merge it! awesome work!

@pedro-psb pedro-psb merged commit f0d9665 into dynaconf:master Jun 14, 2023
@pedro-psb pedro-psb deleted the feature/inspect branch June 14, 2023 17:35
@pedro-psb pedro-psb added this to the 3.2.0 milestone Jun 14, 2023
pedro-psb added a commit to pedro-psb/dynaconf that referenced this pull request Jul 13, 2023
Shortlog of commits since last release:

    Bruno Rocha (4):
          Ignore docs build without a tag
          Cancel any running CI job when a Push is made to an existing PR or branch (dynaconf#952)
          Fix dynaconf#959 cli get will exit code 1 in case of KeyError. (dynaconf#960)
          add tech preview note to inspect docs (dynaconf#961)

    Pedro Pessoa (9):
          Docs - Update envvar.md custom token e.g. to use add_converter (dynaconf#941)
          Feature - Inspect and CLI (dynaconf#939)
          Fix - Template substitution with variable update (dynaconf#944)
          Assert dynaconf#658 works (dynaconf#945)
          fix infinite recursions in special case of django app dynaconf#867 (dynaconf#947)
          Fix - Django functions with `add_converter` (dynaconf#951)
          Fix hooks not re-running on reload dynaconf#850 (dynaconf#953)
          update vault and redis warning recommendations. fix dynaconf#950 (dynaconf#954)
          Fix - Enable merge equal False (dynaconf#957)
@pedro-psb pedro-psb removed this from the 3.2.1 milestone Jul 13, 2023
@pedro-psb pedro-psb mentioned this pull request Aug 10, 2023
11 tasks
rochacbruno added a commit that referenced this pull request Aug 11, 2023
Shortlog of commits since last release:

    Bruno Rocha (5):
          Ignore docs build without a tag
          Cancel any running CI job when a Push is made to an existing PR or branch (#952)
          Fix #959 cli get will exit code 1 in case of KeyError. (#960)
          add tech preview note to inspect docs (#961)
          Build docs

    Hugo Prudente (1):
          Doc advanced usage for cli overrides dynaconf settings fix #967 (#970)

    Marian Ganisin (1):
          Feat: Support for multidoc yaml files (#825)

    Pedro Pessoa (11):
          Docs - Update envvar.md custom token e.g. to use add_converter (#941)
          Feature - Inspect and CLI (#939)
          Fix - Template substitution with variable update (#944)
          Assert #658 works (#945)
          fix infinite recursions in special case of django app #867 (#947)
          Fix - Django functions with `add_converter` (#951)
          Fix hooks not re-running on reload #850 (#953)
          update vault and redis warning recommendations. fix #950 (#954)
          Fix - Enable merge equal False (#957)
          CI - Test docker-compose pyyaml issue (#964)
          Fix: unexpected _bypass_evaluation in BoxList (#966)

    pedro-psb (1):
          Release version 3.2.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants