squirrels 0.3.3__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of squirrels might be problematic. Click here for more details.
- squirrels/__init__.py +7 -3
- squirrels/_api_response_models.py +96 -72
- squirrels/_api_server.py +375 -201
- squirrels/_authenticator.py +23 -22
- squirrels/_command_line.py +70 -46
- squirrels/_connection_set.py +23 -25
- squirrels/_constants.py +29 -78
- squirrels/_dashboards_io.py +61 -0
- squirrels/_environcfg.py +53 -50
- squirrels/_initializer.py +184 -141
- squirrels/_manifest.py +168 -195
- squirrels/_models.py +159 -292
- squirrels/_package_loader.py +7 -8
- squirrels/_parameter_configs.py +173 -141
- squirrels/_parameter_sets.py +49 -38
- squirrels/_py_module.py +7 -7
- squirrels/_seeds.py +13 -12
- squirrels/_utils.py +114 -54
- squirrels/_version.py +1 -1
- squirrels/arguments/init_time_args.py +16 -10
- squirrels/arguments/run_time_args.py +89 -24
- squirrels/dashboards.py +82 -0
- squirrels/data_sources.py +212 -232
- squirrels/dateutils.py +29 -26
- squirrels/package_data/assets/index.css +1 -1
- squirrels/package_data/assets/index.js +27 -18
- squirrels/package_data/base_project/.gitignore +2 -2
- squirrels/package_data/base_project/connections.yml +1 -1
- squirrels/package_data/base_project/dashboards/dashboard_example.py +32 -0
- squirrels/package_data/base_project/dashboards.yml +10 -0
- squirrels/package_data/base_project/docker/.dockerignore +9 -4
- squirrels/package_data/base_project/docker/Dockerfile +7 -6
- squirrels/package_data/base_project/docker/compose.yml +1 -1
- squirrels/package_data/base_project/env.yml +2 -2
- squirrels/package_data/base_project/models/dbviews/{database_view1.py → dbview_example.py} +2 -1
- squirrels/package_data/base_project/models/dbviews/{database_view1.sql → dbview_example.sql} +3 -2
- squirrels/package_data/base_project/models/federates/{dataset_example.py → federate_example.py} +6 -6
- squirrels/package_data/base_project/models/federates/{dataset_example.sql → federate_example.sql} +1 -1
- squirrels/package_data/base_project/parameters.yml +6 -4
- squirrels/package_data/base_project/pyconfigs/auth.py +1 -1
- squirrels/package_data/base_project/pyconfigs/connections.py +1 -1
- squirrels/package_data/base_project/pyconfigs/context.py +38 -10
- squirrels/package_data/base_project/pyconfigs/parameters.py +15 -7
- squirrels/package_data/base_project/squirrels.yml.j2 +14 -7
- squirrels/package_data/templates/index.html +3 -3
- squirrels/parameter_options.py +103 -106
- squirrels/parameters.py +347 -195
- squirrels/project.py +378 -0
- squirrels/user_base.py +14 -6
- {squirrels-0.3.3.dist-info → squirrels-0.4.0.dist-info}/METADATA +9 -21
- squirrels-0.4.0.dist-info/RECORD +60 -0
- squirrels/_timer.py +0 -23
- squirrels-0.3.3.dist-info/RECORD +0 -56
- {squirrels-0.3.3.dist-info → squirrels-0.4.0.dist-info}/LICENSE +0 -0
- {squirrels-0.3.3.dist-info → squirrels-0.4.0.dist-info}/WHEEL +0 -0
- {squirrels-0.3.3.dist-info → squirrels-0.4.0.dist-info}/entry_points.txt +0 -0
squirrels/_environcfg.py
CHANGED
|
@@ -1,81 +1,84 @@
|
|
|
1
|
-
from
|
|
2
|
-
from
|
|
3
|
-
import
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Any, Callable
|
|
3
|
+
from pydantic import BaseModel, Field, field_validator, ValidationError
|
|
4
|
+
import os, yaml, time
|
|
4
5
|
|
|
5
6
|
from . import _constants as c, _utils as u
|
|
6
|
-
from ._timer import timer, time
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
_GLOBAL_SQUIRRELS_CFG_FILE2 = u.join_paths(os.path.expanduser('~'), '.squirrels', c.ENV_CONFIG_FILE)
|
|
8
|
+
_GLOBAL_SQUIRRELS_CFG_FILE = u.Path(os.path.expanduser('~'), '.squirrels', c.ENV_CONFIG_FILE)
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
11
|
+
class _UserConfig(BaseModel, extra="allow"):
|
|
12
|
+
username: str
|
|
13
|
+
password: str
|
|
14
|
+
is_internal: bool = False
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _CredentialsConfig(BaseModel):
|
|
18
|
+
username: str
|
|
19
|
+
password: str
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EnvironConfig(BaseModel):
|
|
23
|
+
users: dict[str, _UserConfig] = Field(default_factory=dict)
|
|
24
|
+
env_vars: dict[str, str] = Field(default_factory=dict)
|
|
25
|
+
credentials: dict[str, _CredentialsConfig] = Field(default_factory=dict)
|
|
26
|
+
secrets: dict[str, Any | None] = Field(default_factory=dict)
|
|
27
|
+
|
|
28
|
+
@field_validator("users", mode="before")
|
|
29
|
+
@classmethod
|
|
30
|
+
def inject_username(cls, users: dict[str, dict[str, Any]]) -> dict[str, dict[str, Any]]:
|
|
31
|
+
processed_users = {}
|
|
32
|
+
for username, user in users.items():
|
|
33
|
+
processed_users[username] = {"username": username, **user}
|
|
34
|
+
return processed_users
|
|
28
35
|
|
|
29
|
-
def get_users(self) -> dict[str,
|
|
30
|
-
return self.
|
|
36
|
+
def get_users(self) -> dict[str, _UserConfig]:
|
|
37
|
+
return self.users.copy()
|
|
31
38
|
|
|
32
39
|
def get_all_env_vars(self) -> dict[str, str]:
|
|
33
|
-
return self.
|
|
40
|
+
return self.env_vars.copy()
|
|
34
41
|
|
|
35
|
-
def get_credential(self, key:
|
|
42
|
+
def get_credential(self, key: str | None) -> tuple[str, str]:
|
|
36
43
|
if not key:
|
|
37
44
|
return "", ""
|
|
38
45
|
|
|
39
46
|
try:
|
|
40
|
-
credential = self.
|
|
47
|
+
credential = self.credentials[key]
|
|
41
48
|
except KeyError as e:
|
|
42
49
|
raise u.ConfigurationError(f'No credentials configured for "{key}"') from e
|
|
43
50
|
|
|
44
|
-
return credential
|
|
51
|
+
return credential.username, credential.password
|
|
45
52
|
|
|
46
|
-
def get_secret(self, key: str,
|
|
47
|
-
if
|
|
48
|
-
self.
|
|
49
|
-
return self.
|
|
53
|
+
def get_secret(self, key: str, default_factory: Callable[[], Any]) -> Any:
|
|
54
|
+
if self.secrets.get(key) is None:
|
|
55
|
+
self.secrets[key] = default_factory()
|
|
56
|
+
return self.secrets[key]
|
|
50
57
|
|
|
51
58
|
|
|
52
59
|
class EnvironConfigIO:
|
|
53
|
-
obj: _EnvironConfig
|
|
54
60
|
|
|
55
61
|
@classmethod
|
|
56
|
-
def
|
|
62
|
+
def load_from_file(cls, logger: u.Logger, base_path: str) -> EnvironConfig:
|
|
57
63
|
start = time.time()
|
|
58
|
-
def load_yaml(filename: str) -> dict[str, dict]:
|
|
64
|
+
def load_yaml(filename: str | Path) -> dict[str, dict]:
|
|
59
65
|
try:
|
|
60
66
|
with open(filename, 'r') as f:
|
|
61
67
|
return yaml.safe_load(f)
|
|
62
68
|
except FileNotFoundError:
|
|
63
69
|
return {}
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
proj_env_config1 = load_yaml(c.ENVIRON_CONFIG_FILE)
|
|
68
|
-
proj_env_config2 = load_yaml(c.ENV_CONFIG_FILE)
|
|
71
|
+
master_env_config = load_yaml(_GLOBAL_SQUIRRELS_CFG_FILE)
|
|
72
|
+
proj_env_config = load_yaml(Path(base_path, c.ENV_CONFIG_FILE))
|
|
69
73
|
|
|
70
|
-
for
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
master_env_config1[key].update(project_config[key])
|
|
74
|
+
for key in proj_env_config:
|
|
75
|
+
master_env_config.setdefault(key, {})
|
|
76
|
+
master_env_config[key].update(proj_env_config[key])
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
try:
|
|
79
|
+
env_cfg = EnvironConfig(**master_env_config)
|
|
80
|
+
except ValidationError as e:
|
|
81
|
+
raise u.ConfigurationError(f"Failed to process {c.ENV_CONFIG_FILE} file. " + str(e)) from e
|
|
82
|
+
|
|
83
|
+
logger.log_activity_time(f"loading {c.ENV_CONFIG_FILE} file", start)
|
|
84
|
+
return env_cfg
|
squirrels/_initializer.py
CHANGED
|
@@ -1,178 +1,221 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
|
+
from datetime import datetime
|
|
2
3
|
import inquirer, os, shutil
|
|
3
4
|
|
|
4
5
|
from . import _constants as c, _utils as u
|
|
5
6
|
|
|
6
|
-
base_proj_dir = u.
|
|
7
|
+
base_proj_dir = u.Path(os.path.dirname(__file__), c.PACKAGE_DATA_FOLDER, c.BASE_PROJECT_FOLDER)
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class Initializer:
|
|
10
|
-
def __init__(self, overwrite: bool):
|
|
11
|
+
def __init__(self, *, overwrite: bool = False):
|
|
11
12
|
self.overwrite = overwrite
|
|
12
13
|
|
|
13
|
-
def _path_exists(self, filepath:
|
|
14
|
-
|
|
15
|
-
print(f'File "{filepath}" already exists. Creation skipped.')
|
|
16
|
-
return True
|
|
17
|
-
return False
|
|
14
|
+
def _path_exists(self, filepath: u.Path) -> bool:
|
|
15
|
+
return os.path.exists(filepath)
|
|
18
16
|
|
|
19
|
-
def
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
def _files_have_same_content(self, file1: u.Path, file2: u.Path) -> bool:
|
|
18
|
+
with open(file1, 'rb') as f1, open(file2, 'rb') as f2:
|
|
19
|
+
return f1.read() == f2.read()
|
|
20
|
+
|
|
21
|
+
def _add_timestamp_to_filename(self, path: u.Path) -> u.Path:
|
|
22
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
23
|
+
new_filename = f"{path.stem}_{timestamp}{path.suffix}"
|
|
24
|
+
return path.with_name(new_filename)
|
|
25
|
+
|
|
26
|
+
def _copy_file(self, filepath: u.Path, *, src_folder: str = ""):
|
|
27
|
+
src_path = u.Path(base_proj_dir, src_folder, filepath)
|
|
28
|
+
|
|
29
|
+
dest_dir = os.path.dirname(filepath)
|
|
30
|
+
if dest_dir != "":
|
|
31
|
+
os.makedirs(dest_dir, exist_ok=True)
|
|
32
|
+
|
|
33
|
+
perform_copy = True
|
|
34
|
+
if self._path_exists(filepath):
|
|
35
|
+
old_filepath = filepath
|
|
36
|
+
if self._files_have_same_content(src_path, filepath):
|
|
37
|
+
perform_copy = False
|
|
38
|
+
extra_msg = "Skipping... file contents is same as source"
|
|
39
|
+
elif self.overwrite:
|
|
40
|
+
extra_msg = "Overwriting file..."
|
|
41
|
+
else:
|
|
42
|
+
filepath = self._add_timestamp_to_filename(old_filepath)
|
|
43
|
+
extra_msg = f'Creating file as "{filepath}" instead...'
|
|
44
|
+
print(f'File "{old_filepath}" already exists.', extra_msg)
|
|
45
|
+
else:
|
|
46
|
+
print(f'Creating file "{filepath}"...')
|
|
47
|
+
|
|
48
|
+
if perform_copy:
|
|
25
49
|
shutil.copy(src_path, filepath)
|
|
26
50
|
|
|
27
51
|
def _copy_dbview_file(self, filepath: str):
|
|
28
|
-
self._copy_file(u.
|
|
52
|
+
self._copy_file(u.Path(c.MODELS_FOLDER, c.DBVIEWS_FOLDER, filepath))
|
|
29
53
|
|
|
30
54
|
def _copy_federate_file(self, filepath: str):
|
|
31
|
-
self._copy_file(u.
|
|
55
|
+
self._copy_file(u.Path(c.MODELS_FOLDER, c.FEDERATES_FOLDER, filepath))
|
|
32
56
|
|
|
33
57
|
def _copy_database_file(self, filepath: str):
|
|
34
|
-
self._copy_file(u.
|
|
58
|
+
self._copy_file(u.Path(c.DATABASE_FOLDER, filepath))
|
|
35
59
|
|
|
36
60
|
def _copy_pyconfig_file(self, filepath: str):
|
|
37
|
-
self._copy_file(u.
|
|
61
|
+
self._copy_file(u.Path(c.PYCONFIGS_FOLDER, filepath))
|
|
38
62
|
|
|
39
63
|
def _copy_seed_file(self, filepath: str):
|
|
40
|
-
self._copy_file(u.
|
|
64
|
+
self._copy_file(u.Path(c.SEEDS_FOLDER, filepath))
|
|
65
|
+
|
|
66
|
+
def _copy_dashboard_file(self, filepath: str):
|
|
67
|
+
self._copy_file(u.Path(c.DASHBOARDS_FOLDER, filepath))
|
|
41
68
|
|
|
42
|
-
def
|
|
43
|
-
options = ["core", "connections", "parameters", "dbview", "federate", "auth", "sample_db"]
|
|
44
|
-
CORE, CONNECTIONS, PARAMETERS, DBVIEW, FEDERATE, AUTH, SAMPLE_DB = options
|
|
69
|
+
def _create_manifest_file(self, has_connections: bool, has_parameters: bool, has_dashboards: bool):
|
|
45
70
|
TMP_FOLDER = "tmp"
|
|
46
71
|
|
|
72
|
+
def get_content(file_name: Optional[str]) -> str:
|
|
73
|
+
if file_name is None:
|
|
74
|
+
return ""
|
|
75
|
+
|
|
76
|
+
yaml_path = u.Path(base_proj_dir, file_name)
|
|
77
|
+
return u.read_file(yaml_path)
|
|
78
|
+
|
|
79
|
+
file_name_dict = {
|
|
80
|
+
"parameters": c.PARAMETERS_YML_FILE if has_parameters else None,
|
|
81
|
+
"connections": c.CONNECTIONS_YML_FILE if has_connections else None,
|
|
82
|
+
"dashboards": c.DASHBOARDS_YML_FILE if has_dashboards else None
|
|
83
|
+
}
|
|
84
|
+
substitutions = {key: get_content(val) for key, val in file_name_dict.items()}
|
|
85
|
+
|
|
86
|
+
manifest_template = get_content(c.MANIFEST_JINJA_FILE)
|
|
87
|
+
manifest_content = u.render_string(manifest_template, **substitutions)
|
|
88
|
+
output_path = u.Path(base_proj_dir, TMP_FOLDER, c.MANIFEST_FILE)
|
|
89
|
+
with open(u.Path(output_path), "w") as f:
|
|
90
|
+
f.write(manifest_content)
|
|
91
|
+
|
|
92
|
+
self._copy_file(u.Path(c.MANIFEST_FILE), src_folder=TMP_FOLDER)
|
|
93
|
+
|
|
94
|
+
def init_project(self, args):
|
|
95
|
+
options = ["core", "connections", "parameters", "dbview", "federate", "dashboard", "auth"]
|
|
96
|
+
_, CONNECTIONS, PARAMETERS, DBVIEW, FEDERATE, DASHBOARD, AUTH = options
|
|
97
|
+
|
|
47
98
|
answers = { x: getattr(args, x) for x in options }
|
|
48
99
|
if not any(answers.values()):
|
|
49
|
-
|
|
50
|
-
inquirer.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
message="What's the file format for the federated model?",
|
|
69
|
-
choices=c.FILE_TYPE_CHOICES),
|
|
70
|
-
]
|
|
71
|
-
answers.update(inquirer.prompt(conditional_questions))
|
|
72
|
-
|
|
73
|
-
remaining_questions = [
|
|
74
|
-
inquirer.Confirm(AUTH,
|
|
75
|
-
message=f"Do you want to add the '{c.AUTH_FILE}' file to enable custom API authentication?" ,
|
|
76
|
-
default=False),
|
|
77
|
-
inquirer.List(SAMPLE_DB,
|
|
78
|
-
message="What sample sqlite database do you wish to use (if any)?",
|
|
79
|
-
choices= c.DATABASE_CHOICES)
|
|
100
|
+
questions = [
|
|
101
|
+
inquirer.List(
|
|
102
|
+
CONNECTIONS, message=f"How would you like to configure the database connections?", choices=c.CONF_FORMAT_CHOICES
|
|
103
|
+
),
|
|
104
|
+
inquirer.List(
|
|
105
|
+
PARAMETERS, message=f"How would you like to configure the parameters?", choices=c.CONF_FORMAT_CHOICES2
|
|
106
|
+
),
|
|
107
|
+
inquirer.List(
|
|
108
|
+
DBVIEW, message="What's the file format for the database view model?", choices=c.FILE_TYPE_CHOICES
|
|
109
|
+
),
|
|
110
|
+
inquirer.List(
|
|
111
|
+
FEDERATE, message="What's the file format for the federated model?", choices=c.FILE_TYPE_CHOICES
|
|
112
|
+
),
|
|
113
|
+
inquirer.Confirm(
|
|
114
|
+
DASHBOARD, message=f"Do you want to include a dashboard example?", default=False
|
|
115
|
+
),
|
|
116
|
+
inquirer.Confirm(
|
|
117
|
+
AUTH, message=f"Do you want to add the '{c.AUTH_FILE}' file to enable custom API authentication?", default=False
|
|
118
|
+
),
|
|
80
119
|
]
|
|
81
|
-
answers
|
|
120
|
+
answers = inquirer.prompt(questions)
|
|
121
|
+
assert isinstance(answers, dict)
|
|
82
122
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
connections_use_py = (connections_format == c.PYTHON_FORMAT)
|
|
96
|
-
|
|
97
|
-
parameters_format = answers.get(PARAMETERS)
|
|
98
|
-
parameters_use_yaml = (parameters_format == c.YML_FORMAT)
|
|
99
|
-
parameters_use_py = (parameters_format == c.PYTHON_FORMAT)
|
|
100
|
-
|
|
101
|
-
db_view_format = answers.get(DBVIEW)
|
|
102
|
-
if db_view_format == c.SQL_FILE_TYPE:
|
|
103
|
-
db_view_file = c.DATABASE_VIEW_SQL_FILE
|
|
104
|
-
elif db_view_format == c.PYTHON_FILE_TYPE:
|
|
105
|
-
db_view_file = c.DATABASE_VIEW_PY_FILE
|
|
106
|
-
else:
|
|
107
|
-
raise NotImplementedError(f"Database view format '{db_view_format}' not supported")
|
|
123
|
+
def get_answer(key, default):
|
|
124
|
+
"""
|
|
125
|
+
If key is in answers dict as None, using `.get` on a dictionary will return None even if a default is provided.
|
|
126
|
+
|
|
127
|
+
For instance, the following prints None.
|
|
128
|
+
>>> test_dict = {"key": None}
|
|
129
|
+
>>> print(test_dict.get("key", "default"))
|
|
130
|
+
|
|
131
|
+
This function will return the default value if the key is in the dict with value None.
|
|
132
|
+
"""
|
|
133
|
+
answer = answers.get(key)
|
|
134
|
+
return answer if answer is not None else default
|
|
108
135
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
136
|
+
connections_format = get_answer(CONNECTIONS, c.YML_FORMAT)
|
|
137
|
+
connections_use_yaml = (connections_format == c.YML_FORMAT)
|
|
138
|
+
connections_use_py = (connections_format == c.PYTHON_FORMAT)
|
|
139
|
+
|
|
140
|
+
parameters_format = get_answer(PARAMETERS, c.PYTHON_FORMAT)
|
|
141
|
+
parameters_use_yaml = (parameters_format == c.YML_FORMAT)
|
|
142
|
+
parameters_use_py = (parameters_format == c.PYTHON_FORMAT)
|
|
143
|
+
|
|
144
|
+
dbview_format = get_answer(DBVIEW, c.SQL_FILE_TYPE)
|
|
145
|
+
if dbview_format == c.SQL_FILE_TYPE:
|
|
146
|
+
db_view_file = c.DBVIEW_FILE_STEM + ".sql"
|
|
147
|
+
elif dbview_format == c.PYTHON_FILE_TYPE:
|
|
148
|
+
db_view_file = c.DBVIEW_FILE_STEM + ".py"
|
|
149
|
+
else:
|
|
150
|
+
raise NotImplementedError(f"Dbview model format '{dbview_format}' not supported")
|
|
116
151
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
file_name_dict = {
|
|
126
|
-
"parameters": c.PARAMETERS_YML_FILE if parameters_use_yaml else None,
|
|
127
|
-
"connections": c.CONNECTIONS_YML_FILE if connections_use_yaml else None
|
|
128
|
-
}
|
|
129
|
-
substitutions = {key: get_content(val) for key, val in file_name_dict.items()}
|
|
130
|
-
|
|
131
|
-
manifest_template = get_content(c.MANIFEST_JINJA_FILE)
|
|
132
|
-
manifest_content = u.render_string(manifest_template, **substitutions)
|
|
133
|
-
output_path = u.join_paths(base_proj_dir, TMP_FOLDER, c.MANIFEST_FILE)
|
|
134
|
-
with open(u.join_paths(output_path), "w") as f:
|
|
135
|
-
f.write(manifest_content)
|
|
136
|
-
|
|
137
|
-
create_manifest_file()
|
|
138
|
-
|
|
139
|
-
self._copy_file(".gitignore")
|
|
140
|
-
self._copy_file(c.MANIFEST_FILE, src_folder=TMP_FOLDER)
|
|
141
|
-
|
|
142
|
-
if connections_use_py:
|
|
143
|
-
self._copy_pyconfig_file(c.CONNECTIONS_FILE)
|
|
144
|
-
elif connections_use_yaml:
|
|
145
|
-
pass # already included in squirrels.yml
|
|
146
|
-
else:
|
|
147
|
-
raise NotImplementedError(f"Format '{connections_format}' not supported for configuring database connections")
|
|
148
|
-
|
|
149
|
-
if parameters_use_py:
|
|
150
|
-
self._copy_pyconfig_file(c.PARAMETERS_FILE)
|
|
151
|
-
elif parameters_use_yaml:
|
|
152
|
-
pass # already included in squirrels.yml
|
|
153
|
-
else:
|
|
154
|
-
raise NotImplementedError(f"Format '{parameters_format}' not supported for configuring widget parameters")
|
|
155
|
-
|
|
156
|
-
self._copy_pyconfig_file(c.CONTEXT_FILE)
|
|
157
|
-
self._copy_file(c.ENV_CONFIG_FILE)
|
|
158
|
-
self._copy_seed_file(c.CATEGORY_SEED_FILE)
|
|
159
|
-
self._copy_seed_file(c.SUBCATEGORY_SEED_FILE)
|
|
152
|
+
federate_format = get_answer(FEDERATE, c.SQL_FILE_TYPE)
|
|
153
|
+
if federate_format == c.SQL_FILE_TYPE:
|
|
154
|
+
federate_file = c.FEDERATE_FILE_STEM + ".sql"
|
|
155
|
+
elif federate_format == c.PYTHON_FILE_TYPE:
|
|
156
|
+
federate_file = c.FEDERATE_FILE_STEM + ".py"
|
|
157
|
+
else:
|
|
158
|
+
raise NotImplementedError(f"Federate model format '{federate_format}' not supported")
|
|
160
159
|
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
dashboards_enabled = get_answer(DASHBOARD, False)
|
|
161
|
+
|
|
162
|
+
self._create_manifest_file(connections_use_yaml, parameters_use_yaml, dashboards_enabled)
|
|
163
|
+
|
|
164
|
+
self._copy_file(u.Path(".gitignore"))
|
|
165
|
+
self._copy_file(u.Path(c.ENV_CONFIG_FILE))
|
|
166
|
+
|
|
167
|
+
if connections_use_py:
|
|
168
|
+
self._copy_pyconfig_file(c.CONNECTIONS_FILE)
|
|
169
|
+
elif connections_use_yaml:
|
|
170
|
+
pass # already included in squirrels.yml
|
|
171
|
+
else:
|
|
172
|
+
raise NotImplementedError(f"Format '{connections_format}' not supported for configuring database connections")
|
|
173
|
+
|
|
174
|
+
if parameters_use_py:
|
|
175
|
+
self._copy_pyconfig_file(c.PARAMETERS_FILE)
|
|
176
|
+
elif parameters_use_yaml:
|
|
177
|
+
pass # already included in squirrels.yml
|
|
178
|
+
else:
|
|
179
|
+
raise NotImplementedError(f"Format '{parameters_format}' not supported for configuring widget parameters")
|
|
163
180
|
|
|
164
|
-
|
|
181
|
+
self._copy_pyconfig_file(c.CONTEXT_FILE)
|
|
182
|
+
self._copy_seed_file(c.CATEGORY_SEED_FILE)
|
|
183
|
+
self._copy_seed_file(c.SUBCATEGORY_SEED_FILE)
|
|
184
|
+
|
|
185
|
+
self._copy_dbview_file(db_view_file)
|
|
186
|
+
self._copy_federate_file(federate_file)
|
|
187
|
+
|
|
188
|
+
if dashboards_enabled:
|
|
189
|
+
self._copy_dashboard_file(c.DASHBOARD_FILE_STEM + ".py")
|
|
190
|
+
|
|
191
|
+
if get_answer(AUTH, False):
|
|
165
192
|
self._copy_pyconfig_file(c.AUTH_FILE)
|
|
166
193
|
|
|
167
|
-
|
|
168
|
-
if sample_db is None: # None if not prompt mode and '--sample-db' option was not specified
|
|
169
|
-
sample_db = c.EXPENSES_DB_NAME
|
|
194
|
+
self._copy_database_file(c.EXPENSES_DB)
|
|
170
195
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
196
|
+
print(f"\nSuccessfully created new Squirrels project in current directory!\n")
|
|
197
|
+
|
|
198
|
+
def get_file(self, args):
|
|
199
|
+
if args.file_name == c.ENV_CONFIG_FILE:
|
|
200
|
+
self._copy_file(u.Path(c.ENV_CONFIG_FILE))
|
|
201
|
+
print("PLEASE ENSURE THE FILE IS INCLUDED IN .gitignore")
|
|
202
|
+
elif args.file_name == c.MANIFEST_FILE:
|
|
203
|
+
self._create_manifest_file(not args.no_connections, args.parameters, args.dashboards)
|
|
204
|
+
elif args.file_name in (c.AUTH_FILE, c.CONNECTIONS_FILE, c.PARAMETERS_FILE, c.CONTEXT_FILE):
|
|
205
|
+
self._copy_pyconfig_file(args.file_name)
|
|
206
|
+
elif args.file_name in (c.DBVIEW_FILE_STEM, c.FEDERATE_FILE_STEM):
|
|
207
|
+
if args.format == c.SQL_FILE_TYPE:
|
|
208
|
+
extension = ".sql"
|
|
209
|
+
elif args.format == c.PYTHON_FILE_TYPE:
|
|
210
|
+
extension = ".py"
|
|
176
211
|
else:
|
|
177
|
-
raise NotImplementedError(f"
|
|
178
|
-
|
|
212
|
+
raise NotImplementedError(f"Format '{args.format}' not supported for {args.file_name}")
|
|
213
|
+
copy_method = self._copy_dbview_file if args.file_name == c.DBVIEW_FILE_STEM else self._copy_federate_file
|
|
214
|
+
copy_method(args.file_name + extension)
|
|
215
|
+
elif args.file_name == c.DASHBOARD_FILE_STEM:
|
|
216
|
+
self._copy_dashboard_file(args.file_name + ".py")
|
|
217
|
+
elif args.file_name in (c.EXPENSES_DB, c.WEATHER_DB):
|
|
218
|
+
self._copy_database_file(args.file_name)
|
|
219
|
+
else:
|
|
220
|
+
raise NotImplementedError(f"File '{args.file_name}' not supported")
|
|
221
|
+
|