singlestoredb 1.16.1__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.
- singlestoredb/__init__.py +75 -0
- singlestoredb/ai/__init__.py +2 -0
- singlestoredb/ai/chat.py +139 -0
- singlestoredb/ai/embeddings.py +128 -0
- singlestoredb/alchemy/__init__.py +90 -0
- singlestoredb/apps/__init__.py +3 -0
- singlestoredb/apps/_cloud_functions.py +90 -0
- singlestoredb/apps/_config.py +72 -0
- singlestoredb/apps/_connection_info.py +18 -0
- singlestoredb/apps/_dashboards.py +47 -0
- singlestoredb/apps/_process.py +32 -0
- singlestoredb/apps/_python_udfs.py +100 -0
- singlestoredb/apps/_stdout_supress.py +30 -0
- singlestoredb/apps/_uvicorn_util.py +36 -0
- singlestoredb/auth.py +245 -0
- singlestoredb/config.py +484 -0
- singlestoredb/connection.py +1487 -0
- singlestoredb/converters.py +950 -0
- singlestoredb/docstring/__init__.py +33 -0
- singlestoredb/docstring/attrdoc.py +126 -0
- singlestoredb/docstring/common.py +230 -0
- singlestoredb/docstring/epydoc.py +267 -0
- singlestoredb/docstring/google.py +412 -0
- singlestoredb/docstring/numpydoc.py +562 -0
- singlestoredb/docstring/parser.py +100 -0
- singlestoredb/docstring/py.typed +1 -0
- singlestoredb/docstring/rest.py +256 -0
- singlestoredb/docstring/tests/__init__.py +1 -0
- singlestoredb/docstring/tests/_pydoctor.py +21 -0
- singlestoredb/docstring/tests/test_epydoc.py +729 -0
- singlestoredb/docstring/tests/test_google.py +1007 -0
- singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
- singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
- singlestoredb/docstring/tests/test_parser.py +248 -0
- singlestoredb/docstring/tests/test_rest.py +547 -0
- singlestoredb/docstring/tests/test_util.py +70 -0
- singlestoredb/docstring/util.py +141 -0
- singlestoredb/exceptions.py +120 -0
- singlestoredb/functions/__init__.py +16 -0
- singlestoredb/functions/decorator.py +201 -0
- singlestoredb/functions/dtypes.py +1793 -0
- singlestoredb/functions/ext/__init__.py +1 -0
- singlestoredb/functions/ext/arrow.py +375 -0
- singlestoredb/functions/ext/asgi.py +2133 -0
- singlestoredb/functions/ext/json.py +420 -0
- singlestoredb/functions/ext/mmap.py +413 -0
- singlestoredb/functions/ext/rowdat_1.py +724 -0
- singlestoredb/functions/ext/timer.py +89 -0
- singlestoredb/functions/ext/utils.py +218 -0
- singlestoredb/functions/signature.py +1578 -0
- singlestoredb/functions/typing/__init__.py +41 -0
- singlestoredb/functions/typing/numpy.py +20 -0
- singlestoredb/functions/typing/pandas.py +2 -0
- singlestoredb/functions/typing/polars.py +2 -0
- singlestoredb/functions/typing/pyarrow.py +2 -0
- singlestoredb/functions/utils.py +421 -0
- singlestoredb/fusion/__init__.py +11 -0
- singlestoredb/fusion/graphql.py +213 -0
- singlestoredb/fusion/handler.py +916 -0
- singlestoredb/fusion/handlers/__init__.py +0 -0
- singlestoredb/fusion/handlers/export.py +525 -0
- singlestoredb/fusion/handlers/files.py +690 -0
- singlestoredb/fusion/handlers/job.py +660 -0
- singlestoredb/fusion/handlers/models.py +250 -0
- singlestoredb/fusion/handlers/stage.py +502 -0
- singlestoredb/fusion/handlers/utils.py +324 -0
- singlestoredb/fusion/handlers/workspace.py +956 -0
- singlestoredb/fusion/registry.py +249 -0
- singlestoredb/fusion/result.py +399 -0
- singlestoredb/http/__init__.py +27 -0
- singlestoredb/http/connection.py +1267 -0
- singlestoredb/magics/__init__.py +34 -0
- singlestoredb/magics/run_personal.py +137 -0
- singlestoredb/magics/run_shared.py +134 -0
- singlestoredb/management/__init__.py +9 -0
- singlestoredb/management/billing_usage.py +148 -0
- singlestoredb/management/cluster.py +462 -0
- singlestoredb/management/export.py +295 -0
- singlestoredb/management/files.py +1102 -0
- singlestoredb/management/inference_api.py +105 -0
- singlestoredb/management/job.py +887 -0
- singlestoredb/management/manager.py +373 -0
- singlestoredb/management/organization.py +226 -0
- singlestoredb/management/region.py +169 -0
- singlestoredb/management/utils.py +423 -0
- singlestoredb/management/workspace.py +1927 -0
- singlestoredb/mysql/__init__.py +177 -0
- singlestoredb/mysql/_auth.py +298 -0
- singlestoredb/mysql/charset.py +214 -0
- singlestoredb/mysql/connection.py +2032 -0
- singlestoredb/mysql/constants/CLIENT.py +38 -0
- singlestoredb/mysql/constants/COMMAND.py +32 -0
- singlestoredb/mysql/constants/CR.py +78 -0
- singlestoredb/mysql/constants/ER.py +474 -0
- singlestoredb/mysql/constants/EXTENDED_TYPE.py +3 -0
- singlestoredb/mysql/constants/FIELD_TYPE.py +48 -0
- singlestoredb/mysql/constants/FLAG.py +15 -0
- singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
- singlestoredb/mysql/constants/VECTOR_TYPE.py +6 -0
- singlestoredb/mysql/constants/__init__.py +0 -0
- singlestoredb/mysql/converters.py +271 -0
- singlestoredb/mysql/cursors.py +896 -0
- singlestoredb/mysql/err.py +92 -0
- singlestoredb/mysql/optionfile.py +20 -0
- singlestoredb/mysql/protocol.py +450 -0
- singlestoredb/mysql/tests/__init__.py +19 -0
- singlestoredb/mysql/tests/base.py +126 -0
- singlestoredb/mysql/tests/conftest.py +37 -0
- singlestoredb/mysql/tests/test_DictCursor.py +132 -0
- singlestoredb/mysql/tests/test_SSCursor.py +141 -0
- singlestoredb/mysql/tests/test_basic.py +452 -0
- singlestoredb/mysql/tests/test_connection.py +851 -0
- singlestoredb/mysql/tests/test_converters.py +58 -0
- singlestoredb/mysql/tests/test_cursor.py +141 -0
- singlestoredb/mysql/tests/test_err.py +16 -0
- singlestoredb/mysql/tests/test_issues.py +514 -0
- singlestoredb/mysql/tests/test_load_local.py +75 -0
- singlestoredb/mysql/tests/test_nextset.py +88 -0
- singlestoredb/mysql/tests/test_optionfile.py +27 -0
- singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
- singlestoredb/mysql/times.py +23 -0
- singlestoredb/notebook/__init__.py +16 -0
- singlestoredb/notebook/_objects.py +213 -0
- singlestoredb/notebook/_portal.py +352 -0
- singlestoredb/py.typed +0 -0
- singlestoredb/pytest.py +352 -0
- singlestoredb/server/__init__.py +0 -0
- singlestoredb/server/docker.py +452 -0
- singlestoredb/server/free_tier.py +267 -0
- singlestoredb/tests/__init__.py +0 -0
- singlestoredb/tests/alltypes.sql +307 -0
- singlestoredb/tests/alltypes_no_nulls.sql +208 -0
- singlestoredb/tests/empty.sql +0 -0
- singlestoredb/tests/ext_funcs/__init__.py +702 -0
- singlestoredb/tests/local_infile.csv +3 -0
- singlestoredb/tests/test.ipynb +18 -0
- singlestoredb/tests/test.sql +680 -0
- singlestoredb/tests/test2.ipynb +18 -0
- singlestoredb/tests/test2.sql +1 -0
- singlestoredb/tests/test_basics.py +1332 -0
- singlestoredb/tests/test_config.py +318 -0
- singlestoredb/tests/test_connection.py +3103 -0
- singlestoredb/tests/test_dbapi.py +27 -0
- singlestoredb/tests/test_exceptions.py +45 -0
- singlestoredb/tests/test_ext_func.py +1472 -0
- singlestoredb/tests/test_ext_func_data.py +1101 -0
- singlestoredb/tests/test_fusion.py +1527 -0
- singlestoredb/tests/test_http.py +288 -0
- singlestoredb/tests/test_management.py +1599 -0
- singlestoredb/tests/test_plugin.py +33 -0
- singlestoredb/tests/test_results.py +171 -0
- singlestoredb/tests/test_types.py +132 -0
- singlestoredb/tests/test_udf.py +737 -0
- singlestoredb/tests/test_udf_returns.py +459 -0
- singlestoredb/tests/test_vectorstore.py +51 -0
- singlestoredb/tests/test_xdict.py +333 -0
- singlestoredb/tests/utils.py +141 -0
- singlestoredb/types.py +373 -0
- singlestoredb/utils/__init__.py +0 -0
- singlestoredb/utils/config.py +950 -0
- singlestoredb/utils/convert_rows.py +69 -0
- singlestoredb/utils/debug.py +13 -0
- singlestoredb/utils/dtypes.py +205 -0
- singlestoredb/utils/events.py +65 -0
- singlestoredb/utils/mogrify.py +151 -0
- singlestoredb/utils/results.py +585 -0
- singlestoredb/utils/xdict.py +425 -0
- singlestoredb/vectorstore.py +192 -0
- singlestoredb/warnings.py +5 -0
- singlestoredb-1.16.1.dist-info/METADATA +165 -0
- singlestoredb-1.16.1.dist-info/RECORD +183 -0
- singlestoredb-1.16.1.dist-info/WHEEL +5 -0
- singlestoredb-1.16.1.dist-info/entry_points.txt +2 -0
- singlestoredb-1.16.1.dist-info/licenses/LICENSE +201 -0
- singlestoredb-1.16.1.dist-info/top_level.txt +3 -0
- sqlx/__init__.py +4 -0
- sqlx/magic.py +113 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Utilities for running singlestoredb-dev Docker image."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import atexit
|
|
6
|
+
import os
|
|
7
|
+
import platform
|
|
8
|
+
import secrets
|
|
9
|
+
import signal
|
|
10
|
+
import socket
|
|
11
|
+
import subprocess
|
|
12
|
+
import time
|
|
13
|
+
import urllib.parse
|
|
14
|
+
from contextlib import closing
|
|
15
|
+
from types import TracebackType
|
|
16
|
+
from typing import Any
|
|
17
|
+
from typing import Dict
|
|
18
|
+
from typing import List
|
|
19
|
+
from typing import Optional
|
|
20
|
+
from typing import Type
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
import docker
|
|
24
|
+
has_docker = True
|
|
25
|
+
except ImportError:
|
|
26
|
+
has_docker = False
|
|
27
|
+
raise RuntimeError('docker python package is not installed')
|
|
28
|
+
|
|
29
|
+
from .. import connect
|
|
30
|
+
from ..connection import Connection
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
import pymongo
|
|
34
|
+
has_pymongo = True
|
|
35
|
+
except ImportError:
|
|
36
|
+
has_pymongo = False
|
|
37
|
+
|
|
38
|
+
DEFAULT_IMAGE = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest'
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SingleStoreDB:
|
|
42
|
+
"""
|
|
43
|
+
Manager for SingleStoreDB server running in Docker.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
-----------
|
|
47
|
+
name : str, optional
|
|
48
|
+
Name of the container.
|
|
49
|
+
password : str, optional
|
|
50
|
+
Password for the SingleStoreDB server.
|
|
51
|
+
license : str, optional
|
|
52
|
+
License key for SingleStoreDB.
|
|
53
|
+
enable_kai : bool, optional
|
|
54
|
+
Enable Kai (MongoDB) server.
|
|
55
|
+
server_port : int, optional
|
|
56
|
+
Port for the SingleStoreDB server.
|
|
57
|
+
studio_port : int, optional
|
|
58
|
+
Port for the SingleStoreDB Studio.
|
|
59
|
+
data_api_port : int, optional
|
|
60
|
+
Port for the SingleStoreDB Data API.
|
|
61
|
+
kai_port : int, optional
|
|
62
|
+
Port for the Kai server.
|
|
63
|
+
hostname : str, optional
|
|
64
|
+
Hostname for the container.
|
|
65
|
+
data_dir : str, optional
|
|
66
|
+
Path to the data directory.
|
|
67
|
+
logs_dir : str, optional
|
|
68
|
+
Path to the logs directory.
|
|
69
|
+
server_dir : str, optional
|
|
70
|
+
Path to the server directory.
|
|
71
|
+
global_vars : dict, optional
|
|
72
|
+
Global variables to set in the SingleStoreDB server.
|
|
73
|
+
init_sql : str, optional
|
|
74
|
+
Path to an SQL file to run on startup.
|
|
75
|
+
image : str, optional
|
|
76
|
+
Docker image to use.
|
|
77
|
+
database : str, optional
|
|
78
|
+
Default database to connect to.
|
|
79
|
+
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
user: str
|
|
83
|
+
password: str
|
|
84
|
+
kai_enabled: bool
|
|
85
|
+
server_port: int
|
|
86
|
+
studio_port: int
|
|
87
|
+
data_api_port: int
|
|
88
|
+
kai_port: Optional[int]
|
|
89
|
+
data_dir: Optional[str]
|
|
90
|
+
logs_dir: Optional[str]
|
|
91
|
+
server_dir: Optional[str]
|
|
92
|
+
|
|
93
|
+
def __init__(
|
|
94
|
+
self,
|
|
95
|
+
name: Optional[str] = None,
|
|
96
|
+
*,
|
|
97
|
+
password: Optional[str] = None,
|
|
98
|
+
license: Optional[str] = None,
|
|
99
|
+
enable_kai: bool = False,
|
|
100
|
+
server_port: Optional[int] = None,
|
|
101
|
+
studio_port: Optional[int] = None,
|
|
102
|
+
data_api_port: Optional[int] = None,
|
|
103
|
+
kai_port: Optional[int] = None,
|
|
104
|
+
hostname: Optional[str] = None,
|
|
105
|
+
data_dir: Optional[str] = None,
|
|
106
|
+
logs_dir: Optional[str] = None,
|
|
107
|
+
server_dir: Optional[str] = None,
|
|
108
|
+
global_vars: Optional[Dict[str, Any]] = None,
|
|
109
|
+
init_sql: Optional[str] = None,
|
|
110
|
+
image: str = DEFAULT_IMAGE,
|
|
111
|
+
database: Optional[str] = None,
|
|
112
|
+
):
|
|
113
|
+
self.kai_enabled = enable_kai
|
|
114
|
+
self.kai_port = None
|
|
115
|
+
self.server_port = server_port or self._get_available_port()
|
|
116
|
+
self.studio_port = studio_port or self._get_available_port()
|
|
117
|
+
self.data_api_port = data_api_port or self._get_available_port()
|
|
118
|
+
self.data_dir = data_dir
|
|
119
|
+
self.logs_dir = logs_dir
|
|
120
|
+
self.server_dir = server_dir
|
|
121
|
+
self.user = 'root'
|
|
122
|
+
|
|
123
|
+
# Setup container ports
|
|
124
|
+
ports = {
|
|
125
|
+
'3306/tcp': self.server_port,
|
|
126
|
+
'8080/tcp': self.studio_port,
|
|
127
|
+
'9000/tcp': self.data_api_port,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if enable_kai:
|
|
131
|
+
self.kai_port = kai_port or self._get_available_port()
|
|
132
|
+
ports['27017/tcp'] = self.kai_port
|
|
133
|
+
|
|
134
|
+
# Setup password
|
|
135
|
+
self.password = password or secrets.token_urlsafe(10)
|
|
136
|
+
|
|
137
|
+
# Setup license value
|
|
138
|
+
if license is None:
|
|
139
|
+
license = os.environ.get('SINGLESTORE_LICENSE', None)
|
|
140
|
+
|
|
141
|
+
# Setup environment variables for the container
|
|
142
|
+
env = {'ROOT_PASSWORD': self.password}
|
|
143
|
+
|
|
144
|
+
if license:
|
|
145
|
+
env['SINGLESTORE_LICENSE'] = license
|
|
146
|
+
|
|
147
|
+
if enable_kai:
|
|
148
|
+
env['ENABLE_KAI'] = '1'
|
|
149
|
+
|
|
150
|
+
# Construct Docker arguments
|
|
151
|
+
kwargs = {
|
|
152
|
+
'environment': env,
|
|
153
|
+
'ports': ports,
|
|
154
|
+
'detach': True,
|
|
155
|
+
'auto_remove': True,
|
|
156
|
+
'remove': True,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if 'macOS' in platform.platform():
|
|
160
|
+
kwargs['platform'] = 'linux/amd64'
|
|
161
|
+
|
|
162
|
+
for pname, pvalue in [
|
|
163
|
+
('name', name),
|
|
164
|
+
('hostname', hostname),
|
|
165
|
+
]:
|
|
166
|
+
if pvalue is not None:
|
|
167
|
+
kwargs[pname] = pvalue
|
|
168
|
+
|
|
169
|
+
# Setup volumes
|
|
170
|
+
volumes: Dict[str, Dict[str, str]] = {}
|
|
171
|
+
if data_dir:
|
|
172
|
+
volumes[data_dir] = {'bind': '/data', 'mode': 'rw'}
|
|
173
|
+
if logs_dir:
|
|
174
|
+
volumes[logs_dir] = {'bind': '/logs', 'mode': 'ro'}
|
|
175
|
+
if server_dir:
|
|
176
|
+
volumes[server_dir] = {'bind': '/server', 'mode': 'ro'}
|
|
177
|
+
if init_sql:
|
|
178
|
+
volumes[os.path.abspath(init_sql)] = {'bind': '/init.sql', 'mode': 'ro'}
|
|
179
|
+
if volumes:
|
|
180
|
+
kwargs['volumes'] = volumes
|
|
181
|
+
|
|
182
|
+
# Setup global vars
|
|
183
|
+
for k, v in (global_vars or {}).items():
|
|
184
|
+
env['SINGLESTORE_SET_GLOBAL_' + k.upper()] = str(v)
|
|
185
|
+
|
|
186
|
+
self._saved_server_urls: Dict[str, Optional[str]] = {}
|
|
187
|
+
|
|
188
|
+
docker_client = docker.from_env()
|
|
189
|
+
self.container = docker_client.containers.run(image, **kwargs)
|
|
190
|
+
|
|
191
|
+
# Make sure container gets cleaned up at exit
|
|
192
|
+
atexit.register(self.stop)
|
|
193
|
+
signal.signal(signal.SIGINT, self.stop)
|
|
194
|
+
signal.signal(signal.SIGTERM, self.stop)
|
|
195
|
+
|
|
196
|
+
if not self._wait_on_ready():
|
|
197
|
+
raise RuntimeError('server did not come up properly')
|
|
198
|
+
|
|
199
|
+
self._database = database
|
|
200
|
+
self._set_server_urls()
|
|
201
|
+
|
|
202
|
+
def __str__(self) -> str:
|
|
203
|
+
return f"SingleStoreDB('{self.connection_url}')"
|
|
204
|
+
|
|
205
|
+
def __repr__(self) -> str:
|
|
206
|
+
return str(self)
|
|
207
|
+
|
|
208
|
+
def _get_available_port(self) -> int:
|
|
209
|
+
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
|
|
210
|
+
s.bind(('', 0))
|
|
211
|
+
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
212
|
+
return s.getsockname()[1]
|
|
213
|
+
|
|
214
|
+
def _set_server_urls(self) -> None:
|
|
215
|
+
self._saved_server_urls['DATABASE_URL'] = os.environ.get('DATABASE_URL')
|
|
216
|
+
os.environ['DATABASE_URL'] = self.connection_url
|
|
217
|
+
self._saved_server_urls['SINGLESTOREDB_URL'] = os.environ.get('SINGLESTOREDB_URL')
|
|
218
|
+
os.environ['SINGLESTOREDB_URL'] = self.connection_url
|
|
219
|
+
|
|
220
|
+
def _restore_server_urls(self) -> None:
|
|
221
|
+
try:
|
|
222
|
+
for k, v in self._saved_server_urls.items():
|
|
223
|
+
if v is None:
|
|
224
|
+
del os.environ[k]
|
|
225
|
+
else:
|
|
226
|
+
os.environ[k] = v
|
|
227
|
+
except KeyError:
|
|
228
|
+
pass
|
|
229
|
+
|
|
230
|
+
def _wait_on_ready(self) -> bool:
|
|
231
|
+
for i in range(80):
|
|
232
|
+
for line in self.logs():
|
|
233
|
+
if 'INFO: ' in line:
|
|
234
|
+
return True
|
|
235
|
+
time.sleep(3)
|
|
236
|
+
return False
|
|
237
|
+
|
|
238
|
+
def logs(self) -> List[str]:
|
|
239
|
+
return self.container.logs().decode('utf8').split('\n')
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def connection_url(self) -> str:
|
|
243
|
+
"""Connection URL for the SingleStoreDB server."""
|
|
244
|
+
dbname = f'/{self._database}' if self._database else ''
|
|
245
|
+
password = urllib.parse.quote_plus(self.password)
|
|
246
|
+
return f'singlestoredb://{self.user}:{password}@' + \
|
|
247
|
+
f'localhost:{self.server_port}{dbname}'
|
|
248
|
+
|
|
249
|
+
@property
|
|
250
|
+
def http_connection_url(self) -> str:
|
|
251
|
+
"""HTTP Connection URL for the SingleStoreDB server."""
|
|
252
|
+
dbname = f'/{self._database}' if self._database else ''
|
|
253
|
+
password = urllib.parse.quote_plus(self.password)
|
|
254
|
+
return f'singlestoredb+http://{self.user}:{password}@' + \
|
|
255
|
+
f'localhost:{self.data_api_port}{dbname}'
|
|
256
|
+
|
|
257
|
+
def connect(
|
|
258
|
+
self,
|
|
259
|
+
use_data_api: bool = False,
|
|
260
|
+
**kwargs: Any,
|
|
261
|
+
) -> Connection:
|
|
262
|
+
"""
|
|
263
|
+
Connect to the SingleStoreDB server.
|
|
264
|
+
|
|
265
|
+
Parameters
|
|
266
|
+
-----------
|
|
267
|
+
use_data_api : bool, optional
|
|
268
|
+
Use the Data API for the connection.
|
|
269
|
+
**kwargs : Any, optional
|
|
270
|
+
Additional keyword arguments to pass to the connection.
|
|
271
|
+
|
|
272
|
+
Returns
|
|
273
|
+
--------
|
|
274
|
+
Connection : Connection to the SingleStoreDB server.
|
|
275
|
+
|
|
276
|
+
"""
|
|
277
|
+
if use_data_api:
|
|
278
|
+
return connect(self.http_connection_url, **kwargs)
|
|
279
|
+
return connect(self.connection_url, **kwargs)
|
|
280
|
+
|
|
281
|
+
@property
|
|
282
|
+
def kai_url(self) -> Optional[str]:
|
|
283
|
+
"""Connection URL for the Kai (MongoDB) server."""
|
|
284
|
+
if not self.kai_enabled:
|
|
285
|
+
return None
|
|
286
|
+
password = urllib.parse.quote_plus(self.password)
|
|
287
|
+
return f'mongodb://{self.user}:{password}@' + \
|
|
288
|
+
f'localhost:{self.kai_port}/?authMechanism=PLAIN&loadBalanced=true'
|
|
289
|
+
|
|
290
|
+
def connect_kai(self) -> 'pymongo.MongoClient':
|
|
291
|
+
"""Connect to the Kai (MongoDB) server."""
|
|
292
|
+
if not self.kai_enabled:
|
|
293
|
+
raise RuntimeError('kai is not enabled')
|
|
294
|
+
if not has_pymongo:
|
|
295
|
+
raise RuntimeError('pymongo is not installed')
|
|
296
|
+
return pymongo.MongoClient(self.kai_url)
|
|
297
|
+
|
|
298
|
+
@property
|
|
299
|
+
def studio_url(self) -> str:
|
|
300
|
+
"""URL for the SingleStoreDB Studio."""
|
|
301
|
+
return f'http://localhost:{self.studio_port}'
|
|
302
|
+
|
|
303
|
+
def open_studio(self) -> None:
|
|
304
|
+
"""Open the SingleStoreDB Studio in a web browser."""
|
|
305
|
+
import webbrowser
|
|
306
|
+
if platform.platform().lower().startswith('macos'):
|
|
307
|
+
chrome_path = r'open -a /Applications/Google\ Chrome.app %s'
|
|
308
|
+
webbrowser.get(chrome_path).open(self.studio_url, new=2)
|
|
309
|
+
else:
|
|
310
|
+
webbrowser.open(self.studio_url, new=2)
|
|
311
|
+
|
|
312
|
+
def open_shell(self) -> None:
|
|
313
|
+
"""Open a shell in the SingleStoreDB server."""
|
|
314
|
+
if platform.platform().lower().startswith('macos'):
|
|
315
|
+
subprocess.call([
|
|
316
|
+
'osascript', '-e',
|
|
317
|
+
'tell app "Terminal" to do script '
|
|
318
|
+
f'"docker exec -it {self.container.id} singlestore-auth"',
|
|
319
|
+
])
|
|
320
|
+
elif platform.platform().lower().startswith('linux'):
|
|
321
|
+
subprocess.call([
|
|
322
|
+
'gnome-terminal', '--',
|
|
323
|
+
'docker', 'exec', '-it', self.container.id, 'singlestore-auth',
|
|
324
|
+
])
|
|
325
|
+
elif platform.platform().lower().startswith('windows'):
|
|
326
|
+
subprocess.call([
|
|
327
|
+
'start', 'cmd', '/k'
|
|
328
|
+
'docker', 'exec', '-it', self.container.id, 'singlestore-auth',
|
|
329
|
+
])
|
|
330
|
+
else:
|
|
331
|
+
raise RuntimeError('unsupported platform')
|
|
332
|
+
|
|
333
|
+
def open_mongosh(self) -> None:
|
|
334
|
+
"""Open a mongosh in the SingleStoreDB server."""
|
|
335
|
+
if not self.kai_enabled:
|
|
336
|
+
raise RuntimeError('kai interface is not enabled')
|
|
337
|
+
if platform.platform().lower().startswith('macos'):
|
|
338
|
+
subprocess.call([
|
|
339
|
+
'osascript', '-e',
|
|
340
|
+
'tell app "Terminal" to do script '
|
|
341
|
+
f'"docker exec -it {self.container.id} mongosh-auth"',
|
|
342
|
+
])
|
|
343
|
+
elif platform.platform().lower().startswith('linux'):
|
|
344
|
+
subprocess.call([
|
|
345
|
+
'gnome-terminal', '--',
|
|
346
|
+
'docker', 'exec', '-it', self.container.id, 'mongosh-auth',
|
|
347
|
+
])
|
|
348
|
+
elif platform.platform().lower().startswith('windows'):
|
|
349
|
+
subprocess.call([
|
|
350
|
+
'start', 'cmd', '/k'
|
|
351
|
+
'docker', 'exec', '-it', self.container.id, 'mongosh-auth',
|
|
352
|
+
])
|
|
353
|
+
else:
|
|
354
|
+
raise RuntimeError('unsupported platform')
|
|
355
|
+
|
|
356
|
+
def __enter__(self) -> SingleStoreDB:
|
|
357
|
+
return self
|
|
358
|
+
|
|
359
|
+
def __exit__(
|
|
360
|
+
self,
|
|
361
|
+
exc_type: Optional[Type[BaseException]],
|
|
362
|
+
exc_val: Optional[BaseException],
|
|
363
|
+
exc_tb: Optional[TracebackType],
|
|
364
|
+
) -> Optional[bool]:
|
|
365
|
+
self.stop()
|
|
366
|
+
return None
|
|
367
|
+
|
|
368
|
+
def stop(self, *args: Any) -> None:
|
|
369
|
+
"""Stop the SingleStoreDB server."""
|
|
370
|
+
if self.container is not None:
|
|
371
|
+
self._restore_server_urls()
|
|
372
|
+
try:
|
|
373
|
+
self.container.stop()
|
|
374
|
+
finally:
|
|
375
|
+
self.container = None
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def start(
|
|
379
|
+
name: Optional[str] = None,
|
|
380
|
+
password: Optional[str] = None,
|
|
381
|
+
license: Optional[str] = None,
|
|
382
|
+
enable_kai: bool = False,
|
|
383
|
+
server_port: Optional[int] = None,
|
|
384
|
+
studio_port: Optional[int] = None,
|
|
385
|
+
data_api_port: Optional[int] = None,
|
|
386
|
+
kai_port: Optional[int] = None,
|
|
387
|
+
hostname: Optional[str] = None,
|
|
388
|
+
data_dir: Optional[str] = None,
|
|
389
|
+
logs_dir: Optional[str] = None,
|
|
390
|
+
server_dir: Optional[str] = None,
|
|
391
|
+
global_vars: Optional[Dict[str, Any]] = None,
|
|
392
|
+
init_sql: Optional[str] = None,
|
|
393
|
+
image: str = DEFAULT_IMAGE,
|
|
394
|
+
database: Optional[str] = None,
|
|
395
|
+
) -> SingleStoreDB:
|
|
396
|
+
"""
|
|
397
|
+
Manager for SingleStoreDB server running in Docker.
|
|
398
|
+
|
|
399
|
+
Parameters
|
|
400
|
+
-----------
|
|
401
|
+
name : str, optional
|
|
402
|
+
Name of the container.
|
|
403
|
+
password : str, optional
|
|
404
|
+
Password for the SingleStoreDB server.
|
|
405
|
+
license : str, optional
|
|
406
|
+
License key for SingleStoreDB.
|
|
407
|
+
enable_kai : bool, optional
|
|
408
|
+
Enable Kai (MongoDB) server.
|
|
409
|
+
server_port : int, optional
|
|
410
|
+
Port for the SingleStoreDB server.
|
|
411
|
+
studio_port : int, optional
|
|
412
|
+
Port for the SingleStoreDB Studio.
|
|
413
|
+
data_api_port : int, optional
|
|
414
|
+
Port for the SingleStoreDB Data API.
|
|
415
|
+
kai_port : int, optional
|
|
416
|
+
Port for the Kai server.
|
|
417
|
+
hostname : str, optional
|
|
418
|
+
Hostname for the container.
|
|
419
|
+
data_dir : str, optional
|
|
420
|
+
Path to the data directory.
|
|
421
|
+
logs_dir : str, optional
|
|
422
|
+
Path to the logs directory.
|
|
423
|
+
server_dir : str, optional
|
|
424
|
+
Path to the server directory.
|
|
425
|
+
global_vars : dict, optional
|
|
426
|
+
Global variables to set in the SingleStoreDB server.
|
|
427
|
+
init_sql : str, optional
|
|
428
|
+
Path to an SQL file to run on startup.
|
|
429
|
+
image : str, optional
|
|
430
|
+
Docker image to use.
|
|
431
|
+
database : str, optional
|
|
432
|
+
Default database to connect to.
|
|
433
|
+
|
|
434
|
+
"""
|
|
435
|
+
return SingleStoreDB(
|
|
436
|
+
name=name,
|
|
437
|
+
password=password,
|
|
438
|
+
license=license,
|
|
439
|
+
enable_kai=enable_kai,
|
|
440
|
+
server_port=server_port,
|
|
441
|
+
studio_port=studio_port,
|
|
442
|
+
data_api_port=data_api_port,
|
|
443
|
+
kai_port=kai_port,
|
|
444
|
+
hostname=hostname,
|
|
445
|
+
data_dir=data_dir,
|
|
446
|
+
logs_dir=logs_dir,
|
|
447
|
+
server_dir=server_dir,
|
|
448
|
+
global_vars=global_vars,
|
|
449
|
+
init_sql=init_sql,
|
|
450
|
+
image=image,
|
|
451
|
+
database=database,
|
|
452
|
+
)
|