Repository: dynaconf/dynaconf

Issue:
[bug]Clean Python pip install problem
**Describe the bug**
If starting a new Python installation, DynaConf 2.1.0 will not work successfully.  It appears to be choking while reading a YAML file.  The only workaround I have found is to roll back to 2.0.4.


**To Reproduce**
Steps to reproduce the behavior:
I have put together a very simple project that will demonstrate the problem, see the attached zip file below.  Just make sure you are using a brand new installation of Python - System, VirtualEnv or Conda Environment - problem occurs in all cases.  Just for clarity, I use Conda.

pip install -r requirements.txt
python dc-error.py


**Expected behavior**
The program should run and print out the setting from the error.yaml file.


**Debug output**
C:\ProgramData\Anaconda3\envs\DynaConfError\python.exe C:/Development/DynaConfError/dc-error.py
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\envs\DynaConfError\lib\site-packages\dynaconf\loaders\base.py", line 110, in _read
    data = source_data[env.lower()]
KeyError: 'dynaconf'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:/Development/DynaConfError/dc-error.py", line 11, in <module>
    settings.load_file(path='error.yaml', silent=False)
  File "C:\ProgramData\Anaconda3\envs\DynaConfError\lib\site-packages\dynaconf\base.py", line 908, in load_file
    filename=path,
  File "C:\ProgramData\Anaconda3\envs\DynaConfError\lib\site-packages\dynaconf\loaders\__init__.py", line 116, in settings_loader
    obj, filename=mod_file, env=env, silent=silent, key=key
  File "C:\ProgramData\Anaconda3\envs\DynaConfError\lib\site-packages\dynaconf\loaders\yaml_loader.py", line 50, in load
    loader.load(filename=filename, key=key, silent=silent)
  File "C:\ProgramData\Anaconda3\envs\DynaConfError\lib\site-packages\dynaconf\loaders\base.py", line 71, in load
    self._read(files, env_list, silent, key)
  File "C:\ProgramData\Anaconda3\envs\DynaConfError\lib\site-packages\dynaconf\loaders\base.py", line 125, in _read
    raise KeyError(message)
KeyError: 'yaml_loader: dynaconf env not defined in C:\\Development\\DynaConfError\\.\\error.yaml'


**Environment (please complete the following information):**
 - OS: Windows 10 Pro, Ubuntu 18.04, CentOS 7
 - Dynaconf Version 2.1.0
 - Frameworks in use:  None


**Additional context**
Interestingly, if you already had an older version of DynaConf installed in a python environment and update it, this code will execute and work as expected.


[DynaConfError.zip](https://github.com/rochacbruno/dynaconf/files/3598272/DynaConfError.zip)



Discussion:
This is the expected behavior if you load using `silent=False` this makes dynaconf to raise all the internal errors, in this case your settings file doesn't have all the possible environments.

Change it to Silent=True or remove this parameter as `silent=True` is the default

```py
from dynaconf import LazySettings

# This is an easy way to get around having to have an.env file to set this environmental variable.  It's a
# DynaConf thing...
#   Env Files:  https://dynaconf.readthedocs.io/en/latest/guides/usage.html#the-settings-files
#   This workaround:  https://dynaconf.readthedocs.io/en/latest/guides/configuration.html
settings = LazySettings(
    ROOT_PATH_FOR_DYNACONF='.',
)

settings.load_file(path='error.yaml', silent=True)
print(settings['var_1'])

```
I will keep this open as this may be documented under `advanced usage` doc guide.

Resolving patch:
diff --git a/dynaconf/loaders/base.py b/dynaconf/loaders/base.py
--- a/dynaconf/loaders/base.py
+++ b/dynaconf/loaders/base.py
@@ -103,17 +103,27 @@ def _read(self, files, envs, silent=True, key=None):
                 k.lower(): value for k, value in source_data.items()
             }
 
-            for env in envs:
+            # all lower case for comparison
+            base_envs = [
+                # DYNACONF or MYPROGRAM
+                (self.obj.get("ENVVAR_PREFIX_FOR_DYNACONF") or "").lower(),
+                # DEFAULT
+                self.obj.get("DEFAULT_ENV_FOR_DYNACONF").lower(),
+                # default active env unless ENV_FOR_DYNACONF is changed
+                "development",
+                # backwards compatibility for global
+                "dynaconf",
+                # global that rules all
+                "global",
+            ]
 
+            for env in envs:
+                env = env.lower()  # lower for better comparison
                 data = {}
                 try:
-                    data = source_data[env.lower()]
+                    data = source_data[env]
                 except KeyError:
-                    if env not in (
-                        self.obj.get("ENVVAR_PREFIX_FOR_DYNACONF")
-                        or "DYNACONF",
-                        "GLOBAL",
-                    ):
+                    if env not in base_envs:
                         message = "%s_loader: %s env not defined in %s" % (
                             self.identifier,
                             env,
@@ -125,11 +135,8 @@ def _read(self, files, envs, silent=True, key=None):
                             raise KeyError(message)
                     continue
 
-                if (
-                    env.lower()
-                    != self.obj.get("DEFAULT_ENV_FOR_DYNACONF").lower()
-                ):
-                    identifier = "{0}_{1}".format(self.identifier, env.lower())
+                if env != self.obj.get("DEFAULT_ENV_FOR_DYNACONF").lower():
+                    identifier = "{0}_{1}".format(self.identifier, env)
                 else:
                     identifier = self.identifier
 
@@ -144,7 +151,7 @@ def _read(self, files, envs, silent=True, key=None):
                     "{}_loader: {}[{}]{}".format(
                         self.identifier,
                         os.path.split(source_file)[-1],
-                        env.lower(),
+                        env,
                         list(data.keys()) if is_secret else data,
                     )
                 )


Test patch: