mito-ai 0.1.50__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.
- mito_ai/__init__.py +114 -0
- mito_ai/_version.py +4 -0
- mito_ai/anthropic_client.py +334 -0
- mito_ai/app_deploy/__init__.py +6 -0
- mito_ai/app_deploy/app_deploy_utils.py +44 -0
- mito_ai/app_deploy/handlers.py +345 -0
- mito_ai/app_deploy/models.py +98 -0
- mito_ai/app_manager/__init__.py +4 -0
- mito_ai/app_manager/handlers.py +167 -0
- mito_ai/app_manager/models.py +71 -0
- mito_ai/app_manager/utils.py +24 -0
- mito_ai/auth/README.md +18 -0
- mito_ai/auth/__init__.py +6 -0
- mito_ai/auth/handlers.py +96 -0
- mito_ai/auth/urls.py +13 -0
- mito_ai/chat_history/handlers.py +63 -0
- mito_ai/chat_history/urls.py +32 -0
- mito_ai/completions/completion_handlers/__init__.py +3 -0
- mito_ai/completions/completion_handlers/agent_auto_error_fixup_handler.py +59 -0
- mito_ai/completions/completion_handlers/agent_execution_handler.py +66 -0
- mito_ai/completions/completion_handlers/chat_completion_handler.py +141 -0
- mito_ai/completions/completion_handlers/code_explain_handler.py +113 -0
- mito_ai/completions/completion_handlers/completion_handler.py +42 -0
- mito_ai/completions/completion_handlers/inline_completer_handler.py +48 -0
- mito_ai/completions/completion_handlers/smart_debug_handler.py +160 -0
- mito_ai/completions/completion_handlers/utils.py +147 -0
- mito_ai/completions/handlers.py +415 -0
- mito_ai/completions/message_history.py +401 -0
- mito_ai/completions/models.py +404 -0
- mito_ai/completions/prompt_builders/__init__.py +3 -0
- mito_ai/completions/prompt_builders/agent_execution_prompt.py +57 -0
- mito_ai/completions/prompt_builders/agent_smart_debug_prompt.py +160 -0
- mito_ai/completions/prompt_builders/agent_system_message.py +472 -0
- mito_ai/completions/prompt_builders/chat_name_prompt.py +15 -0
- mito_ai/completions/prompt_builders/chat_prompt.py +116 -0
- mito_ai/completions/prompt_builders/chat_system_message.py +92 -0
- mito_ai/completions/prompt_builders/explain_code_prompt.py +32 -0
- mito_ai/completions/prompt_builders/inline_completer_prompt.py +197 -0
- mito_ai/completions/prompt_builders/prompt_constants.py +170 -0
- mito_ai/completions/prompt_builders/smart_debug_prompt.py +199 -0
- mito_ai/completions/prompt_builders/utils.py +84 -0
- mito_ai/completions/providers.py +284 -0
- mito_ai/constants.py +63 -0
- mito_ai/db/__init__.py +3 -0
- mito_ai/db/crawlers/__init__.py +6 -0
- mito_ai/db/crawlers/base_crawler.py +61 -0
- mito_ai/db/crawlers/constants.py +43 -0
- mito_ai/db/crawlers/snowflake.py +71 -0
- mito_ai/db/handlers.py +168 -0
- mito_ai/db/models.py +31 -0
- mito_ai/db/urls.py +34 -0
- mito_ai/db/utils.py +185 -0
- mito_ai/docker/mssql/compose.yml +37 -0
- mito_ai/docker/mssql/init/setup.sql +21 -0
- mito_ai/docker/mysql/compose.yml +18 -0
- mito_ai/docker/mysql/init/setup.sql +13 -0
- mito_ai/docker/oracle/compose.yml +17 -0
- mito_ai/docker/oracle/init/setup.sql +20 -0
- mito_ai/docker/postgres/compose.yml +17 -0
- mito_ai/docker/postgres/init/setup.sql +13 -0
- mito_ai/enterprise/__init__.py +3 -0
- mito_ai/enterprise/utils.py +15 -0
- mito_ai/file_uploads/__init__.py +3 -0
- mito_ai/file_uploads/handlers.py +248 -0
- mito_ai/file_uploads/urls.py +21 -0
- mito_ai/gemini_client.py +232 -0
- mito_ai/log/handlers.py +38 -0
- mito_ai/log/urls.py +21 -0
- mito_ai/logger.py +37 -0
- mito_ai/openai_client.py +382 -0
- mito_ai/path_utils.py +70 -0
- mito_ai/rules/handlers.py +44 -0
- mito_ai/rules/urls.py +22 -0
- mito_ai/rules/utils.py +56 -0
- mito_ai/settings/handlers.py +41 -0
- mito_ai/settings/urls.py +20 -0
- mito_ai/settings/utils.py +42 -0
- mito_ai/streamlit_conversion/agent_utils.py +37 -0
- mito_ai/streamlit_conversion/prompts/prompt_constants.py +172 -0
- mito_ai/streamlit_conversion/prompts/prompt_utils.py +10 -0
- mito_ai/streamlit_conversion/prompts/streamlit_app_creation_prompt.py +46 -0
- mito_ai/streamlit_conversion/prompts/streamlit_error_correction_prompt.py +28 -0
- mito_ai/streamlit_conversion/prompts/streamlit_finish_todo_prompt.py +45 -0
- mito_ai/streamlit_conversion/prompts/streamlit_system_prompt.py +56 -0
- mito_ai/streamlit_conversion/prompts/update_existing_app_prompt.py +50 -0
- mito_ai/streamlit_conversion/search_replace_utils.py +94 -0
- mito_ai/streamlit_conversion/streamlit_agent_handler.py +144 -0
- mito_ai/streamlit_conversion/streamlit_utils.py +85 -0
- mito_ai/streamlit_conversion/validate_streamlit_app.py +105 -0
- mito_ai/streamlit_preview/__init__.py +6 -0
- mito_ai/streamlit_preview/handlers.py +111 -0
- mito_ai/streamlit_preview/manager.py +152 -0
- mito_ai/streamlit_preview/urls.py +22 -0
- mito_ai/streamlit_preview/utils.py +29 -0
- mito_ai/tests/__init__.py +3 -0
- mito_ai/tests/chat_history/test_chat_history.py +211 -0
- mito_ai/tests/completions/completion_handlers_utils_test.py +190 -0
- mito_ai/tests/conftest.py +53 -0
- mito_ai/tests/create_agent_system_message_prompt_test.py +22 -0
- mito_ai/tests/data/prompt_lg.py +69 -0
- mito_ai/tests/data/prompt_sm.py +6 -0
- mito_ai/tests/data/prompt_xl.py +13 -0
- mito_ai/tests/data/stock_data.sqlite3 +0 -0
- mito_ai/tests/db/conftest.py +39 -0
- mito_ai/tests/db/connections_test.py +102 -0
- mito_ai/tests/db/mssql_test.py +29 -0
- mito_ai/tests/db/mysql_test.py +29 -0
- mito_ai/tests/db/oracle_test.py +29 -0
- mito_ai/tests/db/postgres_test.py +29 -0
- mito_ai/tests/db/schema_test.py +93 -0
- mito_ai/tests/db/sqlite_test.py +31 -0
- mito_ai/tests/db/test_db_constants.py +61 -0
- mito_ai/tests/deploy_app/test_app_deploy_utils.py +89 -0
- mito_ai/tests/file_uploads/__init__.py +2 -0
- mito_ai/tests/file_uploads/test_handlers.py +282 -0
- mito_ai/tests/message_history/test_generate_short_chat_name.py +120 -0
- mito_ai/tests/message_history/test_message_history_utils.py +469 -0
- mito_ai/tests/open_ai_utils_test.py +152 -0
- mito_ai/tests/performance_test.py +329 -0
- mito_ai/tests/providers/test_anthropic_client.py +447 -0
- mito_ai/tests/providers/test_azure.py +631 -0
- mito_ai/tests/providers/test_capabilities.py +120 -0
- mito_ai/tests/providers/test_gemini_client.py +195 -0
- mito_ai/tests/providers/test_mito_server_utils.py +448 -0
- mito_ai/tests/providers/test_model_resolution.py +130 -0
- mito_ai/tests/providers/test_openai_client.py +57 -0
- mito_ai/tests/providers/test_provider_completion_exception.py +66 -0
- mito_ai/tests/providers/test_provider_limits.py +42 -0
- mito_ai/tests/providers/test_providers.py +382 -0
- mito_ai/tests/providers/test_retry_logic.py +389 -0
- mito_ai/tests/providers/test_stream_mito_server_utils.py +140 -0
- mito_ai/tests/providers/utils.py +85 -0
- mito_ai/tests/rules/conftest.py +26 -0
- mito_ai/tests/rules/rules_test.py +117 -0
- mito_ai/tests/server_limits_test.py +406 -0
- mito_ai/tests/settings/conftest.py +26 -0
- mito_ai/tests/settings/settings_test.py +70 -0
- mito_ai/tests/settings/test_settings_constants.py +9 -0
- mito_ai/tests/streamlit_conversion/__init__.py +3 -0
- mito_ai/tests/streamlit_conversion/test_apply_search_replace.py +240 -0
- mito_ai/tests/streamlit_conversion/test_streamlit_agent_handler.py +246 -0
- mito_ai/tests/streamlit_conversion/test_streamlit_utils.py +193 -0
- mito_ai/tests/streamlit_conversion/test_validate_streamlit_app.py +112 -0
- mito_ai/tests/streamlit_preview/test_streamlit_preview_handler.py +118 -0
- mito_ai/tests/streamlit_preview/test_streamlit_preview_manager.py +292 -0
- mito_ai/tests/test_constants.py +47 -0
- mito_ai/tests/test_telemetry.py +12 -0
- mito_ai/tests/user/__init__.py +2 -0
- mito_ai/tests/user/test_user.py +120 -0
- mito_ai/tests/utils/__init__.py +3 -0
- mito_ai/tests/utils/test_anthropic_utils.py +162 -0
- mito_ai/tests/utils/test_gemini_utils.py +98 -0
- mito_ai/tests/version_check_test.py +169 -0
- mito_ai/user/handlers.py +45 -0
- mito_ai/user/urls.py +21 -0
- mito_ai/utils/__init__.py +3 -0
- mito_ai/utils/anthropic_utils.py +168 -0
- mito_ai/utils/create.py +94 -0
- mito_ai/utils/db.py +74 -0
- mito_ai/utils/error_classes.py +42 -0
- mito_ai/utils/gemini_utils.py +133 -0
- mito_ai/utils/message_history_utils.py +87 -0
- mito_ai/utils/mito_server_utils.py +242 -0
- mito_ai/utils/open_ai_utils.py +200 -0
- mito_ai/utils/provider_utils.py +49 -0
- mito_ai/utils/schema.py +86 -0
- mito_ai/utils/server_limits.py +152 -0
- mito_ai/utils/telemetry_utils.py +480 -0
- mito_ai/utils/utils.py +89 -0
- mito_ai/utils/version_utils.py +94 -0
- mito_ai/utils/websocket_base.py +88 -0
- mito_ai/version_check.py +60 -0
- mito_ai-0.1.50.data/data/etc/jupyter/jupyter_server_config.d/mito_ai.json +7 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/build_log.json +728 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/package.json +243 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/package.json.orig +238 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/toolbar-buttons.json +37 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.8f1845da6bf2b128c049.js +21602 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.8f1845da6bf2b128c049.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js +198 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.78d3ccb73e7ca1da3aae.js +619 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.78d3ccb73e7ca1da3aae.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/style.js +4 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js +712 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_apis_signOut_mjs-node_module-75790d.688c25857e7b81b1740f.js +533 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_apis_signOut_mjs-node_module-75790d.688c25857e7b81b1740f.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_tokenProvider_tokenProvider_-72f1c8.a917210f057fcfe224ad.js +6941 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_tokenProvider_tokenProvider_-72f1c8.a917210f057fcfe224ad.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js +1021 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js +59698 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_react-dom_client_js-node_modules_aws-amplify_ui-react_dist_styles_css.b43d4249e4d3dac9ad7b.js +7440 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_react-dom_client_js-node_modules_aws-amplify_ui-react_dist_styles_css.b43d4249e4d3dac9ad7b.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js +2792 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js +4859 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js.map +1 -0
- mito_ai-0.1.50.dist-info/METADATA +221 -0
- mito_ai-0.1.50.dist-info/RECORD +205 -0
- mito_ai-0.1.50.dist-info/WHEEL +4 -0
- mito_ai-0.1.50.dist-info/entry_points.txt +2 -0
- mito_ai-0.1.50.dist-info/licenses/LICENSE +3 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
from mito_ai.tests.db.test_db_constants import SNOWFLAKE
|
|
6
|
+
from mito_ai.tests.conftest import TOKEN
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# --- ADD CONNECTION ---
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_add_connection_with_auth(jp_base_url: str) -> None:
|
|
13
|
+
response = requests.post(
|
|
14
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
15
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
16
|
+
json=SNOWFLAKE,
|
|
17
|
+
)
|
|
18
|
+
if response.status_code != 200:
|
|
19
|
+
print(f"Error response: {response.text}")
|
|
20
|
+
assert response.status_code == 200
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_add_connection_with_no_auth(jp_base_url: str) -> None:
|
|
24
|
+
response = requests.post(
|
|
25
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
26
|
+
json=SNOWFLAKE,
|
|
27
|
+
)
|
|
28
|
+
assert response.status_code == 403 # Forbidden
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_add_connection_with_incorrect_auth(jp_base_url: str) -> None:
|
|
32
|
+
response = requests.post(
|
|
33
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
34
|
+
headers={"Authorization": f"token incorrect-token"},
|
|
35
|
+
json=SNOWFLAKE,
|
|
36
|
+
)
|
|
37
|
+
assert response.status_code == 403 # Forbidden
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# --- GET CONNECTIONS ---
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_get_connections_with_auth(jp_base_url: str, first_connection_id: str) -> None:
|
|
44
|
+
response = requests.get(
|
|
45
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
46
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
47
|
+
)
|
|
48
|
+
assert response.status_code == 200
|
|
49
|
+
# Ensure the response has the correct number of connections
|
|
50
|
+
assert len(response.json()) == 1
|
|
51
|
+
# Ensure the response has the correct connection details
|
|
52
|
+
assert response.json()[first_connection_id] == SNOWFLAKE
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_get_connections_with_no_auth(jp_base_url: str) -> None:
|
|
56
|
+
response = requests.get(jp_base_url + "/mito-ai/db/connections")
|
|
57
|
+
assert response.status_code == 403 # Forbidden
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_get_connections_with_incorrect_auth(jp_base_url: str) -> None:
|
|
61
|
+
response = requests.get(
|
|
62
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
63
|
+
headers={"Authorization": f"token incorrect-token"},
|
|
64
|
+
)
|
|
65
|
+
assert response.status_code == 403 # Forbidden
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# --- DELETE CONNECTION ---
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_delete_connection_with_no_auth(jp_base_url: str, first_connection_id: str) -> None:
|
|
72
|
+
response = requests.delete(
|
|
73
|
+
jp_base_url + f"/mito-ai/db/connections/{first_connection_id}",
|
|
74
|
+
)
|
|
75
|
+
assert response.status_code == 403 # Forbidden
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_delete_connection_with_incorrect_auth(
|
|
79
|
+
jp_base_url: str, first_connection_id: str
|
|
80
|
+
) -> None:
|
|
81
|
+
response = requests.delete(
|
|
82
|
+
jp_base_url + f"/mito-ai/db/connections/{first_connection_id}",
|
|
83
|
+
headers={"Authorization": f"token incorrect-token"},
|
|
84
|
+
)
|
|
85
|
+
assert response.status_code == 403 # Forbidden
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_delete_connection_with_auth(
|
|
89
|
+
jp_base_url: str, first_connection_id: str
|
|
90
|
+
) -> None:
|
|
91
|
+
response = requests.delete(
|
|
92
|
+
jp_base_url + f"/mito-ai/db/connections/{first_connection_id}",
|
|
93
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
94
|
+
)
|
|
95
|
+
assert response.status_code == 200
|
|
96
|
+
|
|
97
|
+
# Ensure the connection was deleted
|
|
98
|
+
response = requests.get(
|
|
99
|
+
jp_base_url + f"/mito-ai/db/connections",
|
|
100
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
101
|
+
)
|
|
102
|
+
assert len(response.json()) == 0
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
from mito_ai.tests.db.test_db_constants import MSSQL_CONNECTION_DETAILS
|
|
6
|
+
from mito_ai.tests.conftest import TOKEN
|
|
7
|
+
|
|
8
|
+
# To create a postgres database, run the following command:
|
|
9
|
+
# docker-compose -f mito_ai/docker/mssql/compose.yml up
|
|
10
|
+
# and then, to delete the database, run the following command:
|
|
11
|
+
# docker-compose -f mito_ai/docker/mssql/compose.yml down -v
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_add_mssql_connection(jp_base_url: str) -> None:
|
|
15
|
+
response = requests.post(
|
|
16
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
17
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
18
|
+
json=MSSQL_CONNECTION_DETAILS,
|
|
19
|
+
)
|
|
20
|
+
assert response.status_code == 200
|
|
21
|
+
|
|
22
|
+
# Get the schemas
|
|
23
|
+
response = requests.get(
|
|
24
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
25
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
26
|
+
)
|
|
27
|
+
assert response.status_code == 200
|
|
28
|
+
# Esnure that there is one scema dict in the response
|
|
29
|
+
assert len(response.json()) == 1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
from mito_ai.tests.db.test_db_constants import MYSQL_CONNECTION_DETAILS
|
|
6
|
+
from mito_ai.tests.conftest import TOKEN
|
|
7
|
+
|
|
8
|
+
# To create a mysql database, run the following command:
|
|
9
|
+
# docker-compose -f mito_ai/docker/mysql/compose.yml up
|
|
10
|
+
# and then, to delete the database, run the following command:
|
|
11
|
+
# docker-compose -f mito_ai/docker/mysql/compose.yml down -v
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_add_mysql_connection(jp_base_url: str) -> None:
|
|
15
|
+
response = requests.post(
|
|
16
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
17
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
18
|
+
json=MYSQL_CONNECTION_DETAILS,
|
|
19
|
+
)
|
|
20
|
+
assert response.status_code == 200
|
|
21
|
+
|
|
22
|
+
# Get the schemas
|
|
23
|
+
response = requests.get(
|
|
24
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
25
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
26
|
+
)
|
|
27
|
+
assert response.status_code == 200
|
|
28
|
+
# Esnure that there is one scema dict in the response
|
|
29
|
+
assert len(response.json()) == 1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
from mito_ai.tests.db.test_db_constants import ORACLE_CONNECTION_DETAILS
|
|
6
|
+
from mito_ai.tests.conftest import TOKEN
|
|
7
|
+
|
|
8
|
+
# To create a postgres database, run the following command:
|
|
9
|
+
# docker-compose -f mito_ai/docker/postgres/compose.yml up
|
|
10
|
+
# and then, to delete the database, run the following command:
|
|
11
|
+
# docker-compose -f mito_ai/docker/postgres/compose.yml down -v
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_add_oracle_connection(jp_base_url: str) -> None:
|
|
15
|
+
response = requests.post(
|
|
16
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
17
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
18
|
+
json=ORACLE_CONNECTION_DETAILS,
|
|
19
|
+
)
|
|
20
|
+
assert response.status_code == 200
|
|
21
|
+
|
|
22
|
+
# Get the schemas
|
|
23
|
+
response = requests.get(
|
|
24
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
25
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
26
|
+
)
|
|
27
|
+
assert response.status_code == 200
|
|
28
|
+
# Esnure that there is one scema dict in the response
|
|
29
|
+
assert len(response.json()) == 1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
from mito_ai.tests.db.test_db_constants import POSTGRES_CONNECTION_DETAILS
|
|
6
|
+
from mito_ai.tests.conftest import TOKEN
|
|
7
|
+
|
|
8
|
+
# To create a postgres database, run the following command:
|
|
9
|
+
# docker-compose -f mito_ai/docker/postgres/compose.yml up
|
|
10
|
+
# and then, to delete the database, run the following command:
|
|
11
|
+
# docker-compose -f mito_ai/docker/postgres/compose.yml down -v
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_add_postgres_connection(jp_base_url: str) -> None:
|
|
15
|
+
response = requests.post(
|
|
16
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
17
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
18
|
+
json=POSTGRES_CONNECTION_DETAILS,
|
|
19
|
+
)
|
|
20
|
+
assert response.status_code == 200
|
|
21
|
+
|
|
22
|
+
# Get the schemas
|
|
23
|
+
response = requests.get(
|
|
24
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
25
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
26
|
+
)
|
|
27
|
+
assert response.status_code == 200
|
|
28
|
+
# Esnure that there is one scema dict in the response
|
|
29
|
+
assert len(response.json()) == 1
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
import requests
|
|
6
|
+
from mito_ai.tests.db.test_db_constants import SNOWFLAKE
|
|
7
|
+
from mito_ai.tests.conftest import TOKEN
|
|
8
|
+
|
|
9
|
+
# --- GET SCHEMAS ---
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_get_schemas_with_auth(jp_base_url: str) -> None:
|
|
13
|
+
# Add a connection to get a schema
|
|
14
|
+
response = requests.post(
|
|
15
|
+
jp_base_url + f"/mito-ai/db/connections",
|
|
16
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
17
|
+
json=SNOWFLAKE,
|
|
18
|
+
)
|
|
19
|
+
assert response.status_code == 200
|
|
20
|
+
|
|
21
|
+
# Get the schemas
|
|
22
|
+
response = requests.get(
|
|
23
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
24
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
25
|
+
)
|
|
26
|
+
assert response.status_code == 200
|
|
27
|
+
# Esnure that there is one scema dict in the response
|
|
28
|
+
assert len(response.json()) == 1
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_ensure_no_application_databases(jp_base_url: str, first_connection_id: str) -> None:
|
|
32
|
+
# We currently don't support Snowflake application databases.
|
|
33
|
+
# This test ensures that we don't crawl application databases.
|
|
34
|
+
|
|
35
|
+
response = requests.get(
|
|
36
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
37
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
crawled_databases = response.json()[first_connection_id]["databases"].keys()
|
|
41
|
+
assert len(crawled_databases) > 0
|
|
42
|
+
assert "SNOWFLAKE" not in crawled_databases
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_get_schemas_with_no_auth(jp_base_url: str) -> None:
|
|
46
|
+
response = requests.get(
|
|
47
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
48
|
+
)
|
|
49
|
+
assert response.status_code == 403 # Forbidden
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_get_schemas_with_incorrect_auth(jp_base_url: str) -> None:
|
|
53
|
+
response = requests.get(
|
|
54
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
55
|
+
headers={"Authorization": f"token incorrect-token"},
|
|
56
|
+
)
|
|
57
|
+
assert response.status_code == 403 # Forbidden
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# --- DELETE SCHEMA ---
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_delete_schema_with_auth(jp_base_url: str, first_connection_id: str) -> None:
|
|
64
|
+
response = requests.delete(
|
|
65
|
+
jp_base_url + f"/mito-ai/db/schemas/{first_connection_id}",
|
|
66
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
67
|
+
)
|
|
68
|
+
assert response.status_code == 200
|
|
69
|
+
|
|
70
|
+
# Ensure the schema was deleted
|
|
71
|
+
response = requests.get(
|
|
72
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
73
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
74
|
+
)
|
|
75
|
+
assert response.status_code == 200
|
|
76
|
+
assert len(response.json()) == 0
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_delete_schema_with_no_auth(jp_base_url: str, first_connection_id: str) -> None:
|
|
80
|
+
response = requests.delete(
|
|
81
|
+
jp_base_url + f"/mito-ai/db/schemas/{first_connection_id}",
|
|
82
|
+
)
|
|
83
|
+
assert response.status_code == 403 # Forbidden
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_delete_schema_with_incorrect_auth(
|
|
87
|
+
jp_base_url: str, first_connection_id: str
|
|
88
|
+
) -> None:
|
|
89
|
+
response = requests.delete(
|
|
90
|
+
jp_base_url + f"/mito-ai/db/schemas/{first_connection_id}",
|
|
91
|
+
headers={"Authorization": f"token incorrect-token"},
|
|
92
|
+
)
|
|
93
|
+
assert response.status_code == 403 # Forbidden
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import requests
|
|
6
|
+
from mito_ai.tests.db.test_db_constants import (
|
|
7
|
+
SQLITE_TEST_DB_PATH,
|
|
8
|
+
SQLITE_CONNECTION_DETAILS,
|
|
9
|
+
)
|
|
10
|
+
from mito_ai.tests.conftest import TOKEN
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_add_sqlite_connection(jp_base_url: str) -> None:
|
|
14
|
+
# Check for the sqlite database
|
|
15
|
+
assert os.path.exists(SQLITE_TEST_DB_PATH)
|
|
16
|
+
|
|
17
|
+
response = requests.post(
|
|
18
|
+
jp_base_url + "/mito-ai/db/connections",
|
|
19
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
20
|
+
json=SQLITE_CONNECTION_DETAILS,
|
|
21
|
+
)
|
|
22
|
+
assert response.status_code == 200
|
|
23
|
+
|
|
24
|
+
# Get the schemas
|
|
25
|
+
response = requests.get(
|
|
26
|
+
jp_base_url + f"/mito-ai/db/schemas",
|
|
27
|
+
headers={"Authorization": f"token {TOKEN}"},
|
|
28
|
+
)
|
|
29
|
+
assert response.status_code == 200
|
|
30
|
+
# Esnure that there is one scema dict in the response
|
|
31
|
+
assert len(response.json()) == 1
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from typing import Final
|
|
6
|
+
from mito_ai.utils.schema import MITO_FOLDER
|
|
7
|
+
|
|
8
|
+
DB_DIR_PATH: Final[str] = os.path.join(MITO_FOLDER, "db")
|
|
9
|
+
CONNECTIONS_PATH: Final[str] = os.path.join(DB_DIR_PATH, "connections.json")
|
|
10
|
+
SCHEMAS_PATH: Final[str] = os.path.join(DB_DIR_PATH, "schemas.json")
|
|
11
|
+
BACKUP_DB_DIR_PATH: Final[str] = os.path.join(MITO_FOLDER, "db_backup")
|
|
12
|
+
MSSQL_CONNECTION_DETAILS = {
|
|
13
|
+
"type": "mssql",
|
|
14
|
+
"username": os.environ.get("MSSQL_USERNAME"),
|
|
15
|
+
"password": os.environ.get("MSSQL_PASSWORD"),
|
|
16
|
+
"host": os.environ.get("MSSQL_HOST"),
|
|
17
|
+
"port": "1433",
|
|
18
|
+
"database": "Northwind",
|
|
19
|
+
"odbc_driver_version": "18",
|
|
20
|
+
}
|
|
21
|
+
MYSQL_CONNECTION_DETAILS = {
|
|
22
|
+
"type": "mysql",
|
|
23
|
+
"username": os.environ.get("MYSQL_USERNAME"),
|
|
24
|
+
"password": os.environ.get("MYSQL_PASSWORD"),
|
|
25
|
+
"host": os.environ.get("MYSQL_HOST"),
|
|
26
|
+
"port": "3306",
|
|
27
|
+
"database": "Northwind",
|
|
28
|
+
}
|
|
29
|
+
ORACLE_CONNECTION_DETAILS = {
|
|
30
|
+
"type": "oracle",
|
|
31
|
+
"username": os.environ.get("ORACLE_USERNAME"),
|
|
32
|
+
"password": os.environ.get("ORACLE_PASSWORD"),
|
|
33
|
+
"host": os.environ.get("ORACLE_HOST"),
|
|
34
|
+
"port": "1521",
|
|
35
|
+
"service_name": "ORCL",
|
|
36
|
+
}
|
|
37
|
+
POSTGRES_CONNECTION_DETAILS = {
|
|
38
|
+
"type": "postgres",
|
|
39
|
+
"username": os.environ.get("POSTGRES_USERNAME"),
|
|
40
|
+
"password": os.environ.get("POSTGRES_PASSWORD"),
|
|
41
|
+
"host": os.environ.get("POSTGRES_HOST"),
|
|
42
|
+
"port": "5432",
|
|
43
|
+
"database": "postgres",
|
|
44
|
+
}
|
|
45
|
+
SNOWFLAKE = {
|
|
46
|
+
"type": "snowflake",
|
|
47
|
+
"username": os.environ.get("SNOWFLAKE_USERNAME"),
|
|
48
|
+
"password": os.environ.get("SNOWFLAKE_PASSWORD"),
|
|
49
|
+
"account": os.environ.get("SNOWFLAKE_ACCOUNT"),
|
|
50
|
+
"warehouse": "COMPUTE_WH",
|
|
51
|
+
}
|
|
52
|
+
SQLITE_TEST_DB_PATH: Final[str] = os.path.join(
|
|
53
|
+
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
|
|
54
|
+
"tests",
|
|
55
|
+
"data",
|
|
56
|
+
"stock_data.sqlite3",
|
|
57
|
+
)
|
|
58
|
+
SQLITE_CONNECTION_DETAILS = {
|
|
59
|
+
"type": "sqlite",
|
|
60
|
+
"database": SQLITE_TEST_DB_PATH,
|
|
61
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import zipfile
|
|
5
|
+
import logging
|
|
6
|
+
from mito_ai.app_deploy.app_deploy_utils import add_files_to_zip
|
|
7
|
+
from mito_ai.path_utils import AbsoluteNotebookDirPath
|
|
8
|
+
|
|
9
|
+
class TestAddFilesToZip:
|
|
10
|
+
"""Test cases for add_files_to_zip helper function"""
|
|
11
|
+
|
|
12
|
+
def test_files_added_correctly(self, tmp_path):
|
|
13
|
+
"""Ensure individual files are added correctly to the zip"""
|
|
14
|
+
# Create files
|
|
15
|
+
f1 = tmp_path / "file1.txt"
|
|
16
|
+
f1.write_text("file1 content")
|
|
17
|
+
f2 = tmp_path / "file2.txt"
|
|
18
|
+
f2.write_text("file2 content")
|
|
19
|
+
|
|
20
|
+
zip_path = tmp_path / "test.zip"
|
|
21
|
+
add_files_to_zip(str(zip_path), AbsoluteNotebookDirPath(str(tmp_path)), ["file1.txt", "file2.txt"], 'test-app-file-name.py')
|
|
22
|
+
|
|
23
|
+
with zipfile.ZipFile(zip_path, "r") as zf:
|
|
24
|
+
names = zf.namelist()
|
|
25
|
+
assert "file1.txt" in names
|
|
26
|
+
assert "file2.txt" in names
|
|
27
|
+
assert len(names) == 2
|
|
28
|
+
|
|
29
|
+
def test_renames_app_file(self, tmp_path):
|
|
30
|
+
"""Ensure individual files are added correctly to the zip"""
|
|
31
|
+
# Create files
|
|
32
|
+
f1 = tmp_path / "original-file-name.py"
|
|
33
|
+
f1.write_text("file1 content")
|
|
34
|
+
f2 = tmp_path / "file2.txt"
|
|
35
|
+
f2.write_text("file2 content")
|
|
36
|
+
|
|
37
|
+
zip_path = tmp_path / "test.zip"
|
|
38
|
+
add_files_to_zip(str(zip_path), AbsoluteNotebookDirPath(str(tmp_path)), ["original-file-name.py", "file2.txt"], 'original-file-name.py')
|
|
39
|
+
|
|
40
|
+
with zipfile.ZipFile(zip_path, "r") as zf:
|
|
41
|
+
names = zf.namelist()
|
|
42
|
+
assert "app.py" in names
|
|
43
|
+
assert "file2.txt" in names
|
|
44
|
+
assert len(names) == 2
|
|
45
|
+
|
|
46
|
+
def test_directories_added_recursively(self, tmp_path):
|
|
47
|
+
"""Ensure directories are added recursively with correct relative paths"""
|
|
48
|
+
nested = tmp_path / "folder"
|
|
49
|
+
nested.mkdir()
|
|
50
|
+
(nested / "nested1.txt").write_text("nested1 content")
|
|
51
|
+
subfolder = nested / "sub"
|
|
52
|
+
subfolder.mkdir()
|
|
53
|
+
(subfolder / "nested2.txt").write_text("nested2 content")
|
|
54
|
+
|
|
55
|
+
zip_path = tmp_path / "test.zip"
|
|
56
|
+
add_files_to_zip(str(zip_path), AbsoluteNotebookDirPath(str(tmp_path)), ["folder"], 'test-app.py')
|
|
57
|
+
|
|
58
|
+
with zipfile.ZipFile(zip_path, "r") as zf:
|
|
59
|
+
names = zf.namelist()
|
|
60
|
+
assert "folder/nested1.txt" in names
|
|
61
|
+
assert "folder/sub/nested2.txt" in names
|
|
62
|
+
|
|
63
|
+
def test_missing_files_skipped(self, tmp_path, caplog):
|
|
64
|
+
"""Ensure missing files do not break the function and warning is logged"""
|
|
65
|
+
caplog.set_level(logging.WARNING)
|
|
66
|
+
zip_path = tmp_path / "test.zip"
|
|
67
|
+
add_files_to_zip(str(zip_path), AbsoluteNotebookDirPath(str(tmp_path)), ["does_not_exist.txt"], 'test-app.py', logger=logging.getLogger())
|
|
68
|
+
|
|
69
|
+
# Zip should exist but be empty
|
|
70
|
+
with zipfile.ZipFile(zip_path, "r") as zf:
|
|
71
|
+
assert zf.namelist() == []
|
|
72
|
+
|
|
73
|
+
# Check warning was logged
|
|
74
|
+
assert any("Skipping missing file" in record.message for record in caplog.records)
|
|
75
|
+
|
|
76
|
+
def test_arcname_paths_correct(self, tmp_path):
|
|
77
|
+
"""Ensure arcname paths inside zip preserve relative paths to base_path"""
|
|
78
|
+
(tmp_path / "file.txt").write_text("content")
|
|
79
|
+
folder = tmp_path / "folder"
|
|
80
|
+
folder.mkdir()
|
|
81
|
+
(folder / "nested.txt").write_text("nested content")
|
|
82
|
+
|
|
83
|
+
zip_path = tmp_path / "test.zip"
|
|
84
|
+
add_files_to_zip(str(zip_path), AbsoluteNotebookDirPath(str(tmp_path)), ["file.txt", "folder"], 'test-app.py')
|
|
85
|
+
|
|
86
|
+
with zipfile.ZipFile(zip_path, "r") as zf:
|
|
87
|
+
names = zf.namelist()
|
|
88
|
+
assert "file.txt" in names
|
|
89
|
+
assert "folder/nested.txt" in names
|