Repository: rochacbruno/dynaconf (python)

Issue:
[bug] GLOBAL_ENV_FOR_DYNACONF=none should disable the prefix
**Describe the bug**
Considering this a bug because this seems to be the natural behavior, if someone does not want to have the prefix `DYNACONF_` on envvars. (like in docker containers as reported by @janw) then it should be possible to disable it.

**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
.env
```
</details>

2. Having the following config files:

<!-- Please adjust if you are using different files and formats! -->

<details>
<summary> Config files </summary>

**.env**
```bash
GLOBAL_ENV_FOR_DYNACONF=none
VALUE=1
OTHER="other value"
```
</details>

5. Executing under the following environment

<details>
<summary> Execution </summary>

```bash
$ dynaconf list -k VALUE        
Working in development environment 
Key not found
```
</details>

**Expected behavior**

When `GLOBAL_ENV_FOR_DYNACONF` is set to `none` expected is that exported envvars is read without prefix. so:

```bash
$ dynaconf list -k VALUE        
Working in development environment 
VALUE: 1
```

**Debug output**

<details>
<summary> Debug Output </summary>

```bash

 $ dynaconf list -k ENV_FOR_DYNACONF    
2019-04-17:17:08:17,866 DEBUG    [default_settings.py:49 - start_dotenv] Starting Dynaconf Dotenv Base
2019-04-17:17:08:17,866 DEBUG    [files.py:51 - find_file] No root_path for .env
2019-04-17:17:08:17,881 DEBUG    [files.py:68 - find_file] Search Tree: ['/home/rochacbruno/Projects/python/envs/dynaconf/bin', '/home/rochacbruno/Projects/python/envs/dynaconf/bin/config', '/home/rochacbruno/Projects/python/envs/dynaconf', '/home/rochacbruno/Projects/python/envs/dynaconf/config', '/home/rochacbruno/Projects/python/envs', '/home/rochacbruno/Projects/python/envs/config', '/home/rochacbruno/Projects/python', '/home/rochacbruno/Projects/python/config', '/home/rochacbruno/Projects', '/home/rochacbruno/Projects/config', '/home/rochacbruno', '/home/rochacbruno/config', '/home', '/home/config', '/', '/config', '/tmp/test_dis/project', '/tmp/test_dis/project/config']
2019-04-17:17:08:17,881 DEBUG    [files.py:72 - find_file] Searching for .env
2019-04-17:17:08:17,881 DEBUG    [files.py:79 - find_file] Found: /tmp/test_dis/project/.env
2019-04-17:17:08:17,882 DEBUG    [base.py:181 - __init__] Initializing Dynaconf ({})
2019-04-17:17:08:17,882 DEBUG    [__init__.py:29 - default_loader] loading: RENAMED_VARS:{'DYNACONF_NAMESPACE': 'ENV_FOR_DYNACONF', 'NAMESPACE_FOR_DYNACONF': 'ENV_FOR_DYNACONF', 'DYNACONF_SETTINGS_MODULE': 'SETTINGS_MODULE_FOR_DYNACONF', 'DYNACONF_SETTINGS': 'SETTINGS_MODULE_FOR_DYNACONF', 'SETTINGS_MODULE': 'SETTINGS_MODULE_FOR_DYNACONF', 'PROJECT_ROOT': 'ROOT_PATH_FOR_DYNACONF', 'PROJECT_ROOT_FOR_DYNACONF': 'ROOT_PATH_FOR_DYNACONF', 'DYNACONF_SILENT_ERRORS': 'SILENT_ERRORS_FOR_DYNACONF', 'DYNACONF_ALWAYS_FRESH_VARS': 'FRESH_VARS_FOR_DYNACONF', 'BASE_NAMESPACE_FOR_DYNACONF': 'DEFAULT_ENV_FOR_DYNACONF'}
2019-04-17:17:08:17,882 DEBUG    [__init__.py:29 - default_loader] loading: ROOT_PATH_FOR_DYNACONF:None
2019-04-17:17:08:17,882 DEBUG    [__init__.py:29 - default_loader] loading: PROJECT_ROOT_FOR_DYNACONF:None
2019-04-17:17:08:17,882 DEBUG    [__init__.py:29 - default_loader] loading: SETTINGS_MODULE_FOR_DYNACONF:settings.py,.secrets.py,settings.toml,settings.tml,.secrets.toml,.secrets.tml,settings.yaml,settings.yml,.secrets.yaml,.secrets.yml,settings.ini,settings.conf,settings.properties,.secrets.ini,.secrets.conf,.secrets.properties,settings.json,.secrets.json
2019-04-17:17:08:17,882 DEBUG    [__init__.py:29 - default_loader] loading: ENV_SWITCHER_FOR_DYNACONF:ENV_FOR_DYNACONF
2019-04-17:17:08:17,882 DEBUG    [__init__.py:29 - default_loader] loading: ENV_FOR_DYNACONF:DEVELOPMENT
2019-04-17:17:08:17,882 DEBUG    [__init__.py:29 - default_loader] loading: DEFAULT_ENV_FOR_DYNACONF:DEFAULT
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: GLOBAL_ENV_FOR_DYNACONF:none
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: ENCODING_FOR_DYNACONF:utf-8
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: MERGE_ENABLED_FOR_DYNACONF:False
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: ENVVAR_FOR_DYNACONF:SETTINGS_MODULE_FOR_DYNACONF
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: REDIS_FOR_DYNACONF:{'host': 'localhost', 'port': 6379, 'db': 0, 'decode_responses': True}
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: REDIS_ENABLED_FOR_DYNACONF:False
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: VAULT_FOR_DYNACONF:{'url': 'http://localhost:8200', 'token': None, 'cert': None, 'verify': None, 'timeout': None, 'proxies': None, 'allow_redirects': None, 'session': None}
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: VAULT_ENABLED_FOR_DYNACONF:False
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: VAULT_PATH_FOR_DYNACONF:/secret/data/
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: CORE_LOADERS_FOR_DYNACONF:['YAML', 'TOML', 'INI', 'JSON', 'PY']
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: LOADERS_FOR_DYNACONF:['dynaconf.loaders.env_loader']
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: SILENT_ERRORS_FOR_DYNACONF:True
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: FRESH_VARS_FOR_DYNACONF:[]
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: DEBUG_LEVEL_FOR_DYNACONF:DEBUG
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: YAML:None
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: TOML:None
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: JSON:None
2019-04-17:17:08:17,883 DEBUG    [__init__.py:29 - default_loader] loading: INI:None
2019-04-17:17:08:17,884 DEBUG    [__init__.py:29 - default_loader] loading: DOTENV_PATH_FOR_DYNACONF:None
2019-04-17:17:08:17,884 DEBUG    [__init__.py:29 - default_loader] loading: DOTENV_VERBOSE_FOR_DYNACONF:False
2019-04-17:17:08:17,884 DEBUG    [__init__.py:29 - default_loader] loading: DOTENV_OVERRIDE_FOR_DYNACONF:False
2019-04-17:17:08:17,884 DEBUG    [__init__.py:29 - default_loader] loading: INSTANCE_FOR_DYNACONF:None
2019-04-17:17:08:17,884 DEBUG    [__init__.py:29 - default_loader] loading: YAML_LOADER_FOR_DYNACONF:full_load
2019-04-17:17:08:17,884 DEBUG    [__init__.py:29 - default_loader] loading: COMMENTJSON_ENABLED_FOR_DYNACONF:False
2019-04-17:17:08:17,884 DEBUG    [__init__.py:29 - default_loader] loading: SECRETS_FOR_DYNACONF:None
2019-04-17:17:08:17,884 DEBUG    [__init__.py:29 - default_loader] loading: INCLUDES_FOR_DYNACONF:[]
2019-04-17:17:08:17,884 DEBUG    [__init__.py:29 - default_loader] loading: SKIP_FILES_FOR_DYNACONF:[]
2019-04-17:17:08:17,884 DEBUG    [default_settings.py:49 - start_dotenv] Starting Dynaconf Dotenv Base
2019-04-17:17:08:17,884 DEBUG    [files.py:51 - find_file] No root_path for .env
2019-04-17:17:08:17,885 DEBUG    [files.py:72 - find_file] Searching for .env
2019-04-17:17:08:17,885 DEBUG    [files.py:79 - find_file] Found: /tmp/test_dis/project/.env
2019-04-17:17:08:17,885 DEBUG    [__init__.py:54 - default_loader] overriding from envvar: GLOBAL_ENV_FOR_DYNACONF:none
2019-04-17:17:08:17,885 DEBUG    [__init__.py:54 - default_loader] overriding from envvar: DEBUG_LEVEL_FOR_DYNACONF:DEBUG
2019-04-17:17:08:17,885 DEBUG    [files.py:51 - find_file] No root_path for settings.py
2019-04-17:17:08:17,886 DEBUG    [files.py:72 - find_file] Searching for settings.py
2019-04-17:17:08:17,886 DEBUG    [files.py:51 - find_file] No root_path for .secrets.py
2019-04-17:17:08:17,886 DEBUG    [files.py:72 - find_file] Searching for .secrets.py
2019-04-17:17:08:17,886 DEBUG    [files.py:51 - find_file] No root_path for settings.toml
2019-04-17:17:08:17,887 DEBUG    [files.py:72 - find_file] Searching for settings.toml
2019-04-17:17:08:17,887 DEBUG    [files.py:51 - find_file] No root_path for settings.tml
2019-04-17:17:08:17,887 DEBUG    [files.py:72 - find_file] Searching for settings.tml
2019-04-17:17:08:17,887 DEBUG    [files.py:51 - find_file] No root_path for .secrets.toml
2019-04-17:17:08:17,888 DEBUG    [files.py:72 - find_file] Searching for .secrets.toml
2019-04-17:17:08:17,888 DEBUG    [files.py:51 - find_file] No root_path for .secrets.tml
2019-04-17:17:08:17,888 DEBUG    [files.py:72 - find_file] Searching for .secrets.tml
2019-04-17:17:08:17,888 DEBUG    [files.py:51 - find_file] No root_path for settings.yaml
2019-04-17:17:08:17,889 DEBUG    [files.py:72 - find_file] Searching for settings.yaml
2019-04-17:17:08:17,889 DEBUG    [files.py:51 - find_file] No root_path for settings.yml
2019-04-17:17:08:17,889 DEBUG    [files.py:72 - find_file] Searching for settings.yml
2019-04-17:17:08:17,890 DEBUG    [files.py:51 - find_file] No root_path for .secrets.yaml
2019-04-17:17:08:17,890 DEBUG    [files.py:72 - find_file] Searching for .secrets.yaml
2019-04-17:17:08:17,890 DEBUG    [files.py:51 - find_file] No root_path for .secrets.yml
2019-04-17:17:08:17,891 DEBUG    [files.py:72 - find_file] Searching for .secrets.yml
2019-04-17:17:08:17,891 DEBUG    [files.py:51 - find_file] No root_path for settings.ini
2019-04-17:17:08:17,891 DEBUG    [files.py:72 - find_file] Searching for settings.ini
2019-04-17:17:08:17,891 DEBUG    [files.py:51 - find_file] No root_path for settings.conf
2019-04-17:17:08:17,892 DEBUG    [files.py:72 - find_file] Searching for settings.conf
2019-04-17:17:08:17,892 DEBUG    [files.py:51 - find_file] No root_path for settings.properties
2019-04-17:17:08:17,892 DEBUG    [files.py:72 - find_file] Searching for settings.properties
2019-04-17:17:08:17,892 DEBUG    [files.py:51 - find_file] No root_path for .secrets.ini
2019-04-17:17:08:17,893 DEBUG    [files.py:72 - find_file] Searching for .secrets.ini
2019-04-17:17:08:17,893 DEBUG    [files.py:51 - find_file] No root_path for .secrets.conf
2019-04-17:17:08:17,893 DEBUG    [files.py:72 - find_file] Searching for .secrets.conf
2019-04-17:17:08:17,893 DEBUG    [files.py:51 - find_file] No root_path for .secrets.properties
2019-04-17:17:08:17,894 DEBUG    [files.py:72 - find_file] Searching for .secrets.properties
2019-04-17:17:08:17,894 DEBUG    [files.py:51 - find_file] No root_path for settings.json
2019-04-17:17:08:17,895 DEBUG    [files.py:72 - find_file] Searching for settings.json
2019-04-17:17:08:17,895 DEBUG    [files.py:51 - find_file] No root_path for .secrets.json
2019-04-17:17:08:17,896 DEBUG    [files.py:72 - find_file] Searching for .secrets.json
2019-04-17:17:08:17,896 DEBUG    [base.py:712 - execute_loaders] Dynaconf executing: dynaconf.loaders.env_loader
2019-04-17:17:08:17,896 DEBUG    [base.py:715 - execute_loaders] Loaded Files: []
2019-04-17:17:08:17,896 DEBUG    [base.py:122 - _setup] Lazy Settings _setup ...
Working in development environment 
ENV_FOR_DYNACONF: 'DEVELOPMENT'


```

</details>

**Environment (please complete the following information):**
 - OS: Fedora 29
 - Dynaconf Version: source

**Additional context**

It works if I use set to `GLOBAL_ENV_FOR_DYNACONF=""` and use `_` as prefix.

.env
```env
GLOBAL_ENV_FOR_DYNACONF=""
_VALUE=1
_OTHER="other value"
```

exec
```
$ dynaconf list -k VALUE
Working in development environment 
VALUE: 1
```

## Suggestion for solution

When `GLOBAL_ENV_FOR_DYNACONF=none` (internally parsed as `None` by toml) then Dynaconf will read all the content of `os.environ`

This is @janw idea :) 


Pull request description:
Fix #163 Allow disabling env prefix
As discussed in #163, setting GLOBAL_ENV_FOR_DYNACONF='@none None', previously caused Dynaconf to only load env vars with a leading underscore, although it would be expected to load *all* vars. 

The necessary changes have been made to support explicit casting to NoneType through `'@none None'`, and forcing an "underscore-only prefix" by setting `GLOBAL_ENV_FOR_DYNACONF=""`. So:

* `GLOBAL_ENV_FOR_DYNACONF="EXAMPLE"` would load `EXAMPLE_VALUE=1` as settings.VALUE
* `GLOBAL_ENV_FOR_DYNACONF="none"` would load `NONE_VALUE=1` as settings.VALUE
* `GLOBAL_ENV_FOR_DYNACONF=""` would load `_VALUE=1` as settings.VALUE
* `GLOBAL_ENV_FOR_DYNACONF="@none None"` would load `VALUE=1`  as settings.VALUE, and all of the above verbatim, because no prefix would be enforced


Patch:
diff --git a/Makefile b/Makefile
index 857693c..c0df2e9 100644
--- a/Makefile
+++ b/Makefile
@@ -61,6 +61,7 @@ test_examples:
 	python example/specific_settings_modules/app.py
 	python example/django_example/manage.py test polls -v 2
 	PYTHONPATH=example/django_example DJANGO_SETTINGS_MODULE=foo.settings python example/django_example/standalone_script.py
+	python example/global_env_prefix/app.py
 
 	@echo '###############  Django Admin From root folder  ###############'
 	PYTHONPATH=./example/django_example/ DJANGO_SETTINGS_MODULE=foo.settings django-admin test polls -v 2
diff --git a/docs/guides/configuration.md b/docs/guides/configuration.md
index e209529..9802db5 100644
--- a/docs/guides/configuration.md
+++ b/docs/guides/configuration.md
@@ -52,8 +52,8 @@ It can also be passed as parameters to extensions like `FlaskDynaconf` or set in
 +---------------------+---------+--------------------------------------------------+--------------------------------------------------+--------------------------------------------------------------+
 | ENV_SWITCHER        | str     | Variable used to change working env              | ENV_FOR_DYNACONF                                 | ENV_SWITCHER_FOR_DYNACONF=MYPROGRAM_ENV                      |
 +---------------------+---------+--------------------------------------------------+--------------------------------------------------+--------------------------------------------------------------+
-| GLOBAL_ENV          | str     | | Prefix for exporting parameters as env vars    | "DYNACONF"                                       | GLOBAL_ENV_FOR_DYNACONF=MYPROGRAM                            |
-|                     |         | |                                                |                                                  |                                                              |
+| GLOBAL_ENV          | str     | | Prefix for exporting parameters as env vars    | "DYNACONF"                                       || GLOBAL_ENV_FOR_DYNACONF=MYPROGRAM                           |
+|                     |         | |                                                |                                                  || GLOBAL_ENV_FOR_DYNACONF=false                               |
 |                     |         | | Example:                                       |                                                  |                                                              |
 |                     |         | | If your program is called `MYPROGRAM`          |                                                  |                                                              |
 |                     |         | | you may want users to use `MYPROGRAM_FOO=bar`  |                                                  |                                                              |
diff --git a/docs/guides/environment_variables.md b/docs/guides/environment_variables.md
index 31d4ec3..d8be8f5 100644
--- a/docs/guides/environment_variables.md
+++ b/docs/guides/environment_variables.md
@@ -95,6 +95,13 @@ Read more in [Getting Started Guide](usage.html)
 
 The **DYNACONF_{param}** prefix is set by **GLOBAL_ENV_FOR_DYNACONF** and serves only to be used in environment variables to override config values.
 
-This prefix itself can be changed to something more significant for your application, however we recommend kepping **DYNACONF_{param}** as your global env prefix.
+This prefix itself can be changed to something more significant for your application, however we recommend keeping **DYNACONF_{param}** as your global env prefix.
+
+Setting **GLOBAL_ENV_FOR_DYNACONF** to `false` will disable the prefix entirely and cause Dynaconf to load *all* environment variables. When providing `GLOBAL_ENV_FOR_DYNACONF` as parameter to **LazySettings** or **settings.configure**, make sure to give it a Python-native `False`:
+
+```python
+from dynaconf import LazySettings
+settings = LazySettings(GLOBAL_ENV_FOR_DYNACONF=False)
+```
 
 > **NOTE**: See the [Configuring dynaconf](configuration.html) section in documentation to learn more on how to use `.env` variables to configure dynaconf behavior.
diff --git a/dynaconf/loaders/env_loader.py b/dynaconf/loaders/env_loader.py
index 1098abb..311a0ee 100644
--- a/dynaconf/loaders/env_loader.py
+++ b/dynaconf/loaders/env_loader.py
@@ -12,7 +12,7 @@ def load(obj, env=None, silent=True, key=None):
     `DYNACONF_` (default global) or `$(GLOBAL_ENV_FOR_DYNACONF)_`
     """
     global_env = obj.get('GLOBAL_ENV_FOR_DYNACONF')
-    if global_env.upper() != 'DYNACONF':
+    if global_env is False or global_env.upper() != 'DYNACONF':
         load_from_env(
             IDENTIFIER + '_global',
             key,
@@ -32,12 +32,14 @@ def load(obj, env=None, silent=True, key=None):
 
 
 def load_from_env(identifier, key, env, obj, silent):
-    env = env.upper()  # noqa
-    env_ = '{0}_'.format(env)  # noqa
+    env_ = ""
+    if env is not False:
+        env = env.upper()
+        env_ = '{0}_'.format(env)
     try:
         if key:
             value = os.environ.get(
-                '{0}_{1}'.format(env, key)
+                '{0}{1}'.format(env_, key)
             )
             if value:
                 obj.logger.debug(
@@ -49,8 +51,9 @@ def load_from_env(identifier, key, env, obj, silent):
                 )
                 obj.set(key, value, loader_identifier=identifier, tomlfy=True)
         else:
+            trim_len = len(env_)
             data = {
-                key.partition(env_)[-1]: parse_conf_data(data, tomlfy=True)
+                key[trim_len:]: parse_conf_data(data, tomlfy=True)
                 for key, data
                 in os.environ.items()
                 if key.startswith(env_)
diff --git a/example/global_env_prefix/.env b/example/global_env_prefix/.env
new file mode 100644
index 0000000..619b279
--- /dev/null
+++ b/example/global_env_prefix/.env
@@ -0,0 +1,9 @@
+# config vars
+EXAMPLE_VAR1=example_var1
+EXAMPLE_VAR2=example_var2
+
+_VAR1=_var1
+_VAR2=_var2
+
+VAR1=var1
+VAR2=var2
diff --git a/example/global_env_prefix/app.py b/example/global_env_prefix/app.py
new file mode 100644
index 0000000..4333650
--- /dev/null
+++ b/example/global_env_prefix/app.py
@@ -0,0 +1,16 @@
+from dynaconf import settings
+
+print('EXAMPLE_ prefix')
+settings.configure(GLOBAL_ENV_FOR_DYNACONF="EXAMPLE")
+print(settings.VAR1)
+print(settings.VAR2)
+
+print('_ prefix')
+settings.configure(GLOBAL_ENV_FOR_DYNACONF="")
+print(settings.VAR1)
+print(settings.VAR2)
+
+print('no prefix at all')
+settings.configure(GLOBAL_ENV_FOR_DYNACONF=False)
+print(settings.VAR1)
+print(settings.VAR2)


Test patch:
diff --git a/tests/test_env_loader.py b/tests/test_env_loader.py
index 76dda9a..5e4c8cc 100644
--- a/tests/test_env_loader.py
+++ b/tests/test_env_loader.py
@@ -1,6 +1,6 @@
 import os
 import pytest
-from dynaconf.loaders.env_loader import load
+from dynaconf.loaders.env_loader import load, load_from_env
 from dynaconf import settings  # noqa
 
 # GLOBAL ENV VARS
@@ -100,3 +100,39 @@ def test_cleaner():
     settings.clean()
     with pytest.raises(AttributeError):
         assert settings.HOSTNAME == 'host.com'
+
+
+def test_empty_string_prefix():
+    os.environ['_VALUE'] = 'underscored'
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        env="",
+        obj=settings,
+        silent=True
+    )
+    assert settings.VALUE == 'underscored'
+
+
+def test_no_prefix():
+    os.environ['VALUE'] = 'no_prefix'
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        env=False,
+        obj=settings,
+        silent=True
+    )
+    assert settings.VALUE == 'no_prefix'
+
+
+def test_none_as_string_prefix():
+    os.environ['NONE_VALUE'] = 'none as prefix'
+    load_from_env(
+        identifier="env_global",
+        key=None,
+        env="none",
+        obj=settings,
+        silent=True
+    )
+    assert settings.VALUE == 'none as prefix'