We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
~/.local/etc/mindsdb and ~/.local/var/lib/mindsdb have been created in current working directory
**Your Environment**

* Python version: 3.7.6
* Pip version: 19.2.3
* Operating system: MacOS 10.15.7
* Python environment used (e.g. venv, conda):  venv
* Mindsdb version you tried to install:2.13.8 (staging)

**Bug description**
~/.local/etc/mindsdb and ~/.local/var/lib/mindsdb have been created in current working directory instead of creating
.local/etc/mindsdb and .local/var/lib/mindsdb in user home directory


**To Reproduce**
1. Create next directories and revoke `write` permissions from current user for all of these dirs:
            f'{mindsdb_path}/etc/',
            f'{mindsdb_path}/var/'
            '/etc/mindsdb',
             '/var/lib/mindsdb'

**Expected behavior**
.local/etc/mindsdb and .local/var/lib/mindsdb created in user home directory

**Actual behavior**
~/.local/etc/mindsdb and ~/.local/var/lib/mindsdb created in current working directory:


**Additional context**
```
mindsdb_venv) ~/repos/MindsDB/mindsdb itsyplen$ python -m mindsdb
Athena Datasource is not available by default. If you wish to use it, please install mindsdb_native[extra_data_sources]
SnowflakeDS Datasource is not available by default. If you wish to use it, please install mindsdb_native[snowflake]
Google Cloud Storage Datasource is not available by default. If you wish to use it, please install mindsdb_native[extra_data_sources]
Configuration file:
   ~/.local/etc/mindsdb/config.json
Storage path:
   /Users/itsyplen/repos/MindsDB/mindsdb/~/.local/etc/mindsdb/~/.local/var/lib/mindsdb
Versions:
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mindsdb/utilities/fs.py`
Content:
```
1 import inspect
2 import os
3 import time
4 from pathlib import Path
5 import json
6 import shutil
7 import pickle
8 from distutils.version import LooseVersion
9 import logging
10 
11 
12 def create_directory(path):
13     path = Path(path)
14     path.mkdir(mode=0o777, exist_ok=True, parents=True)
15 
16 
17 def get_paths():
18     this_file_path = os.path.abspath(inspect.getfile(inspect.currentframe()))
19     mindsdb_path = os.path.abspath(Path(this_file_path).parent.parent.parent)
20 
21     tuples = [
22         (
23             f'{mindsdb_path}/etc/',
24             f'{mindsdb_path}/var/'
25         )
26     ]
27 
28     # if windows
29     if os.name == 'nt':
30         tuples.extend([
31             (
32                 os.path.join(os.environ['APPDATA'], 'mindsdb'),
33                 os.path.join(os.environ['APPDATA'], 'mindsdb'),
34             )
35         ])
36     else:
37         tuples.extend([
38             (
39                 '/etc/mindsdb',
40                 '/var/lib/mindsdb'
41             ),
42             (
43                 '~/.local/etc/mindsdb',
44                 '~/.local/var/lib/mindsdb'
45             )
46         ])
47 
48     return tuples
49 
50 
51 def get_or_create_dir_struct():
52     for tup in get_paths():
53         try:
54             for dir in tup:
55                 assert(os.path.exists(dir))
56                 assert(os.access(dir, os.W_OK) is True)
57 
58             config_dir = tup[0]
59             if 'DEV_CONFIG_PATH' in os.environ:
60                 config_dir = os.environ['DEV_CONFIG_PATH']
61 
62             return config_dir, tup[1]
63         except Exception:
64             pass
65 
66     for tup in get_paths():
67         try:
68             for dir in tup:
69                 create_directory(dir)
70                 assert(os.access(dir, os.W_OK) is True)
71 
72             config_dir = tup[0]
73             if 'DEV_CONFIG_PATH' in os.environ:
74                 config_dir = os.environ['DEV_CONFIG_PATH']
75 
76             return config_dir, tup[1]
77 
78         except Exception:
79             pass
80 
81     raise Exception('MindsDB storage directory does not exist and could not be created')
82 
83 
84 def do_init_migration(paths):
85     ''' That initial migration for storage structure. Should be called once after user updates to 2.8.0.
86         When we decide all active users has update (after a month?), this function can be removed.
87     '''
88     # move predictors files by their directories
89     endings = [
90         '_heavy_model_metadata.pickle',
91         '_light_model_metadata.pickle',
92         '_lightwood_data'
93     ]
94     for ending in endings:
95         for p in Path(paths['predictors']).iterdir():
96             if p.is_file() and p.name.endswith(ending):
97                 predictor_name = p.name[:-len(ending)]
98                 predictor_path = Path(paths['predictors']).joinpath(predictor_name)
99                 create_directory(predictor_path)
100                 new_file_name = ending[1:]
101                 shutil.move(
102                     str(p),
103                     str(predictor_path.joinpath(new_file_name))
104                 )
105                 if new_file_name == 'light_model_metadata.pickle':
106                     with open(str(predictor_path.joinpath(new_file_name)), 'rb') as fp:
107                         lmd = pickle.load(fp)
108 
109                     if 'ludwig_data' in lmd and 'ludwig_save_path' in lmd['ludwig_data']:
110                         lmd['ludwig_data']['ludwig_save_path'] = os.path.join(paths['predictors'], lmd['name'], 'ludwig_data')
111 
112                     if 'lightwood_data' in lmd and 'save_path' in lmd['lightwood_data']:
113                         lmd['lightwood_data']['save_path'] = os.path.join(paths['predictors'], lmd['name'], 'lightwood_data')
114 
115                     with open(os.path.join(paths['predictors'], lmd['name'], 'light_model_metadata.pickle'), 'wb') as fp:
116                         pickle.dump(lmd, fp, protocol=pickle.HIGHEST_PROTOCOL)
117 
118     for p in Path(paths['predictors']).iterdir():
119         if p.is_file() and p.name != 'start.mdb_base':
120             p.unlink()
121 
122     # mopve each datasource files from ds_name/datasource/{file} to ds_name/{file}
123     for p in Path(paths['datasources']).iterdir():
124         if p.is_dir():
125             datasource_folder = p.joinpath('datasource')
126             if datasource_folder.is_dir():
127                 for f in datasource_folder.iterdir():
128                     shutil.move(
129                         str(f),
130                         str(p.joinpath(f.name))
131                     )
132                 shutil.rmtree(datasource_folder)
133 
134 
135 def update_versions_file(config, versions):
136     versions_file_path = os.path.join(config.paths['root'], 'versions.json')
137     old_versions = {}
138     if Path(versions_file_path).is_file():
139         try:
140             with open(versions_file_path, 'rt') as f:
141                 old_versions = json.loads(f.read())
142         except Exception:
143             pass
144 
145     # do here anything for update
146     if len(old_versions) == 0:
147         do_init_migration(config.paths)
148 
149     with open(versions_file_path, 'wt') as f:
150         json.dump(versions, f, indent=4, sort_keys=True)
151 
152 
153 def create_dirs_recursive(path):
154     if isinstance(path, dict):
155         for p in path.values():
156             create_dirs_recursive(p)
157     elif isinstance(path, str):
158         create_directory(path)
159     else:
160         raise ValueError(f'Wrong path: {path}')
161 
162 
163 def archive_obsolete_predictors(config, old_version):
164     ''' move all predictors trained on mindsdb with version less than
165         old_version to folder for obsolete predictors
166 
167         Predictors are outdated in:
168         v2.11.0 - in mindsdb_native added ['data_analysis_v2']['columns']
169     '''
170     obsolete_predictors = []
171     obsolete_predictors_dir = config.paths['obsolete']['predictors']
172     for f in Path(config.paths['predictors']).iterdir():
173         if f.is_dir():
174             if not f.joinpath('versions.json').is_file():
175                 obsolete_predictors.append(f.name)
176             else:
177                 with open(f.joinpath('versions.json'), 'rt') as vf:
178                     versions = json.loads(vf.read())
179                 if LooseVersion(versions['mindsdb']) < LooseVersion(old_version):
180                     obsolete_predictors.append(f.name)
181     if len(obsolete_predictors) > 0:
182         print('These predictors are outdated and moved to {storage_dir}/obsolete/ folder:')
183         for p in obsolete_predictors:
184             print(f' - {p}')
185             new_path = Path(obsolete_predictors_dir).joinpath(p)
186             if Path(obsolete_predictors_dir).joinpath(p).is_dir():
187                 i = 1
188                 while Path(obsolete_predictors_dir).joinpath(f'{p}_{i}').is_dir():
189                     i += 1
190                 new_path = Path(obsolete_predictors_dir).joinpath(f'{p}_{i}')
191 
192             shutil.move(
193                 Path(config.paths['predictors']).joinpath(p),
194                 new_path
195             )
196 
197 
198 def remove_corrupted_predictors(config, mindsdb_native):
199     ''' Checking that all predictors can be loaded.
200         If not - then move such predictir to {storage_dir}/tmp/corrupted_predictors
201     '''
202     for p in [x for x in Path(config.paths['predictors']).iterdir() if x.is_dir()]:
203         model_name = p.name
204         try:
205             mindsdb_native.get_model_data(model_name)
206         except Exception as e:
207             log = logging.getLogger('mindsdb.main')
208             log.error(f"Error: predictor '{model_name}' corrupted. Move predictor data to '{{storage_dir}}/tmp/corrupted_predictors' dir.")
209             log.error(f"Reason is: {e}")
210             corrupted_predictors_dir = Path(config.paths['tmp']).joinpath('corrupted_predictors')
211             create_directory(corrupted_predictors_dir)
212             shutil.move(
213                 str(p),
214                 str(corrupted_predictors_dir.joinpath( model_name + str(int(time.time())) ))
215             )
216
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mindsdb/utilities/fs.py b/mindsdb/utilities/fs.py
--- a/mindsdb/utilities/fs.py
+++ b/mindsdb/utilities/fs.py
@@ -40,8 +40,8 @@
                 '/var/lib/mindsdb'
             ),
             (
-                '~/.local/etc/mindsdb',
-                '~/.local/var/lib/mindsdb'
+                '{}/.local/etc/mindsdb'.format(Path.home()),
+                '{}/.local/var/lib/mindsdb'.format(Path.home())
             )
         ])
 
@@ -51,9 +51,9 @@
 def get_or_create_dir_struct():
     for tup in get_paths():
         try:
-            for dir in tup:
-                assert(os.path.exists(dir))
-                assert(os.access(dir, os.W_OK) is True)
+            for _dir in tup:
+                assert os.path.exists(_dir)
+                assert os.access(_dir, os.W_OK) is True
 
             config_dir = tup[0]
             if 'DEV_CONFIG_PATH' in os.environ:
@@ -65,9 +65,9 @@
 
     for tup in get_paths():
         try:
-            for dir in tup:
-                create_directory(dir)
-                assert(os.access(dir, os.W_OK) is True)
+            for _dir in tup:
+                create_directory(_dir)
+                assert os.access(_dir, os.W_OK) is True
 
             config_dir = tup[0]
             if 'DEV_CONFIG_PATH' in os.environ:

{"golden_diff": "diff --git a/mindsdb/utilities/fs.py b/mindsdb/utilities/fs.py\n--- a/mindsdb/utilities/fs.py\n+++ b/mindsdb/utilities/fs.py\n@@ -40,8 +40,8 @@\n                 '/var/lib/mindsdb'\n             ),\n             (\n-                '~/.local/etc/mindsdb',\n-                '~/.local/var/lib/mindsdb'\n+                '{}/.local/etc/mindsdb'.format(Path.home()),\n+                '{}/.local/var/lib/mindsdb'.format(Path.home())\n             )\n         ])\n \n@@ -51,9 +51,9 @@\n def get_or_create_dir_struct():\n     for tup in get_paths():\n         try:\n-            for dir in tup:\n-                assert(os.path.exists(dir))\n-                assert(os.access(dir, os.W_OK) is True)\n+            for _dir in tup:\n+                assert os.path.exists(_dir)\n+                assert os.access(_dir, os.W_OK) is True\n \n             config_dir = tup[0]\n             if 'DEV_CONFIG_PATH' in os.environ:\n@@ -65,9 +65,9 @@\n \n     for tup in get_paths():\n         try:\n-            for dir in tup:\n-                create_directory(dir)\n-                assert(os.access(dir, os.W_OK) is True)\n+            for _dir in tup:\n+                create_directory(_dir)\n+                assert os.access(_dir, os.W_OK) is True\n \n             config_dir = tup[0]\n             if 'DEV_CONFIG_PATH' in os.environ:\n", "issue": "~/.local/etc/mindsdb and ~/.local/var/lib/mindsdb have been created in current working directory\n**Your Environment**\r\n\r\n* Python version: 3.7.6\r\n* Pip version: 19.2.3\r\n* Operating system: MacOS 10.15.7\r\n* Python environment used (e.g. venv, conda):  venv\r\n* Mindsdb version you tried to install:2.13.8 (staging)\r\n\r\n**Bug description**\r\n~/.local/etc/mindsdb and ~/.local/var/lib/mindsdb have been created in current working directory instead of creating\r\n.local/etc/mindsdb and .local/var/lib/mindsdb in user home directory\r\n\r\n\r\n**To Reproduce**\r\n1. Create next directories and revoke `write` permissions from current user for all of these dirs:\r\n            f'{mindsdb_path}/etc/',\r\n            f'{mindsdb_path}/var/'\r\n            '/etc/mindsdb',\r\n             '/var/lib/mindsdb'\r\n\r\n**Expected behavior**\r\n.local/etc/mindsdb and .local/var/lib/mindsdb created in user home directory\r\n\r\n**Actual behavior**\r\n~/.local/etc/mindsdb and ~/.local/var/lib/mindsdb created in current working directory:\r\n\r\n\r\n**Additional context**\r\n```\r\nmindsdb_venv) ~/repos/MindsDB/mindsdb itsyplen$ python -m mindsdb\r\nAthena Datasource is not available by default. If you wish to use it, please install mindsdb_native[extra_data_sources]\r\nSnowflakeDS Datasource is not available by default. If you wish to use it, please install mindsdb_native[snowflake]\r\nGoogle Cloud Storage Datasource is not available by default. If you wish to use it, please install mindsdb_native[extra_data_sources]\r\nConfiguration file:\r\n   ~/.local/etc/mindsdb/config.json\r\nStorage path:\r\n   /Users/itsyplen/repos/MindsDB/mindsdb/~/.local/etc/mindsdb/~/.local/var/lib/mindsdb\r\nVersions:\r\n```\r\n\n", "before_files": [{"content": "import inspect\nimport os\nimport time\nfrom pathlib import Path\nimport json\nimport shutil\nimport pickle\nfrom distutils.version import LooseVersion\nimport logging\n\n\ndef create_directory(path):\n    path = Path(path)\n    path.mkdir(mode=0o777, exist_ok=True, parents=True)\n\n\ndef get_paths():\n    this_file_path = os.path.abspath(inspect.getfile(inspect.currentframe()))\n    mindsdb_path = os.path.abspath(Path(this_file_path).parent.parent.parent)\n\n    tuples = [\n        (\n            f'{mindsdb_path}/etc/',\n            f'{mindsdb_path}/var/'\n        )\n    ]\n\n    # if windows\n    if os.name == 'nt':\n        tuples.extend([\n            (\n                os.path.join(os.environ['APPDATA'], 'mindsdb'),\n                os.path.join(os.environ['APPDATA'], 'mindsdb'),\n            )\n        ])\n    else:\n        tuples.extend([\n            (\n                '/etc/mindsdb',\n                '/var/lib/mindsdb'\n            ),\n            (\n                '~/.local/etc/mindsdb',\n                '~/.local/var/lib/mindsdb'\n            )\n        ])\n\n    return tuples\n\n\ndef get_or_create_dir_struct():\n    for tup in get_paths():\n        try:\n            for dir in tup:\n                assert(os.path.exists(dir))\n                assert(os.access(dir, os.W_OK) is True)\n\n            config_dir = tup[0]\n            if 'DEV_CONFIG_PATH' in os.environ:\n                config_dir = os.environ['DEV_CONFIG_PATH']\n\n            return config_dir, tup[1]\n        except Exception:\n            pass\n\n    for tup in get_paths():\n        try:\n            for dir in tup:\n                create_directory(dir)\n                assert(os.access(dir, os.W_OK) is True)\n\n            config_dir = tup[0]\n            if 'DEV_CONFIG_PATH' in os.environ:\n                config_dir = os.environ['DEV_CONFIG_PATH']\n\n            return config_dir, tup[1]\n\n        except Exception:\n            pass\n\n    raise Exception('MindsDB storage directory does not exist and could not be created')\n\n\ndef do_init_migration(paths):\n    ''' That initial migration for storage structure. Should be called once after user updates to 2.8.0.\n        When we decide all active users has update (after a month?), this function can be removed.\n    '''\n    # move predictors files by their directories\n    endings = [\n        '_heavy_model_metadata.pickle',\n        '_light_model_metadata.pickle',\n        '_lightwood_data'\n    ]\n    for ending in endings:\n        for p in Path(paths['predictors']).iterdir():\n            if p.is_file() and p.name.endswith(ending):\n                predictor_name = p.name[:-len(ending)]\n                predictor_path = Path(paths['predictors']).joinpath(predictor_name)\n                create_directory(predictor_path)\n                new_file_name = ending[1:]\n                shutil.move(\n                    str(p),\n                    str(predictor_path.joinpath(new_file_name))\n                )\n                if new_file_name == 'light_model_metadata.pickle':\n                    with open(str(predictor_path.joinpath(new_file_name)), 'rb') as fp:\n                        lmd = pickle.load(fp)\n\n                    if 'ludwig_data' in lmd and 'ludwig_save_path' in lmd['ludwig_data']:\n                        lmd['ludwig_data']['ludwig_save_path'] = os.path.join(paths['predictors'], lmd['name'], 'ludwig_data')\n\n                    if 'lightwood_data' in lmd and 'save_path' in lmd['lightwood_data']:\n                        lmd['lightwood_data']['save_path'] = os.path.join(paths['predictors'], lmd['name'], 'lightwood_data')\n\n                    with open(os.path.join(paths['predictors'], lmd['name'], 'light_model_metadata.pickle'), 'wb') as fp:\n                        pickle.dump(lmd, fp, protocol=pickle.HIGHEST_PROTOCOL)\n\n    for p in Path(paths['predictors']).iterdir():\n        if p.is_file() and p.name != 'start.mdb_base':\n            p.unlink()\n\n    # mopve each datasource files from ds_name/datasource/{file} to ds_name/{file}\n    for p in Path(paths['datasources']).iterdir():\n        if p.is_dir():\n            datasource_folder = p.joinpath('datasource')\n            if datasource_folder.is_dir():\n                for f in datasource_folder.iterdir():\n                    shutil.move(\n                        str(f),\n                        str(p.joinpath(f.name))\n                    )\n                shutil.rmtree(datasource_folder)\n\n\ndef update_versions_file(config, versions):\n    versions_file_path = os.path.join(config.paths['root'], 'versions.json')\n    old_versions = {}\n    if Path(versions_file_path).is_file():\n        try:\n            with open(versions_file_path, 'rt') as f:\n                old_versions = json.loads(f.read())\n        except Exception:\n            pass\n\n    # do here anything for update\n    if len(old_versions) == 0:\n        do_init_migration(config.paths)\n\n    with open(versions_file_path, 'wt') as f:\n        json.dump(versions, f, indent=4, sort_keys=True)\n\n\ndef create_dirs_recursive(path):\n    if isinstance(path, dict):\n        for p in path.values():\n            create_dirs_recursive(p)\n    elif isinstance(path, str):\n        create_directory(path)\n    else:\n        raise ValueError(f'Wrong path: {path}')\n\n\ndef archive_obsolete_predictors(config, old_version):\n    ''' move all predictors trained on mindsdb with version less than\n        old_version to folder for obsolete predictors\n\n        Predictors are outdated in:\n        v2.11.0 - in mindsdb_native added ['data_analysis_v2']['columns']\n    '''\n    obsolete_predictors = []\n    obsolete_predictors_dir = config.paths['obsolete']['predictors']\n    for f in Path(config.paths['predictors']).iterdir():\n        if f.is_dir():\n            if not f.joinpath('versions.json').is_file():\n                obsolete_predictors.append(f.name)\n            else:\n                with open(f.joinpath('versions.json'), 'rt') as vf:\n                    versions = json.loads(vf.read())\n                if LooseVersion(versions['mindsdb']) < LooseVersion(old_version):\n                    obsolete_predictors.append(f.name)\n    if len(obsolete_predictors) > 0:\n        print('These predictors are outdated and moved to {storage_dir}/obsolete/ folder:')\n        for p in obsolete_predictors:\n            print(f' - {p}')\n            new_path = Path(obsolete_predictors_dir).joinpath(p)\n            if Path(obsolete_predictors_dir).joinpath(p).is_dir():\n                i = 1\n                while Path(obsolete_predictors_dir).joinpath(f'{p}_{i}').is_dir():\n                    i += 1\n                new_path = Path(obsolete_predictors_dir).joinpath(f'{p}_{i}')\n\n            shutil.move(\n                Path(config.paths['predictors']).joinpath(p),\n                new_path\n            )\n\n\ndef remove_corrupted_predictors(config, mindsdb_native):\n    ''' Checking that all predictors can be loaded.\n        If not - then move such predictir to {storage_dir}/tmp/corrupted_predictors\n    '''\n    for p in [x for x in Path(config.paths['predictors']).iterdir() if x.is_dir()]:\n        model_name = p.name\n        try:\n            mindsdb_native.get_model_data(model_name)\n        except Exception as e:\n            log = logging.getLogger('mindsdb.main')\n            log.error(f\"Error: predictor '{model_name}' corrupted. Move predictor data to '{{storage_dir}}/tmp/corrupted_predictors' dir.\")\n            log.error(f\"Reason is: {e}\")\n            corrupted_predictors_dir = Path(config.paths['tmp']).joinpath('corrupted_predictors')\n            create_directory(corrupted_predictors_dir)\n            shutil.move(\n                str(p),\n                str(corrupted_predictors_dir.joinpath( model_name + str(int(time.time())) ))\n            )\n", "path": "mindsdb/utilities/fs.py"}], "after_files": [{"content": "import inspect\nimport os\nimport time\nfrom pathlib import Path\nimport json\nimport shutil\nimport pickle\nfrom distutils.version import LooseVersion\nimport logging\n\n\ndef create_directory(path):\n    path = Path(path)\n    path.mkdir(mode=0o777, exist_ok=True, parents=True)\n\n\ndef get_paths():\n    this_file_path = os.path.abspath(inspect.getfile(inspect.currentframe()))\n    mindsdb_path = os.path.abspath(Path(this_file_path).parent.parent.parent)\n\n    tuples = [\n        (\n            f'{mindsdb_path}/etc/',\n            f'{mindsdb_path}/var/'\n        )\n    ]\n\n    # if windows\n    if os.name == 'nt':\n        tuples.extend([\n            (\n                os.path.join(os.environ['APPDATA'], 'mindsdb'),\n                os.path.join(os.environ['APPDATA'], 'mindsdb'),\n            )\n        ])\n    else:\n        tuples.extend([\n            (\n                '/etc/mindsdb',\n                '/var/lib/mindsdb'\n            ),\n            (\n                '{}/.local/etc/mindsdb'.format(Path.home()),\n                '{}/.local/var/lib/mindsdb'.format(Path.home())\n            )\n        ])\n\n    return tuples\n\n\ndef get_or_create_dir_struct():\n    for tup in get_paths():\n        try:\n            for _dir in tup:\n                assert os.path.exists(_dir)\n                assert os.access(_dir, os.W_OK) is True\n\n            config_dir = tup[0]\n            if 'DEV_CONFIG_PATH' in os.environ:\n                config_dir = os.environ['DEV_CONFIG_PATH']\n\n            return config_dir, tup[1]\n        except Exception:\n            pass\n\n    for tup in get_paths():\n        try:\n            for _dir in tup:\n                create_directory(_dir)\n                assert os.access(_dir, os.W_OK) is True\n\n            config_dir = tup[0]\n            if 'DEV_CONFIG_PATH' in os.environ:\n                config_dir = os.environ['DEV_CONFIG_PATH']\n\n            return config_dir, tup[1]\n\n        except Exception:\n            pass\n\n    raise Exception('MindsDB storage directory does not exist and could not be created')\n\n\ndef do_init_migration(paths):\n    ''' That initial migration for storage structure. Should be called once after user updates to 2.8.0.\n        When we decide all active users has update (after a month?), this function can be removed.\n    '''\n    # move predictors files by their directories\n    endings = [\n        '_heavy_model_metadata.pickle',\n        '_light_model_metadata.pickle',\n        '_lightwood_data'\n    ]\n    for ending in endings:\n        for p in Path(paths['predictors']).iterdir():\n            if p.is_file() and p.name.endswith(ending):\n                predictor_name = p.name[:-len(ending)]\n                predictor_path = Path(paths['predictors']).joinpath(predictor_name)\n                create_directory(predictor_path)\n                new_file_name = ending[1:]\n                shutil.move(\n                    str(p),\n                    str(predictor_path.joinpath(new_file_name))\n                )\n                if new_file_name == 'light_model_metadata.pickle':\n                    with open(str(predictor_path.joinpath(new_file_name)), 'rb') as fp:\n                        lmd = pickle.load(fp)\n\n                    if 'ludwig_data' in lmd and 'ludwig_save_path' in lmd['ludwig_data']:\n                        lmd['ludwig_data']['ludwig_save_path'] = os.path.join(paths['predictors'], lmd['name'], 'ludwig_data')\n\n                    if 'lightwood_data' in lmd and 'save_path' in lmd['lightwood_data']:\n                        lmd['lightwood_data']['save_path'] = os.path.join(paths['predictors'], lmd['name'], 'lightwood_data')\n\n                    with open(os.path.join(paths['predictors'], lmd['name'], 'light_model_metadata.pickle'), 'wb') as fp:\n                        pickle.dump(lmd, fp, protocol=pickle.HIGHEST_PROTOCOL)\n\n    for p in Path(paths['predictors']).iterdir():\n        if p.is_file() and p.name != 'start.mdb_base':\n            p.unlink()\n\n    # mopve each datasource files from ds_name/datasource/{file} to ds_name/{file}\n    for p in Path(paths['datasources']).iterdir():\n        if p.is_dir():\n            datasource_folder = p.joinpath('datasource')\n            if datasource_folder.is_dir():\n                for f in datasource_folder.iterdir():\n                    shutil.move(\n                        str(f),\n                        str(p.joinpath(f.name))\n                    )\n                shutil.rmtree(datasource_folder)\n\n\ndef update_versions_file(config, versions):\n    versions_file_path = os.path.join(config.paths['root'], 'versions.json')\n    old_versions = {}\n    if Path(versions_file_path).is_file():\n        try:\n            with open(versions_file_path, 'rt') as f:\n                old_versions = json.loads(f.read())\n        except Exception:\n            pass\n\n    # do here anything for update\n    if len(old_versions) == 0:\n        do_init_migration(config.paths)\n\n    with open(versions_file_path, 'wt') as f:\n        json.dump(versions, f, indent=4, sort_keys=True)\n\n\ndef create_dirs_recursive(path):\n    if isinstance(path, dict):\n        for p in path.values():\n            create_dirs_recursive(p)\n    elif isinstance(path, str):\n        create_directory(path)\n    else:\n        raise ValueError(f'Wrong path: {path}')\n\n\ndef archive_obsolete_predictors(config, old_version):\n    ''' move all predictors trained on mindsdb with version less than\n        old_version to folder for obsolete predictors\n\n        Predictors are outdated in:\n        v2.11.0 - in mindsdb_native added ['data_analysis_v2']['columns']\n    '''\n    obsolete_predictors = []\n    obsolete_predictors_dir = config.paths['obsolete']['predictors']\n    for f in Path(config.paths['predictors']).iterdir():\n        if f.is_dir():\n            if not f.joinpath('versions.json').is_file():\n                obsolete_predictors.append(f.name)\n            else:\n                with open(f.joinpath('versions.json'), 'rt') as vf:\n                    versions = json.loads(vf.read())\n                if LooseVersion(versions['mindsdb']) < LooseVersion(old_version):\n                    obsolete_predictors.append(f.name)\n    if len(obsolete_predictors) > 0:\n        print('These predictors are outdated and moved to {storage_dir}/obsolete/ folder:')\n        for p in obsolete_predictors:\n            print(f' - {p}')\n            new_path = Path(obsolete_predictors_dir).joinpath(p)\n            if Path(obsolete_predictors_dir).joinpath(p).is_dir():\n                i = 1\n                while Path(obsolete_predictors_dir).joinpath(f'{p}_{i}').is_dir():\n                    i += 1\n                new_path = Path(obsolete_predictors_dir).joinpath(f'{p}_{i}')\n\n            shutil.move(\n                Path(config.paths['predictors']).joinpath(p),\n                new_path\n            )\n\n\ndef remove_corrupted_predictors(config, mindsdb_native):\n    ''' Checking that all predictors can be loaded.\n        If not - then move such predictir to {storage_dir}/tmp/corrupted_predictors\n    '''\n    for p in [x for x in Path(config.paths['predictors']).iterdir() if x.is_dir()]:\n        model_name = p.name\n        try:\n            mindsdb_native.get_model_data(model_name)\n        except Exception as e:\n            log = logging.getLogger('mindsdb.main')\n            log.error(f\"Error: predictor '{model_name}' corrupted. Move predictor data to '{{storage_dir}}/tmp/corrupted_predictors' dir.\")\n            log.error(f\"Reason is: {e}\")\n            corrupted_predictors_dir = Path(config.paths['tmp']).joinpath('corrupted_predictors')\n            create_directory(corrupted_predictors_dir)\n            shutil.move(\n                str(p),\n                str(corrupted_predictors_dir.joinpath( model_name + str(int(time.time())) ))\n            )\n", "path": "mindsdb/utilities/fs.py"}]}