Repository: dynaconf/dynaconf

Issue:
Case-Insensitive Lookup Might Fail in Dynaconf 3.10
**Describe the bug**

The case-insensitive lookup of data might fail in Dynaconf `3.10` and Dynaconf `3.11` if the config name contains spaces.

**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>
   
   ```
   .
   ├── config.yaml
   └── test.py
   
   0 directories, 2 files
   ```
   </details>
   
2. Having the following config file:

   <!-- Please adjust if you are using different files and formats! -->
   
   <details>
   <summary> Config file </summary>
   
   **config.yaml**
   ```yaml
   ROOT:
     BRANCH NODE:
       LEAF
   ```
   
   </details>

3. Having the following app code:

   <details>
   <summary> Code </summary>
   
   **test.py**
   ```python
   from pathlib import Path
   
   from dynaconf import Dynaconf
   
   if __name__ == '__main__':
       settings = Dynaconf(
           settings_file=[Path(__file__).parent.joinpath('config.yaml')])
       print(settings.root.branch_node)
   ```
   
   </details>

4. Executing under the following environment

   <details>
   <summary> Execution </summary>
   
   ```fish
   python3 test.py
   ```
   
   </details>

**Expected behavior**

The command should produce the following output:

```
LEAF 
```

and exit with a zero exit code. 

**Actual behavior**

The script fails:

```
Traceback (most recent call last):
  File "/Users/rene/Downloads/test.py", line 8, in <module>
    print(settings.root.branch_node)
  File "/Users/rene/.pyenv/versions/3.10.6/lib/python3.10/site-packages/dynaconf/utils/boxing.py", line 18, in evaluate
    value = f(dynabox, item, *args, **kwargs)
  File "/Users/rene/.pyenv/versions/3.10.6/lib/python3.10/site-packages/dynaconf/utils/boxing.py", line 41, in __getattr__
    return super().__getattr__(n_item, *args, **kwargs)
  File "/Users/rene/.pyenv/versions/3.10.6/lib/python3.10/site-packages/dynaconf/vendor/box/box.py", line 175, in __getattr__
    raise BoxKeyError(str(E)) from _A
dynaconf.vendor.box.exceptions.BoxKeyError: "'DynaBox' object has no attribute 'branch_node'"
```

with exit code `1`. If I install Dynaconf `3.1.9`

```sh
pip install dynaconf==3.1.9
```

everything works as expected.

**Environment:**

 - OS: macOS `12.6`
 - Dynaconf Version: `3.1.11`


Discussion:

Resolving patch:
diff --git a/dynaconf/utils/__init__.py b/dynaconf/utils/__init__.py
--- a/dynaconf/utils/__init__.py
+++ b/dynaconf/utils/__init__.py
@@ -456,4 +456,6 @@ def find_the_correct_casing(key: str, data: dict[str, Any]) -> str | None:
     for k in data.keys():
         if k.lower() == key.lower():
             return k
+        if k.replace(" ", "_").lower() == key.lower():
+            return k
     return None


Test patch:
diff --git a/tests/test_yaml_loader.py b/tests/test_yaml_loader.py
--- a/tests/test_yaml_loader.py
+++ b/tests/test_yaml_loader.py
@@ -35,6 +35,9 @@ def settings():
     auth:
       password: qwerty
       test: 1234
+  spaced key: 1
+  spaced nested:
+    key: 1
 development:
   password: 88888
   host: devserver.com
@@ -68,6 +71,11 @@ def test_load_from_yaml(settings):
     assert settings.SERVICE.port == 80
     assert settings.SERVICE.auth.password == "qwerty"
     assert settings.SERVICE.auth.test == 1234
+    assert settings.spaced_key == 1
+    assert settings.spaced_nested.key == 1
+    assert settings.spaced_nested["key"] == 1
+    assert settings["spaced key"] == 1
+    assert settings["SPACED KEY"] == 1
     load(settings, filename=YAML, env="DEVELOPMENT")
     assert settings.HOST == "devserver.com"
     load(settings, filename=YAML)
diff --git a/tests_functional/issues/814_spaces_in_keys/app.py b/tests_functional/issues/814_spaces_in_keys/app.py
new file mode 100644
--- /dev/null
+++ b/tests_functional/issues/814_spaces_in_keys/app.py
@@ -0,0 +1,24 @@
+from __future__ import annotations
+
+from dynaconf import Dynaconf
+
+settings = Dynaconf(
+    settings_file=["settings.yaml"],
+)
+
+# spaced jeys can be accessed with dot notation by replacing
+# spaces with underscores
+assert settings.root.branch_node == "LEAF"
+assert settings.root.BRANCH_node == "LEAF"
+assert settings.root.banana_kid == 1
+
+# however, the original keys are still available
+assert settings.root == {"BANANA KID": 1, "BRANCH NODE": "LEAF"}
+assert settings.root["BANANA KID"] == 1
+assert settings.root["BRANCH NODE"] == "LEAF"
+assert settings.root["branch NODE"] == "LEAF"
+assert settings.first_name == "Bruno"
+assert settings.first_NAME == "Bruno"
+assert settings.FIRST_NAME == "Bruno"
+assert settings["first_name"] == "Bruno"
+assert settings["first name"] == "Bruno"
diff --git a/tests_functional/issues/814_spaces_in_keys/settings.yaml b/tests_functional/issues/814_spaces_in_keys/settings.yaml
new file mode 100644
--- /dev/null
+++ b/tests_functional/issues/814_spaces_in_keys/settings.yaml
@@ -0,0 +1,6 @@
+ROOT:
+  BRANCH NODE:
+    LEAF
+  BANANA KID: 1
+
+FIRST NAME: Bruno