Repository: dynaconf/dynaconf

Issue:
Export merged environment to yaml
I'm looking for a way to "flatten" the settings into a single `values.yaml` file from the following `settings.yaml`.  

Assume that `ENV_FOR_DYNACONF=development`

```
global:
  a: 1
 
default:
  b: 2

development: 
  foo:
    bar:
      c: 3

production: 
  foo:
    bar:
      c: 4
```

Desired `values.yaml`:
```
a: 1
b: 2
foo:
  bar:
    c: 3
```

Using `print(yaml.dump(settings.as_dict()))` works for the top-level keys but the nested keys returned as *DynaBox* types.




Discussion:
A slightly better version is: 

`print(Box(settings.as_dict()).to_yaml())`

However, the top-level keys are forced to upper-case and the sub-keys remain as original.
My use-case would work perfectly if `settings._store` was a DynaBox instead of a dict().

@austinnichols101 do you want to send a PR changing _store to be a DynaBox?
I made an initial attempt, but the CLI tests are failing.  

I'm going to try to figure it out, but it may turn out to be more involved that what I should attempt for my first dynaconf PR.
@austinnichols101 do you still want to work on it?

I as thinking that it is easy to use https://dynaconf.readthedocs.io/en/latest/guides/accessing_values.html#export-settings-as-a-python-dictionary

and then use that dictionary to create the yaml like:

```py
import yaml
from dynaconf import settings

yaml.dump(settings.as_dict(env='development'), open('/tmp/foo.yaml', 'w'))
```
Dynaconf cli already exports as json

```
dynaconf list -o /tmp/foo.json
```

We can add more arguments and parsers to that command

example:
```
dynaconf list -o /tmp/foo.yaml --flat
```

Resolving patch:
diff --git a/dynaconf/cli.py b/dynaconf/cli.py
--- a/dynaconf/cli.py
+++ b/dynaconf/cli.py
@@ -15,6 +15,7 @@
 from dynaconf import constants
 from dynaconf import default_settings
 from dynaconf import LazySettings
+from dynaconf import loaders
 from dynaconf.loaders.py_loader import get_module
 from dynaconf.utils.files import read_file
 from dynaconf.utils.parse_conf import parse_conf_data
@@ -380,7 +381,14 @@ def init(fileformat, path, env, _vars, _secrets, wg, y, django):
     default=None,
     help="Filepath to write the listed values as json",
 )
-def _list(env, key, more, loader, _all=False, output=None):
+@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.
     """
@@ -428,8 +436,7 @@ def color(_k):
         )
         (click.echo_via_pager if more else click.echo)(datalines)
         if output:
-            with open(output, "w") as output_file:
-                json.dump({cur_env: data}, output_file)
+            loaders.write(output, data, env=not flat and cur_env)
     else:
         key = key.upper()
         value = data.get(key)
@@ -444,8 +451,9 @@ def color(_k):
             )
         )
         if output:
-            with open(output, "w") as output_file:
-                json.dump({cur_env: {key.upper(): value}}, output_file)
+            loaders.write(
+                output, {key.upper(): value}, env=not flat and cur_env
+            )
 
     if env:
         settings.setenv()
diff --git a/dynaconf/loaders/__init__.py b/dynaconf/loaders/__init__.py
--- a/dynaconf/loaders/__init__.py
+++ b/dynaconf/loaders/__init__.py
@@ -9,6 +9,7 @@
 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.parse_conf import false_values
 
 
@@ -174,3 +175,17 @@ def enable_external_loaders(obj):
         ):  # noqa
             obj.logger.debug("loaders: Enabling %s", loader)
             obj.LOADERS_FOR_DYNACONF.insert(0, loader)
+
+
+def write(filename, data, env=None):
+    """Writes `data` to `filename` infers format by file extension."""
+    loader_name = "{0}_loader".format(filename.rpartition(".")[-1])
+    loader = globals().get(loader_name)
+    if not loader:
+        raise IOError("{0} cannot be found.".format(loader_name))
+
+    data = DynaBox(data).to_dict()
+    if env and env not in data:
+        data = {env: data}
+
+    loader.write(filename, data, merge=False)


Test patch: