Repository: rochacbruno/dynaconf (python)

Issue:
get_fresh breaks configuration
It's possible i'm using this wrong but I suspect this might be bug.

```Dynaconf 1.2.1,``` 
```
Python 3.7.1 (default, Dec 14 2018, 13:28:58) 
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
```
Code
```
In [1]: from dynaconf import settings                                                                                                                                                    

In [2]: settings.POTATO                                                                                                                                                                  
Out[2]: 'test'

In [3]: settings.get_fresh('POTATO')                                                                                                                                                     

In [4]: settings.POTATO                                                                                                                                                                  
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-22d467a777a4> in <module>
----> 1 settings.POTATO

~/miniconda3/lib/python3.7/site-packages/dynaconf/base.py in __getattr__(self, name)
     95             raise AttributeError(
     96                 "Attribute %s was deleted, "
---> 97                 "or belongs to different env" % name
     98             )
     99         if (

AttributeError: Attribute POTATO was deleted, or belongs to different env
```
settings.toml
```
[default]# Defaults
   potato='test'
```

empty .env file.

Pull request description:
Fix #129 on settings file, single keys should be case insensitive.

Patch:
diff --git a/Makefile b/Makefile
index 8f5b723..668b212 100644
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,7 @@ test_examples:
 	@cd example/validators/with_toml/;pwd;dynaconf validate
 	@cd example/toml_with_secrets/;pwd;python program.py | grep -c My5up3r53c4et
 	@cd example/envs;pwd;python app.py
+	@cd example/get_fresh;pwd;python app.py
 	@cd example/django_example/;pwd;python manage.py test
 	@cd example/project_root/;pwd;rm -rf /tmp/dynaconf_project_root_test/settings.py;mkdir -p /tmp/dynaconf_project_root_test/;echo "MESSAGE = 'Hello from tmp'" > /tmp/dynaconf_project_root_test/settings.py;python app.py;rm -rf /tmp/dynaconf_project_root_test/
 
diff --git a/docs/guides/usage.md b/docs/guides/usage.md
index bc25286..c3173e2 100644
--- a/docs/guides/usage.md
+++ b/docs/guides/usage.md
@@ -117,7 +117,7 @@ address = "localhost"
 address = "0.0.0.0"
 ```
 
-> **NOTE**: The **[env]** name and first level variables are case insensitive as internally dynaconf will always use upper case, that means **[development]** and **[DEVELOPMENT]** are equivalent and **address** and **ADDRESS** are also equivalent. This rule does not apply for inner data structures as dictionaries and arrays.
+> **NOTE**: The **[env]** name and first level variables are case insensitive as internally dynaconf will always use upper case, that means **[development]** and **[DEVELOPMENT]** are equivalent and **address** and **ADDRESS** are also equivalent. **But the recommendation is to `always use lower case in files` and `always use upper case in env vars and .py files`** (This rule does not apply for inner data structures as dictionaries and arrays).
 
 ## Supported file formats
 
diff --git a/dynaconf/loaders/base.py b/dynaconf/loaders/base.py
index 255af96..8bc2c87 100644
--- a/dynaconf/loaders/base.py
+++ b/dynaconf/loaders/base.py
@@ -111,6 +111,7 @@ class BaseLoader(object):
             if not source_data:
                 continue
 
+            # env name is checked in lower
             source_data = {
                 k.lower(): value
                 for k, value
@@ -138,6 +139,11 @@ class BaseLoader(object):
                 else:
                     identifier = self.identifier
 
+                # data 1st level keys should be transformed to upper case.
+                data = {k.upper(): v for k, v in data.items()}
+                if key:
+                    key = key.upper()
+
                 if not key:
                     self.obj.update(data, loader_identifier=identifier)
                 elif key in data:
diff --git a/dynaconf/loaders/ini_loader.py b/dynaconf/loaders/ini_loader.py
index a454498..e2d3898 100644
--- a/dynaconf/loaders/ini_loader.py
+++ b/dynaconf/loaders/ini_loader.py
@@ -1,5 +1,6 @@
 # coding: utf-8
 import io
+from pathlib import Path
 from dynaconf import default_settings
 from dynaconf.loaders.base import BaseLoader
 from dynaconf.constants import INI_EXTENSIONS
@@ -43,6 +44,7 @@ def write(settings_path, settings_data, merge=True):
     :param settings_data: a dictionary with data
     :param merge: boolean if existing file should be merged with new data
     """
+    settings_path = Path(settings_path)
     if settings_path.exists() and merge:  # pragma: no cover
         object_merge(
             ConfigObj(
diff --git a/dynaconf/loaders/json_loader.py b/dynaconf/loaders/json_loader.py
index 5b23f01..5cfc5dc 100644
--- a/dynaconf/loaders/json_loader.py
+++ b/dynaconf/loaders/json_loader.py
@@ -1,5 +1,6 @@
 # coding: utf-8
 import io
+from pathlib import Path
 from dynaconf import default_settings
 from dynaconf.loaders.base import BaseLoader
 from dynaconf.constants import JSON_EXTENSIONS
@@ -36,7 +37,7 @@ def write(settings_path, settings_data, merge=True):
     :param settings_data: a dictionary with data
     :param merge: boolean if existing file should be merged with new data
     """
-
+    settings_path = Path(settings_path)
     if settings_path.exists() and merge:  # pragma: no cover
         object_merge(
             json.load(
diff --git a/dynaconf/loaders/py_loader.py b/dynaconf/loaders/py_loader.py
index 6a2a13d..b8d48dd 100644
--- a/dynaconf/loaders/py_loader.py
+++ b/dynaconf/loaders/py_loader.py
@@ -3,6 +3,7 @@ import os
 import errno
 import types
 import importlib
+from pathlib import Path
 from dynaconf import default_settings
 from dynaconf.utils.files import find_file
 from dynaconf.utils import DynaconfDict, object_merge, raw_logger
@@ -89,6 +90,7 @@ def write(settings_path, settings_data, merge=True):
     :param settings_data: a dictionary with data
     :param merge: boolean if existing file should be merged with new data
     """
+    settings_path = Path(settings_path)
     if settings_path.exists() and merge:  # pragma: no cover
         existing = DynaconfDict()
         load(existing, str(settings_path))
diff --git a/dynaconf/loaders/toml_loader.py b/dynaconf/loaders/toml_loader.py
index 57aa4b8..d7149d2 100644
--- a/dynaconf/loaders/toml_loader.py
+++ b/dynaconf/loaders/toml_loader.py
@@ -1,12 +1,13 @@
 # coding: utf-8
 import io
+from pathlib import Path
 from dynaconf import default_settings
 from dynaconf.loaders.base import BaseLoader
 from dynaconf.constants import TOML_EXTENSIONS
 from dynaconf.utils import object_merge
 try:
     import toml
-except ImportError as e:  # pragma: no cover
+except ImportError:  # pragma: no cover
     toml = None
 
 
@@ -43,6 +44,7 @@ def write(settings_path, settings_data, merge=True):
     :param settings_data: a dictionary with data
     :param merge: boolean if existing file should be merged with new data
     """
+    settings_path = Path(settings_path)
     if settings_path.exists() and merge:  # pragma: no cover
         object_merge(
             toml.load(
diff --git a/dynaconf/loaders/yaml_loader.py b/dynaconf/loaders/yaml_loader.py
index 191603b..c77dce0 100644
--- a/dynaconf/loaders/yaml_loader.py
+++ b/dynaconf/loaders/yaml_loader.py
@@ -1,5 +1,6 @@
 # coding: utf-8
 import io
+from pathlib import Path
 from dynaconf import default_settings
 from dynaconf.loaders.base import BaseLoader
 from dynaconf.constants import YAML_EXTENSIONS
@@ -43,6 +44,7 @@ def write(settings_path, settings_data, merge=True):
     :param settings_data: a dictionary with data
     :param merge: boolean if existing file should be merged with new data
     """
+    settings_path = Path(settings_path)
     if settings_path.exists() and merge:  # pragma: no cover
         object_merge(
             yaml.load(
diff --git a/example/get_fresh/.env b/example/get_fresh/.env
new file mode 100644
index 0000000..e69de29
diff --git a/example/get_fresh/app.py b/example/get_fresh/app.py
new file mode 100644
index 0000000..04c9001
--- /dev/null
+++ b/example/get_fresh/app.py
@@ -0,0 +1,36 @@
+from dynaconf import settings
+from dynaconf.loaders.toml_loader import write
+
+# Get the potato
+original = str(settings.POTATO)  # str() to force a copy
+modern = 'Modern Potato'
+print('Original data:', original)
+assert settings.POTATO == settings.get('potato') == original
+
+# Change the Toml file
+print('Change POTATO to `Modern Potato` in settings.toml file...')
+write(
+    settings.path_for('settings.toml'),
+    {'default': {'potato': modern}}
+)
+
+
+# Print the original
+print("Dynaconf knows:", settings.POTATO)
+assert settings.POTATO == settings.get('potato') == original
+
+# Get it freshly
+print('Read it freshly to get changed value...')
+print('Changed data:', settings.get_fresh('POTATO'))
+assert settings.POTATO == settings.get_fresh('potato') == modern
+
+# Get it again
+print('Now read again without the get_fresh method')
+print('Still the new value no?', settings.POTATO)
+assert settings.POTATO == settings.get('potato') == modern
+
+# Restore it
+write(
+    settings.path_for('settings.toml'),
+    {'default': {'potato': original}}
+)
diff --git a/example/get_fresh/settings.toml b/example/get_fresh/settings.toml
new file mode 100644
index 0000000..0e03600
--- /dev/null
+++ b/example/get_fresh/settings.toml
@@ -0,0 +1,2 @@
+[default]
+potato = "Original Potato"


Test patch:
diff --git a/tests/test_ini_loader.py b/tests/test_ini_loader.py
index 4da0edb..d4e4d2f 100644
--- a/tests/test_ini_loader.py
+++ b/tests/test_ini_loader.py
@@ -111,12 +111,20 @@ def test_load_single_key():
     a = "a,b"
     [foo]
     bar = "blaz"
-    zaz = "naz"
+    ZAZ = "naz"
+    lowerkey = 'hello'
+    UPPERKEY = 'world'
     """
     load(settings, filename=ini, env='FOO', key='bar')
     assert settings.BAR == 'blaz'
     assert settings.exists('BAR') is True
     assert settings.exists('ZAZ') is False
+    load(settings, filename=ini, env='FOO', key='ZAZ')
+    assert settings.ZAZ == 'naz'
+    load(settings, filename=ini, env='FOO', key='LOWERKEY')
+    assert settings.LOWERKEY == 'hello'
+    load(settings, filename=ini, env='FOO', key='upperkey')
+    assert settings.UPPERKEY == 'world'
 
 
 def test_empty_value():
diff --git a/tests/test_toml_loader.py b/tests/test_toml_loader.py
index 05f8774..f76f732 100644
--- a/tests/test_toml_loader.py
+++ b/tests/test_toml_loader.py
@@ -111,14 +111,23 @@ def test_no_key_error_on_invalid_env():
 def test_load_single_key():
     """Test loading a single key"""
     toml = """
+    a = "a,b"
     [foo]
     bar = "blaz"
-    zaz = "naz"
+    ZAZ = "naz"
+    lowerkey = 'hello'
+    UPPERKEY = 'world'
     """
     load(settings, filename=toml, env='FOO', key='bar')
     assert settings.BAR == 'blaz'
     assert settings.exists('BAR') is True
     assert settings.exists('ZAZ') is False
+    load(settings, filename=toml, env='FOO', key='ZAZ')
+    assert settings.ZAZ == 'naz'
+    load(settings, filename=toml, env='FOO', key='LOWERKEY')
+    assert settings.LOWERKEY == 'hello'
+    load(settings, filename=toml, env='FOO', key='upperkey')
+    assert settings.UPPERKEY == 'world'
 
 
 def test_empty_value():