Repository: dynaconf/dynaconf

Issue:
[bug] settings.local.toml tree overrides settings.toml
**Describe the bug**
If I define a conf variable "A.B.C" in one file and another conf variable "A.cousin.D" in another file, then "A.B.C" is erased.


**To Reproduce**
Steps to reproduce the behavior:

1. Having the following folder structure

<!-- Describe or use the command `$ tree -v` and paste below -->

<details>
<summary> Project structure </summary>

```bash
$ ls -alh
total 24K
drwxrwxr-x   2 user group 4,0K Jan 15 18:34 ./
drwxr-xr-x 109 user group 4,0K Jan 15 17:31 ../
-rw-rw-r--   1 user group   75 Jan 15 18:27 dynaconf_test.py
-rw-rw-r--   1 user group   16 Jan 15 18:34 requirements.txt
-rw-rw-r--   1 user group   45 Jan 15 18:28 settings.local.toml
-rw-rw-r--   1 user group   40 Jan 15 18:27 settings.toml
```
</details>

2. Having the following config files:

<!-- Please adjust if you are using different files and formats! -->

<details>
<summary> Config files </summary>


```bash
$ echo $ENV_FOR_DYNACONF

```

and

**/path/settings.toml**
```toml
[default]

[development.A.B]
  C = "1"
```

**/path/settings.local.toml**
```toml
[default]

[development.A.cousin]
  D = "2"

```

**/path/requirements.txt**
```
dynaconf==v2.2.2
```


</details>

3. Having the following app code:

<details>
<summary> Code </summary>

**/path/dynaconf_test.py**
```python
from dynaconf import settings

print(settings.get('A').get('B').get('C'))
```

</details>

4. Executing under the following environment:

<details>
<summary> Execution </summary>

```bash
$ python3 --version
Python 3.6.9

$ python3 -m pip install --user --upgrade pip
Requirement already up-to-date: ...
$ python3 -m pip install --user --upgrade virtualenv
Requirement already up-to-date:
$ python3 -m virtualenv -p python3 venv
Already using interpreter /usr/bin/python3
Using base prefix '/usr'
[...]
Installing setuptools, pip, wheel...
done.

$ source venv/bin/activate
$ python3 -m pip install --quiet -r requirements.txt
```

</details>

**Expected behavior**
Same as if I remove settings.local.toml or merge the two file together.
```bash
$ python dynaconf_test.py
1
```

**Actual behavior**
```bash
$ python dynaconf_test.py
Traceback (most recent call last):
  File "dynaconf_test.py", line 3, in <module>
    print(settings.get('A').get('B').get('C'))
AttributeError: 'NoneType' object has no attribute 'get'
```

**Debug output**

<details>
<summary> Debug Output </summary>

```bash

# export `DEBUG_LEVEL_FOR_DYNACONF=DEBUG` reproduce your problem and paste the output here
2020-01-15:18:44:51,460 DEBUG    [base.py:86 - _read] toml_loader: /path/settings.toml
2020-01-15:18:44:51,460 DEBUG    [base.py:159 - _read] toml_loader: settings.toml[default]{}
2020-01-15:18:44:51,460 DEBUG    [base.py:159 - _read] toml_loader: settings.toml[development]{'A': {'B': {'C': '1'}}}
2020-01-15:18:44:51,460 DEBUG    [base.py:86 - _read] toml_loader: /path/settings.local.toml
2020-01-15:18:44:51,460 DEBUG    [base.py:159 - _read] toml_loader: settings.local.toml[default]{}
2020-01-15:18:44:51,460 DEBUG    [base.py:159 - _read] toml_loader: settings.local.toml[development]{'A': {'cousin': {'D': '2'}}}
2020-01-15:18:44:51,461 DEBUG    [base.py:902 - execute_loaders] Dynaconf executing: dynaconf.loaders.env_loader
2020-01-15:18:44:51,461 DEBUG    [base.py:905 - execute_loaders] Loaded Files: ['/path/settings.toml', '/path/settings.local.toml']
2020-01-15:18:44:51,461 DEBUG    [base.py:129 - _setup] Lazy Settings _setup ...
Traceback (most recent call last):
  File "dynaconf_test.py", line 3, in <module>
    print(settings.get('A').get('B').get('C'))
AttributeError: 'NoneType' object has no attribute 'get'
```

</details>

**Environment (please complete the following information):**
 - OS: Linux Mint 19 (based on Ubuntu Bionic Beaver)
 - Dynaconf Version: 2.2.2
 - Frameworks in use: None

**Additional context**
If I remove the file settings.local.toml then it works fine:

```bash
$ rm settings.local.toml
$ python dynaconf_test.py
1
```



Discussion:
I was also running into this, but it explained it so myself as logical: If dicts are not replaced completely it would not be possible to remove any keys in a local settings file, would it?
Indeed, I could see use cases where you would want to be able to have this behaviour, but one could argue that the user writing the local settings is supposed to be aware of what is in the global settings, and should explicitly overwrite any branch that he wants to be overridden.

In my example, if the user actually wanted to drop everything in `development.A` from **settings.toml**, perhaps we could devise a way where he would have to make it more explicit, maybe with something like this in **settings.local.toml**:

```
[default]

[development.A]

[development.A.cousin]
  D = "2"
```

To give more context of my use case, I use dynaconf to define connection parameters to multiple data sources. So I have things like this in **settings.toml**

```
[development.connections.sql_database_1]
  url = ...
  login = ...

[development.connections.big_query_project_1]
  project = ...
  json_key_file = ...

etc.
```
Sometimes, I want to test a new connection locally without editing the main **settings.toml** file, especially to avoid committing them by accident.

But moving a single one of these in **settings.local.toml** will make the whole `development.connections` object from **settings.toml** empty.

I hope we can find a way to make this more user friendly.

Similar case:

Sometimes I am lazy and set something like this in my `settings.local.toml` to ease local tests.
```
[default]
SKIP_JWT_VALIDATION = 1
```

In my `settings.toml` I have

```
[testing]
SKIP_JWT_VALIDATION = 0
```
to ensure proper behavior in my unit tests.

`testing` should win IMO against `default`. But apparently `.local.` wins against everything else. `SKIP_JWT_VALIDATION` is set to `1` in the tests.

Resolving patch:
diff --git a/example/issues/284_local_sets/app.py b/example/issues/284_local_sets/app.py
new file mode 100644
--- /dev/null
+++ b/example/issues/284_local_sets/app.py
@@ -0,0 +1,12 @@
+from dynaconf import Dynaconf
+
+settings = Dynaconf(
+    settings_file="settings.toml",
+    environments=True,
+    # merge_enabled=True  # this enabled global merge of all files
+)
+
+print(settings.A)
+
+assert settings.get("A").get("B").get("C") == "1"
+assert settings.get("A").get("cousin").get("D") == "2"


Test patch: