squirrels 0.4.1__py3-none-any.whl → 0.5.0b1__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.

Files changed (80) hide show
  1. squirrels/__init__.py +10 -6
  2. squirrels/_api_response_models.py +93 -44
  3. squirrels/_api_server.py +571 -219
  4. squirrels/_auth.py +451 -0
  5. squirrels/_command_line.py +61 -20
  6. squirrels/_connection_set.py +38 -25
  7. squirrels/_constants.py +44 -34
  8. squirrels/_dashboards_io.py +34 -16
  9. squirrels/_exceptions.py +57 -0
  10. squirrels/_initializer.py +117 -44
  11. squirrels/_manifest.py +124 -62
  12. squirrels/_model_builder.py +111 -0
  13. squirrels/_model_configs.py +74 -0
  14. squirrels/_model_queries.py +52 -0
  15. squirrels/_models.py +860 -354
  16. squirrels/_package_loader.py +8 -4
  17. squirrels/_parameter_configs.py +45 -65
  18. squirrels/_parameter_sets.py +15 -13
  19. squirrels/_project.py +561 -0
  20. squirrels/_py_module.py +4 -3
  21. squirrels/_seeds.py +35 -16
  22. squirrels/_sources.py +106 -0
  23. squirrels/_utils.py +166 -63
  24. squirrels/_version.py +1 -1
  25. squirrels/arguments/init_time_args.py +78 -15
  26. squirrels/arguments/run_time_args.py +62 -101
  27. squirrels/dashboards.py +4 -4
  28. squirrels/data_sources.py +94 -162
  29. squirrels/dataset_result.py +86 -0
  30. squirrels/dateutils.py +4 -4
  31. squirrels/package_data/base_project/.env +30 -0
  32. squirrels/package_data/base_project/.env.example +30 -0
  33. squirrels/package_data/base_project/.gitignore +3 -2
  34. squirrels/package_data/base_project/assets/expenses.db +0 -0
  35. squirrels/package_data/base_project/connections.yml +11 -3
  36. squirrels/package_data/base_project/dashboards/dashboard_example.py +15 -13
  37. squirrels/package_data/base_project/dashboards/dashboard_example.yml +22 -0
  38. squirrels/package_data/base_project/docker/.dockerignore +5 -2
  39. squirrels/package_data/base_project/docker/Dockerfile +3 -3
  40. squirrels/package_data/base_project/docker/compose.yml +1 -1
  41. squirrels/package_data/base_project/duckdb_init.sql +9 -0
  42. squirrels/package_data/base_project/macros/macros_example.sql +15 -0
  43. squirrels/package_data/base_project/models/builds/build_example.py +26 -0
  44. squirrels/package_data/base_project/models/builds/build_example.sql +16 -0
  45. squirrels/package_data/base_project/models/builds/build_example.yml +55 -0
  46. squirrels/package_data/base_project/models/dbviews/dbview_example.sql +12 -22
  47. squirrels/package_data/base_project/models/dbviews/dbview_example.yml +26 -0
  48. squirrels/package_data/base_project/models/federates/federate_example.py +38 -15
  49. squirrels/package_data/base_project/models/federates/federate_example.sql +16 -2
  50. squirrels/package_data/base_project/models/federates/federate_example.yml +65 -0
  51. squirrels/package_data/base_project/models/sources.yml +39 -0
  52. squirrels/package_data/base_project/parameters.yml +36 -21
  53. squirrels/package_data/base_project/pyconfigs/connections.py +6 -11
  54. squirrels/package_data/base_project/pyconfigs/context.py +20 -33
  55. squirrels/package_data/base_project/pyconfigs/parameters.py +19 -21
  56. squirrels/package_data/base_project/pyconfigs/user.py +23 -0
  57. squirrels/package_data/base_project/seeds/seed_categories.yml +15 -0
  58. squirrels/package_data/base_project/seeds/seed_subcategories.csv +15 -15
  59. squirrels/package_data/base_project/seeds/seed_subcategories.yml +21 -0
  60. squirrels/package_data/base_project/squirrels.yml.j2 +17 -40
  61. squirrels/parameters.py +20 -20
  62. {squirrels-0.4.1.dist-info → squirrels-0.5.0b1.dist-info}/METADATA +31 -32
  63. squirrels-0.5.0b1.dist-info/RECORD +70 -0
  64. {squirrels-0.4.1.dist-info → squirrels-0.5.0b1.dist-info}/WHEEL +1 -1
  65. squirrels-0.5.0b1.dist-info/entry_points.txt +3 -0
  66. {squirrels-0.4.1.dist-info → squirrels-0.5.0b1.dist-info/licenses}/LICENSE +1 -1
  67. squirrels/_authenticator.py +0 -85
  68. squirrels/_environcfg.py +0 -84
  69. squirrels/package_data/assets/favicon.ico +0 -0
  70. squirrels/package_data/assets/index.css +0 -1
  71. squirrels/package_data/assets/index.js +0 -58
  72. squirrels/package_data/base_project/dashboards.yml +0 -10
  73. squirrels/package_data/base_project/env.yml +0 -29
  74. squirrels/package_data/base_project/models/dbviews/dbview_example.py +0 -47
  75. squirrels/package_data/base_project/pyconfigs/auth.py +0 -45
  76. squirrels/package_data/templates/index.html +0 -18
  77. squirrels/project.py +0 -378
  78. squirrels/user_base.py +0 -55
  79. squirrels-0.4.1.dist-info/RECORD +0 -60
  80. squirrels-0.4.1.dist-info/entry_points.txt +0 -4
@@ -1,11 +1,11 @@
1
- from dataclasses import dataclass
2
- from sqlalchemy import Engine, create_engine
3
- import time, pandas as pd
1
+ from typing import Any
2
+ from dataclasses import dataclass, field
3
+ from sqlalchemy import Engine
4
+ import time, polars as pl
4
5
 
5
6
  from . import _utils as u, _constants as c, _py_module as pm
6
7
  from .arguments.init_time_args import ConnectionsArgs
7
- from ._environcfg import EnvironConfig
8
- from ._manifest import ManifestConfig
8
+ from ._manifest import ManifestConfig, ConnectionProperties, ConnectionType
9
9
 
10
10
 
11
11
  @dataclass
@@ -16,44 +16,56 @@ class ConnectionSet:
16
16
  Attributes:
17
17
  _engines: A dictionary of connection name to the corresponding sqlalchemy engine
18
18
  """
19
- _engines: dict[str, Engine]
19
+ _connections: dict[str, ConnectionProperties | Any] = field(default_factory=dict)
20
20
 
21
- def get_engines_as_dict(self):
22
- return self._engines.copy()
21
+ def get_connections_as_dict(self):
22
+ return self._connections.copy()
23
23
 
24
- def _get_engine(self, conn_name: str) -> Engine:
24
+ def get_connection(self, conn_name: str) -> ConnectionProperties | Any:
25
25
  try:
26
- connection_pool = self._engines[conn_name]
26
+ connection = self._connections[conn_name]
27
27
  except KeyError as e:
28
28
  raise u.ConfigurationError(f'Connection name "{conn_name}" was not configured') from e
29
- return connection_pool
29
+ return connection
30
30
 
31
- def run_sql_query_from_conn_name(self, query: str, conn_name: str, placeholders: dict = {}) -> pd.DataFrame:
32
- engine = self._get_engine(conn_name)
31
+ def run_sql_query_from_conn_name(self, query: str, conn_name: str, placeholders: dict = {}) -> pl.DataFrame:
32
+ conn = self.get_connection(conn_name)
33
33
  try:
34
- df = pd.read_sql(query, engine, params=placeholders)
34
+ if isinstance(conn, ConnectionProperties) and (conn.type == ConnectionType.CONNECTORX or conn.type == ConnectionType.ADBC):
35
+ if len(placeholders) > 0:
36
+ raise u.ConfigurationError(f"Connection '{conn_name}' is a ConnectorX or ADBC connection, which does not support placeholders")
37
+ df = pl.read_database_uri(query, conn.uri, engine=conn.type.value)
38
+ elif isinstance(conn, ConnectionProperties) and conn.type == ConnectionType.SQLALCHEMY:
39
+ with conn.engine.connect() as connection:
40
+ df = pl.read_database(query, connection, execute_options={"parameters": placeholders})
41
+ else:
42
+ df = pl.read_database(query, conn, execute_options={"parameters": placeholders}) # type: ignore
35
43
  return df
36
44
  except Exception as e:
37
45
  raise RuntimeError(e) from e
38
46
 
39
47
  def dispose(self) -> None:
40
48
  """
41
- Disposes of all the engines in this ConnectionSet
49
+ Disposes / closes all the connections in this ConnectionSet
42
50
  """
43
- for pool in self._engines.values():
44
- if isinstance(pool, Engine):
45
- pool.dispose()
51
+ for conn in self._connections.values():
52
+ if isinstance(conn, Engine):
53
+ conn.dispose()
54
+ elif isinstance(conn, ConnectionProperties):
55
+ if conn.type == ConnectionType.SQLALCHEMY:
56
+ conn.engine.dispose()
57
+ elif hasattr(conn, 'close'):
58
+ conn.close()
46
59
 
47
60
 
48
61
  class ConnectionSetIO:
49
62
 
50
63
  @classmethod
51
- def load_conn_py_args(cls, logger: u.Logger, env_cfg: EnvironConfig, manifest_cfg: ManifestConfig) -> ConnectionsArgs:
64
+ def load_conn_py_args(cls, logger: u.Logger, base_path: str, env_vars: dict[str, str], manifest_cfg: ManifestConfig) -> ConnectionsArgs:
52
65
  start = time.time()
53
66
 
54
67
  proj_vars = manifest_cfg.project_variables.model_dump()
55
- env_vars = env_cfg.get_all_env_vars()
56
- conn_args = ConnectionsArgs(proj_vars, env_vars, env_cfg.get_credential)
68
+ conn_args = ConnectionsArgs(base_path, proj_vars, env_vars)
57
69
 
58
70
  logger.log_activity_time("setting up arguments for connections.py", start)
59
71
  return conn_args
@@ -68,13 +80,14 @@ class ConnectionSetIO:
68
80
  A ConnectionSet with the DB connections from both squirrels.yml and connections.py
69
81
  """
70
82
  start = time.time()
71
- engines: dict[str, Engine] = {}
83
+ connections: dict[str, ConnectionProperties | Any] = {}
72
84
 
73
85
  for config in manifest_cfg.connections.values():
74
- engines[config.name] = create_engine(config.url)
86
+ connections[config.name] = ConnectionProperties(label=config.label, type=config.type, uri=config.uri)
75
87
 
76
- pm.run_pyconfig_main(base_path, c.CONNECTIONS_FILE, {"connections": engines, "sqrl": conn_args})
77
- conn_set = ConnectionSet(engines)
88
+ pm.run_pyconfig_main(base_path, c.CONNECTIONS_FILE, {"connections": connections, "sqrl": conn_args})
89
+
90
+ conn_set = ConnectionSet(connections)
78
91
 
79
92
  logger.log_activity_time("creating sqlalchemy engines", start)
80
93
  return conn_set
squirrels/_constants.py CHANGED
@@ -1,25 +1,51 @@
1
1
  # Squirrels CLI commands
2
- INIT_CMD = 'init'
2
+ INIT_CMD = 'new'
3
3
  GET_FILE_CMD = 'get-file'
4
4
  DEPS_CMD = 'deps'
5
+ BUILD_CMD = 'build'
5
6
  COMPILE_CMD = 'compile'
6
7
  RUN_CMD = 'run'
8
+ DUCKDB_CMD = 'duckdb'
7
9
 
8
- # Environment config keys
9
- JWT_SECRET_KEY = 'jwt_secret'
10
+ # Environment variables
11
+ SQRL_SECRET_KEY = 'SQRL_SECRET__KEY'
12
+ SQRL_SECRET_ADMIN_PASSWORD = 'SQRL_SECRET__ADMIN_PASSWORD'
13
+
14
+ SQRL_AUTH_DB_FILE_PATH = 'SQRL_AUTH__DB_FILE_PATH'
15
+ SQRL_AUTH_TOKEN_EXPIRE_MINUTES = 'SQRL_AUTH__TOKEN_EXPIRE_MINUTES'
16
+
17
+ SQRL_PARAMETERS_CACHE_SIZE = 'SQRL_PARAMETERS__CACHE_SIZE'
18
+ SQRL_PARAMETERS_CACHE_TTL_MINUTES = 'SQRL_PARAMETERS__CACHE_TTL_MINUTES'
19
+
20
+ SQRL_DATASETS_CACHE_SIZE = 'SQRL_DATASETS__CACHE_SIZE'
21
+ SQRL_DATASETS_CACHE_TTL_MINUTES = 'SQRL_DATASETS__CACHE_TTL_MINUTES'
22
+
23
+ SQRL_DASHBOARDS_CACHE_SIZE = 'SQRL_DASHBOARDS__CACHE_SIZE'
24
+ SQRL_DASHBOARDS_CACHE_TTL_MINUTES = 'SQRL_DASHBOARDS__CACHE_TTL_MINUTES'
25
+
26
+ SQRL_SEEDS_INFER_SCHEMA = 'SQRL_SEEDS__INFER_SCHEMA'
27
+ SQRL_SEEDS_NA_VALUES = 'SQRL_SEEDS__NA_VALUES'
28
+
29
+ SQRL_TEST_SETS_DEFAULT_NAME_USED = 'SQRL_TEST_SETS__DEFAULT_NAME_USED'
30
+
31
+ SQRL_CONNECTIONS_DEFAULT_NAME_USED = 'SQRL_CONNECTIONS__DEFAULT_NAME_USED'
32
+
33
+ SQRL_DUCKDB_VENV_DB_FILE_PATH = 'SQRL_DUCKDB_VENV__DB_FILE_PATH'
10
34
 
11
35
  # Folder/File names
12
36
  PACKAGE_DATA_FOLDER = 'package_data'
13
37
  BASE_PROJECT_FOLDER = 'base_project'
14
- ASSETS_FOLDER = 'assets'
15
- TEMPLATES_FOLDER = 'templates'
16
38
 
17
- ENV_CONFIG_FILE = 'env.yml'
39
+ GLOBAL_ENV_FOLDER = '.squirrels'
18
40
  MANIFEST_JINJA_FILE = 'squirrels.yml.j2'
19
41
  CONNECTIONS_YML_FILE = 'connections.yml'
20
42
  PARAMETERS_YML_FILE = 'parameters.yml'
21
43
  DASHBOARDS_YML_FILE = 'dashboards.yml'
22
44
  MANIFEST_FILE = 'squirrels.yml'
45
+ DUCKDB_INIT_FILE = 'duckdb_init.sql'
46
+ DOTENV_FILE = '.env'
47
+ DOTENV_LOCAL_FILE = '.env.local'
48
+ GITIGNORE_FILE = '.gitignore'
23
49
 
24
50
  LOGS_FOLDER = 'logs'
25
51
  LOGS_FILE = 'squirrels.log'
@@ -28,8 +54,12 @@ DATABASE_FOLDER = 'assets'
28
54
  PACKAGES_FOLDER = 'sqrl_packages'
29
55
 
30
56
  MACROS_FOLDER = 'macros'
57
+ MACROS_FILE = 'macros_example.sql'
31
58
 
32
59
  MODELS_FOLDER = 'models'
60
+ SOURCES_FILE = 'sources.yml'
61
+ BUILDS_FOLDER = 'builds'
62
+ BUILD_FILE_STEM = 'build_example'
33
63
  DBVIEWS_FOLDER = 'dbviews'
34
64
  DBVIEW_FILE_STEM = 'dbview_example'
35
65
  FEDERATES_FOLDER = 'federates'
@@ -43,35 +73,17 @@ AUTH_FILE = 'auth.py'
43
73
  CONNECTIONS_FILE = 'connections.py'
44
74
  CONTEXT_FILE = 'context.py'
45
75
  PARAMETERS_FILE = 'parameters.py'
76
+ USER_FILE = 'user.py'
77
+ ADMIN_USERNAME = 'admin'
46
78
 
47
79
  TARGET_FOLDER = 'target'
80
+ DB_FILE = 'auth.sqlite'
48
81
  COMPILE_FOLDER = 'compile'
82
+ DUCKDB_VENV_FILE = 'venv.duckdb'
49
83
 
50
84
  SEEDS_FOLDER = 'seeds'
51
- CATEGORY_SEED_FILE = 'seed_categories.csv'
52
- SUBCATEGORY_SEED_FILE = 'seed_subcategories.csv'
53
-
54
- # Dataset setting names
55
- AUTH_TOKEN_EXPIRE_SETTING = 'auth.token.expire_minutes'
56
- PARAMETERS_CACHE_SIZE_SETTING = 'parameters.cache.size'
57
- PARAMETERS_CACHE_TTL_SETTING = 'parameters.cache.ttl_minutes'
58
- RESULTS_CACHE_SIZE_SETTING = 'results.cache.size' # deprecated
59
- RESULTS_CACHE_TTL_SETTING = 'results.cache.ttl_minutes' # deprecated
60
- DATASETS_CACHE_SIZE_SETTING = 'datasets.cache.size'
61
- DATASETS_CACHE_TTL_SETTING = 'datasets.cache.ttl_minutes'
62
- DASHBOARDS_CACHE_SIZE_SETTING = 'dashboards.cache.size'
63
- DASHBOARDS_CACHE_TTL_SETTING = 'dashboards.cache.ttl_minutes'
64
- TEST_SET_DEFAULT_USED_SETTING = 'selection_test_sets.default_name_used'
65
- DEFAULT_TEST_SET_NAME = 'default'
66
- DB_CONN_DEFAULT_USED_SETTING = 'connections.default_name_used'
67
- DEFAULT_DB_CONN = 'default'
68
- DEFAULT_MATERIALIZE_SETTING = 'defaults.federates.materialized'
69
- DEFAULT_MATERIALIZE = 'table'
70
- SEEDS_INFER_SCHEMA_SETTING = 'seeds.infer_schema'
71
- SEEDS_NA_VALUES_SETTING = 'seeds.na_values'
72
- IN_MEMORY_DB_SETTING = 'in_memory_database'
73
- SQLITE = 'sqlite'
74
- DUCKDB = 'duckdb'
85
+ SEED_CATEGORY_FILE_STEM = 'seed_categories'
86
+ SEED_SUBCATEGORY_FILE_STEM = 'seed_subcategories'
75
87
 
76
88
  # Selection cfg sections
77
89
  USER_ATTRIBUTES_SECTION = 'user_attributes'
@@ -97,10 +109,8 @@ PNG = "png"
97
109
  HTML = "html"
98
110
 
99
111
  # Function names
100
- GET_USER_FUNC = "get_user_if_valid"
101
- DEP_FUNC = "dependencies"
102
112
  MAIN_FUNC = "main"
103
113
 
104
114
  # Regex
105
- date_regex = r"^\d{4}\-\d{2}\-\d{2}$"
106
- color_regex = r"^#[0-9a-fA-F]{6}$"
115
+ DATE_REGEX = r"^\d{4}\-\d{2}\-\d{2}$"
116
+ COLOR_REGEX = r"^#[0-9a-fA-F]{6}$"
@@ -1,18 +1,37 @@
1
1
  from typing import Type, TypeVar, Callable, Coroutine, Any
2
+ from enum import Enum
2
3
  from dataclasses import dataclass
3
- import inspect, os, time
4
+ from pydantic import BaseModel, Field
5
+ import os, time
4
6
 
5
7
  from .arguments.run_time_args import DashboardArgs
6
8
  from ._py_module import PyModule
9
+ from ._manifest import AnalyticsOutputConfig
10
+ from ._exceptions import InvalidInputError, ConfigurationError, FileExecutionError
7
11
  from . import _constants as c, _utils as u, dashboards as d
8
12
 
9
13
  T = TypeVar('T', bound=d.Dashboard)
10
14
 
11
15
 
16
+ class DashboardFormat(Enum):
17
+ PNG = "png"
18
+ HTML = "html"
19
+
20
+ class DashboardDependencies(BaseModel):
21
+ name: str
22
+ dataset: str
23
+ fixed_parameters: list[dict[str, str]] = Field(default_factory=list)
24
+
25
+ class DashboardConfig(AnalyticsOutputConfig):
26
+ format: DashboardFormat = Field(default=DashboardFormat.PNG)
27
+ depends_on: list[DashboardDependencies] = Field(default_factory=list)
28
+
29
+
12
30
  @dataclass
13
- class DashboardFunction:
31
+ class DashboardDefinition:
14
32
  dashboard_name: str
15
33
  filepath: str
34
+ config: DashboardConfig
16
35
 
17
36
  @property
18
37
  def dashboard_func(self) -> Callable[[DashboardArgs], Coroutine[Any, Any, d.Dashboard]]:
@@ -22,23 +41,16 @@ class DashboardFunction:
22
41
  return self._dashboard_func
23
42
 
24
43
  def get_dashboard_format(self) -> str:
25
- return_type = inspect.signature(self.dashboard_func).return_annotation
26
- assert issubclass(return_type, d.Dashboard), f"Function must return Dashboard type"
27
- if return_type == d.PngDashboard:
28
- return c.PNG
29
- elif return_type == d.HtmlDashboard:
30
- return c.HTML
31
- else:
32
- raise NotImplementedError(f"Dashboard format {return_type} not supported")
44
+ return self.config.format.value
33
45
 
34
46
  async def get_dashboard(self, args: DashboardArgs, *, dashboard_type: Type[T] = d.Dashboard) -> T:
35
47
  try:
36
48
  dashboard = await self.dashboard_func(args)
37
49
  assert isinstance(dashboard, dashboard_type), f"Function does not return expected Dashboard type: {dashboard_type}"
38
- except (u.InvalidInputError, u.ConfigurationError, u.FileExecutionError) as e:
50
+ except (InvalidInputError, ConfigurationError, FileExecutionError) as e:
39
51
  raise e
40
52
  except Exception as e:
41
- raise u.FileExecutionError(f'Failed to run "{c.MAIN_FUNC}" function for dashboard "{self.dashboard_name}"', e) from e
53
+ raise FileExecutionError(f'Failed to run "{c.MAIN_FUNC}" function for dashboard "{self.dashboard_name}"', e) from e
42
54
 
43
55
  return dashboard
44
56
 
@@ -46,7 +58,7 @@ class DashboardFunction:
46
58
  class DashboardsIO:
47
59
 
48
60
  @classmethod
49
- def load_files(cls, logger: u.Logger, base_path: str) -> dict[str, DashboardFunction]:
61
+ def load_files(cls, logger: u.Logger, base_path: str) -> dict[str, DashboardDefinition]:
50
62
  start = time.time()
51
63
 
52
64
  dashboards_by_name = {}
@@ -54,8 +66,14 @@ class DashboardsIO:
54
66
  for file in filenames:
55
67
  filepath = os.path.join(dp, file)
56
68
  file_stem, extension = os.path.splitext(file)
57
- if extension == '.py':
58
- dashboards_by_name[file_stem] = DashboardFunction(file_stem, filepath)
59
-
69
+ if not extension == '.py':
70
+ continue
71
+
72
+ # Check for corresponding .yml file
73
+ yml_path = os.path.join(dp, file_stem + '.yml')
74
+ config_dict = u.load_yaml_config(yml_path) if os.path.exists(yml_path) else {}
75
+ config = DashboardConfig(name=file_stem, **config_dict)
76
+ dashboards_by_name[file_stem] = DashboardDefinition(file_stem, filepath, config)
77
+
60
78
  logger.log_activity_time("loading files for dashboards", start)
61
79
  return dashboards_by_name
@@ -0,0 +1,57 @@
1
+ class InvalidInputError(Exception):
2
+ """
3
+ Use this exception when the error is due to providing invalid inputs to the REST API
4
+
5
+ Specific error code ranges are reserved for specific categories of errors.
6
+ 0-19: 401 unauthorized errors
7
+ 20-39: 403 forbidden errors
8
+ 40-59: 404 not found errors
9
+ 60-69: 409 conflict errors
10
+ 70-99: Reserved for future use
11
+ 100-199: 400 bad request errors related to authentication
12
+ 200-299: 400 bad request errors related to data analytics
13
+
14
+ Error code definitions:
15
+ 0 - Incorrect username or password
16
+ 1 - Invalid authorization token
17
+ 2 - Username not found for password change
18
+ 3 - Incorrect password for password change
19
+ 20 - Authorized user is forbidden to add or update users
20
+ 21 - Authorized user is forbidden to delete users
21
+ 22 - Cannot delete your own user
22
+ 23 - Cannot delete the admin user
23
+ 24 - Cannot change the admin user
24
+ 25 - User does not have permission to access the dataset / dashboard
25
+ 26 - User does not have permission to build the virtual data environment
26
+ 27 - User does not have permission to query data models
27
+ 40 - No token found for token_id
28
+ 41 - No user found for username
29
+ 60 - An existing build process is already running and a concurrent build is not allowed
30
+ 61 - Model depends on static data models that cannot be found
31
+ 100 - Missing required field 'username' or 'password' when adding a new user
32
+ 101 - Username already exists when adding a new user
33
+ 102 - Invalid user data when adding a new user
34
+ 200 - Invalid value for dataset parameter
35
+ 201 - Invalid query parameter provided
36
+ 202 - Could not determine parent parameter for parameter refresh
37
+ 203 - SQL query must be provided
38
+ 204 - Failed to run provided SQL query
39
+ """
40
+ def __init__(self, error_code: int, message: str, *args) -> None:
41
+ self.error_code = error_code
42
+ super().__init__(message, *args)
43
+
44
+
45
+ class ConfigurationError(Exception):
46
+ """
47
+ Use this exception when the server error is due to errors in the squirrels project instead of the squirrels framework/library
48
+ """
49
+ pass
50
+
51
+
52
+ class FileExecutionError(Exception):
53
+ def __init__(self, message: str, error: Exception, *args) -> None:
54
+ t = " "
55
+ new_message = f"\n" + message + f"\n{t}Produced error message:\n{t}{t}{error} (see above for more details on handled exception)"
56
+ super().__init__(new_message, *args)
57
+ self.error = error