Repository: dynaconf/dynaconf (python)

Issue:
[bug] Error handling on dynaconf get CLI 
**Describe the bug**
When using get to read a non existent variable it outputs the python traceback to the CLI

**To Reproduce**
```console
$ dynaconf get DONTEXIST
Traceback (most recent call last):
  File "/venv/bin/dynaconf", line 8, in <module>
    sys.exit(main())
  File "/src/dynaconf/dynaconf/vendor/click/core.py", line 857, in __call__
    return self.main(*args, **kwargs)
  File "/src/dynaconf/dynaconf/vendor/click/core.py", line 810, in main
    rv = self.invoke(ctx)
  File "/src/dynaconf/dynaconf/vendor/click/core.py", line 1292, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/src/dynaconf/dynaconf/vendor/click/core.py", line 1099, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/src/dynaconf/dynaconf/vendor/click/core.py", line 613, in invoke
    return callback(*args, **kwargs)
  File "/src/dynaconf/dynaconf/cli.py", line 476, in get
    result = settings[key]  # let the keyerror raises
  File "/src/dynaconf/dynaconf/utils/functional.py", line 19, in inner
    return func(self._wrapped, *args)
  File "/src/dynaconf/dynaconf/base.py", line 315, in __getitem__
    raise KeyError(f"{item} does not exist")
KeyError: 'DONTEXIST does not exist'
```

**Expected behavior**

```console
$ dynaconf get DONTEXIST
Key not found.  # stderr
$ echo $?   # proper retcode
1
```

The same behavior as we have in `list`

```console
$ dynaconf list -k DONTEXIST
Django app detected
Working in development environment 
Key not found
```


Pull request:
Fix #959

Patch:
diff --git a/docs/cli.md b/docs/cli.md
index b9008b4..ab1082a 100644
--- a/docs/cli.md
+++ b/docs/cli.md
@@ -184,6 +184,7 @@ Example:
 export FOO=$(dynaconf get DATABASE_NAME -d 'default')
 ```
 
+If the key doesn't exist and no default is provided it will exit with code 1.
 
 ### dynaconf list
 
diff --git a/dynaconf/cli.py b/dynaconf/cli.py
index b65b999..d498e5b 100644
--- a/dynaconf/cli.py
+++ b/dynaconf/cli.py
@@ -473,7 +473,11 @@ def get(key, default, env, unparse):
     if default is not empty:
         result = settings.get(key, default)
     else:
-        result = settings[key]  # let the keyerror raises
+        try:
+            result = settings[key]
+        except KeyError:
+            click.echo("Key not found", nl=False, err=True)
+            sys.exit(1)
 
     if unparse:
         result = unparse_conf_data(result)
@@ -596,7 +600,7 @@ def _list(env, key, more, loader, _all=False, output=None, flat=False):
             value = empty
 
         if value is empty:
-            click.echo(click.style("Key not found", bg="red", fg="white"))
+            click.secho("Key not found", bg="red", fg="white", err=True)
             return
 
         click.echo(format_setting(key, value))


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 5b1e482..faa3d46 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -126,6 +126,17 @@ def test_get(testdir):
     assert result == "test_value"
 
 
+def test_negative_get(testdir):
+    """Tests get command erroring when key does not exist"""
+    cmd = ["get", "DONTEXIST"]
+    env = {
+        "ROOT_PATH_FOR_DYNACONF": testdir,
+        "INSTANCE_FOR_DYNACONF": "tests.config.settings",
+    }
+    assert run(cmd, env=env, attr="stdout") == "Key not found"
+    assert run(cmd, env=env, attr="exit_code") == 1
+
+
 def test_get_json_dict(testdir):
     """Tests get command printing json"""
     env = env = {