Repository: deeppavlov/DeepPavlov

Issue:
Make ROOT_PATH, MODELS_PATH and DOWNLOADS_PATH environment variables
All config files I've seen so far have the following variables:
```
"ROOT_PATH": "~/.deeppavlov",
"DOWNLOADS_PATH": "{ROOT_PATH}/downloads",
"MODELS_PATH": "{ROOT_PATH}/models"
```
Should we make them environment variables?
This would be better for the following reasons:
1. No need to define the same variables across all configs
1. No need to redefine variables for your system. For example, I do not store source code and downloads/models at same place (cause of their huge size), so I need to change configs for me and change them _back_ to make PR (that is kind of ridiculous). If these variables were in the environment, I'd have to change them only one time - after deeppavlov installation.
1. Make configs working directory independent (no '~/'-paths)


Discussion:
If someone implements this, change variable names to something specific like "DEEPPAVLOV_ROOT_PATH" in order to avoid name clashes.
Proposed solution: environment variable `DP_VARIABLE_NAME` should be interpreted as `VARIABLE_NAME` variable in configs
Another solution: use syntax like `ENV:VARIABLE_NAME` in configs to reference any env variable

Resolving patch:
diff --git a/deeppavlov/core/commands/utils.py b/deeppavlov/core/commands/utils.py
--- a/deeppavlov/core/commands/utils.py
+++ b/deeppavlov/core/commands/utils.py
@@ -11,6 +11,7 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+import os
 from pathlib import Path
 from typing import Union, Dict, TypeVar
 
@@ -38,9 +39,12 @@ def parse_config(config: Union[str, Path, dict]) -> dict:
         config = read_json(find_config(config))
 
     variables = {
-        'DEEPPAVLOV_PATH': Path(__file__).parent.parent.parent
+        'DEEPPAVLOV_PATH': os.getenv(f'DP_DEEPPAVLOV_PATH', Path(__file__).parent.parent.parent)
     }
     for name, value in config.get('metadata', {}).get('variables', {}).items():
+        env_name = f'DP_{name}'
+        if env_name in os.environ:
+            value = os.getenv(env_name)
         variables[name] = value.format(**variables)
 
     return _parse_config_property(config, variables)


Test patch:
diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py
--- a/tests/test_quick_start.py
+++ b/tests/test_quick_start.py
@@ -247,10 +247,6 @@ def download_config(config_path):
     config.setdefault('train', {}).setdefault('pytest_epochs', 1)
     _override_with_test_values(config)
 
-    config_vars = config.setdefault('metadata', {}).setdefault('variables', {})
-    config_vars['ROOT_PATH'] = str(download_path)
-    config_vars['CONFIGS_PATH'] = str(test_configs_path)
-
     config_path = test_configs_path / config_path
     config_path.parent.mkdir(exist_ok=True, parents=True)
     with config_path.open("w", encoding='utf8') as fout:
@@ -277,6 +273,9 @@ def setup_module():
         for (config_path, _, _), _ in conf_dict.items():
             download_config(config_path)
 
+    os.environ['DP_ROOT_PATH'] = str(download_path)
+    os.environ['DP_CONFIGS_PATH'] = str(test_configs_path)
+
     if cache_dir:
         cache_dir.mkdir(parents=True, exist_ok=True)
         os.environ['DP_CACHE_DIR'] = str(cache_dir.resolve())