singlestoredb 1.7.2__cp38-abi3-win_amd64.whl → 1.9.0__cp38-abi3-win_amd64.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 singlestoredb might be problematic. Click here for more details.
- _singlestoredb_accel.pyd +0 -0
- singlestoredb/__init__.py +2 -2
- singlestoredb/config.py +6 -0
- singlestoredb/connection.py +11 -0
- singlestoredb/fusion/handler.py +71 -18
- singlestoredb/fusion/handlers/export.py +237 -0
- singlestoredb/fusion/handlers/files.py +690 -0
- singlestoredb/fusion/handlers/job.py +4 -20
- singlestoredb/fusion/handlers/stage.py +103 -91
- singlestoredb/fusion/handlers/utils.py +148 -0
- singlestoredb/management/__init__.py +1 -0
- singlestoredb/management/export.py +146 -0
- singlestoredb/management/files.py +1038 -0
- singlestoredb/management/workspace.py +162 -349
- singlestoredb/mysql/connection.py +9 -1
- singlestoredb/py.typed +0 -0
- singlestoredb/tests/test.ipynb +18 -0
- singlestoredb/tests/test2.ipynb +18 -0
- singlestoredb/tests/test_fusion.py +0 -4
- singlestoredb/tests/test_management.py +273 -1
- {singlestoredb-1.7.2.dist-info → singlestoredb-1.9.0.dist-info}/METADATA +1 -1
- {singlestoredb-1.7.2.dist-info → singlestoredb-1.9.0.dist-info}/RECORD +28 -19
- {singlestoredb-1.7.2.dist-info → singlestoredb-1.9.0.dist-info}/top_level.txt +1 -0
- sqlx/__init__.py +4 -0
- sqlx/magic.py +113 -0
- {singlestoredb-1.7.2.dist-info → singlestoredb-1.9.0.dist-info}/LICENSE +0 -0
- {singlestoredb-1.7.2.dist-info → singlestoredb-1.9.0.dist-info}/WHEEL +0 -0
- {singlestoredb-1.7.2.dist-info → singlestoredb-1.9.0.dist-info}/entry_points.txt +0 -0
|
@@ -4,9 +4,16 @@ import os
|
|
|
4
4
|
from typing import Any
|
|
5
5
|
from typing import Dict
|
|
6
6
|
from typing import Optional
|
|
7
|
+
from typing import Union
|
|
7
8
|
|
|
8
9
|
from ...exceptions import ManagementError
|
|
9
10
|
from ...management import manage_workspaces
|
|
11
|
+
from ...management.files import FilesManager
|
|
12
|
+
from ...management.files import FileSpace
|
|
13
|
+
from ...management.files import manage_files
|
|
14
|
+
from ...management.files import PERSONAL_SPACE
|
|
15
|
+
from ...management.files import SHARED_SPACE
|
|
16
|
+
from ...management.workspace import StarterWorkspace
|
|
10
17
|
from ...management.workspace import Workspace
|
|
11
18
|
from ...management.workspace import WorkspaceGroup
|
|
12
19
|
from ...management.workspace import WorkspaceManager
|
|
@@ -17,6 +24,11 @@ def get_workspace_manager() -> WorkspaceManager:
|
|
|
17
24
|
return manage_workspaces()
|
|
18
25
|
|
|
19
26
|
|
|
27
|
+
def get_files_manager() -> FilesManager:
|
|
28
|
+
"""Return a new files manager."""
|
|
29
|
+
return manage_files()
|
|
30
|
+
|
|
31
|
+
|
|
20
32
|
def dt_isoformat(dt: Optional[datetime.datetime]) -> Optional[str]:
|
|
21
33
|
"""Convert datetime to string."""
|
|
22
34
|
if dt is None:
|
|
@@ -160,3 +172,139 @@ def get_workspace(params: Dict[str, Any]) -> Workspace:
|
|
|
160
172
|
raise ValueError('clusters and shared workspaces are not currently supported')
|
|
161
173
|
|
|
162
174
|
raise KeyError('no workspace was specified')
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def get_deployment(
|
|
178
|
+
params: Dict[str, Any],
|
|
179
|
+
) -> Union[WorkspaceGroup, StarterWorkspace]:
|
|
180
|
+
"""
|
|
181
|
+
Find a starter workspace matching deployment_id or deployment_name.
|
|
182
|
+
|
|
183
|
+
This function will get a starter workspace or ID from the
|
|
184
|
+
following parameters:
|
|
185
|
+
|
|
186
|
+
* params['deployment_name']
|
|
187
|
+
* params['deployment_id']
|
|
188
|
+
* params['group']['deployment_name']
|
|
189
|
+
* params['group']['deployment_id']
|
|
190
|
+
* params['in_deployment']['deployment_name']
|
|
191
|
+
* params['in_deployment']['deployment_id']
|
|
192
|
+
|
|
193
|
+
Or, from the SINGLESTOREDB_WORKSPACE_GROUP
|
|
194
|
+
or SINGLESTOREDB_CLUSTER environment variables.
|
|
195
|
+
|
|
196
|
+
"""
|
|
197
|
+
manager = get_workspace_manager()
|
|
198
|
+
|
|
199
|
+
deployment_name = params.get('deployment_name') or \
|
|
200
|
+
(params.get('in_deployment') or {}).get('deployment_name') or \
|
|
201
|
+
(params.get('group') or {}).get('deployment_name')
|
|
202
|
+
if deployment_name:
|
|
203
|
+
workspace_groups = [
|
|
204
|
+
x for x in manager.workspace_groups
|
|
205
|
+
if x.name == deployment_name
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
starter_workspaces = []
|
|
209
|
+
if not workspace_groups:
|
|
210
|
+
filtered_starter_workspaces = [
|
|
211
|
+
x for x in manager.starter_workspaces
|
|
212
|
+
if x.name == deployment_name
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
if not filtered_starter_workspaces:
|
|
216
|
+
raise KeyError(
|
|
217
|
+
f'no deployment found with name: {deployment_name}',
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
starter_workspaces = filtered_starter_workspaces
|
|
221
|
+
|
|
222
|
+
if len(workspace_groups) > 1:
|
|
223
|
+
ids = ', '.join(x.id for x in workspace_groups)
|
|
224
|
+
raise ValueError(
|
|
225
|
+
f'more than one workspace group with given name was found: {ids}',
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
if len(starter_workspaces) > 1:
|
|
229
|
+
ids = ', '.join(x.id for x in starter_workspaces)
|
|
230
|
+
raise ValueError(
|
|
231
|
+
f'more than one starter workspace with given name was found: {ids}',
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
if workspace_groups:
|
|
235
|
+
return workspace_groups[0]
|
|
236
|
+
else:
|
|
237
|
+
return starter_workspaces[0]
|
|
238
|
+
|
|
239
|
+
deployment_id = params.get('deployment_id') or \
|
|
240
|
+
(params.get('in_deployment') or {}).get('deployment_id') or \
|
|
241
|
+
(params.get('group') or {}).get('deployment_id')
|
|
242
|
+
if deployment_id:
|
|
243
|
+
try:
|
|
244
|
+
return manager.get_workspace_group(deployment_id)
|
|
245
|
+
except ManagementError as exc:
|
|
246
|
+
if exc.errno == 404:
|
|
247
|
+
try:
|
|
248
|
+
return manager.get_starter_workspace(deployment_id)
|
|
249
|
+
except ManagementError as exc:
|
|
250
|
+
if exc.errno == 404:
|
|
251
|
+
raise KeyError(f'no deployment found with ID: {deployment_id}')
|
|
252
|
+
raise
|
|
253
|
+
else:
|
|
254
|
+
raise
|
|
255
|
+
|
|
256
|
+
if os.environ.get('SINGLESTOREDB_WORKSPACE_GROUP'):
|
|
257
|
+
try:
|
|
258
|
+
return manager.get_workspace_group(
|
|
259
|
+
os.environ['SINGLESTOREDB_WORKSPACE_GROUP'],
|
|
260
|
+
)
|
|
261
|
+
except ManagementError as exc:
|
|
262
|
+
if exc.errno == 404:
|
|
263
|
+
raise KeyError(
|
|
264
|
+
'no workspace found with ID: '
|
|
265
|
+
f'{os.environ["SINGLESTOREDB_WORKSPACE_GROUP"]}',
|
|
266
|
+
)
|
|
267
|
+
raise
|
|
268
|
+
|
|
269
|
+
if os.environ.get('SINGLESTOREDB_CLUSTER'):
|
|
270
|
+
try:
|
|
271
|
+
return manager.get_starter_workspace(
|
|
272
|
+
os.environ['SINGLESTOREDB_CLUSTER'],
|
|
273
|
+
)
|
|
274
|
+
except ManagementError as exc:
|
|
275
|
+
if exc.errno == 404:
|
|
276
|
+
raise KeyError(
|
|
277
|
+
'no starter workspace found with ID: '
|
|
278
|
+
f'{os.environ["SINGLESTOREDB_CLUSTER"]}',
|
|
279
|
+
)
|
|
280
|
+
raise
|
|
281
|
+
|
|
282
|
+
raise KeyError('no deployment was specified')
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def get_file_space(params: Dict[str, Any]) -> FileSpace:
|
|
286
|
+
"""
|
|
287
|
+
Retrieve the specified file space.
|
|
288
|
+
|
|
289
|
+
This function will get a file space from the
|
|
290
|
+
following parameters:
|
|
291
|
+
|
|
292
|
+
* params['file_location']
|
|
293
|
+
"""
|
|
294
|
+
manager = get_files_manager()
|
|
295
|
+
|
|
296
|
+
file_location = params.get('file_location')
|
|
297
|
+
if file_location:
|
|
298
|
+
file_location_lower_case = file_location.lower()
|
|
299
|
+
if (
|
|
300
|
+
file_location_lower_case != PERSONAL_SPACE and
|
|
301
|
+
file_location_lower_case != SHARED_SPACE
|
|
302
|
+
):
|
|
303
|
+
raise ValueError(f'invalid file location: {file_location}')
|
|
304
|
+
|
|
305
|
+
if file_location_lower_case == PERSONAL_SPACE:
|
|
306
|
+
return manager.personal_space
|
|
307
|
+
elif file_location_lower_case == SHARED_SPACE:
|
|
308
|
+
return manager.shared_space
|
|
309
|
+
|
|
310
|
+
raise KeyError('no file space was specified')
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""SingleStoreDB export service."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import copy
|
|
6
|
+
import json
|
|
7
|
+
from typing import Any
|
|
8
|
+
from typing import Dict
|
|
9
|
+
from typing import List
|
|
10
|
+
from typing import Optional
|
|
11
|
+
from typing import Union
|
|
12
|
+
|
|
13
|
+
from .. import ManagementError
|
|
14
|
+
from .utils import vars_to_str
|
|
15
|
+
from .workspace import WorkspaceGroup
|
|
16
|
+
from .workspace import WorkspaceManager
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ExportService(object):
|
|
20
|
+
"""Export service."""
|
|
21
|
+
|
|
22
|
+
database: str
|
|
23
|
+
table: str
|
|
24
|
+
catalog_info: Dict[str, Any]
|
|
25
|
+
storage_info: Dict[str, Any]
|
|
26
|
+
columns: Optional[List[str]]
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
workspace_group: WorkspaceGroup,
|
|
31
|
+
database: str,
|
|
32
|
+
table: str,
|
|
33
|
+
catalog_info: Union[str, Dict[str, Any]],
|
|
34
|
+
storage_info: Union[str, Dict[str, Any]],
|
|
35
|
+
columns: Optional[List[str]],
|
|
36
|
+
):
|
|
37
|
+
#: Workspace group
|
|
38
|
+
self.workspace_group = workspace_group
|
|
39
|
+
|
|
40
|
+
#: Name of SingleStoreDB database
|
|
41
|
+
self.database = database
|
|
42
|
+
|
|
43
|
+
#: Name of SingleStoreDB table
|
|
44
|
+
self.table = table
|
|
45
|
+
|
|
46
|
+
#: List of columns to export
|
|
47
|
+
self.columns = columns
|
|
48
|
+
|
|
49
|
+
#: Catalog
|
|
50
|
+
if isinstance(catalog_info, str):
|
|
51
|
+
self.catalog_info = json.loads(catalog_info)
|
|
52
|
+
else:
|
|
53
|
+
self.catalog_info = copy.copy(catalog_info)
|
|
54
|
+
|
|
55
|
+
#: Storage
|
|
56
|
+
if isinstance(storage_info, str):
|
|
57
|
+
self.storage_info = json.loads(storage_info)
|
|
58
|
+
else:
|
|
59
|
+
self.storage_info = copy.copy(storage_info)
|
|
60
|
+
|
|
61
|
+
self._manager: Optional[WorkspaceManager] = workspace_group._manager
|
|
62
|
+
|
|
63
|
+
def __str__(self) -> str:
|
|
64
|
+
"""Return string representation."""
|
|
65
|
+
return vars_to_str(self)
|
|
66
|
+
|
|
67
|
+
def __repr__(self) -> str:
|
|
68
|
+
"""Return string representation."""
|
|
69
|
+
return str(self)
|
|
70
|
+
|
|
71
|
+
def create_cluster_identity(self) -> Dict[str, Any]:
|
|
72
|
+
"""Create a cluster identity."""
|
|
73
|
+
if self._manager is None:
|
|
74
|
+
raise ManagementError(
|
|
75
|
+
msg='No workspace manager is associated with this object.',
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
out = self._manager._post(
|
|
79
|
+
f'workspaceGroups/{self.workspace_group.id}/'
|
|
80
|
+
'egress/createEgressClusterIdentity',
|
|
81
|
+
json=dict(
|
|
82
|
+
catalogInfo=self.catalog_info,
|
|
83
|
+
storageInfo=self.storage_info,
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return out.json()
|
|
88
|
+
|
|
89
|
+
def start(self, tags: Optional[List[str]] = None) -> 'ExportStatus':
|
|
90
|
+
"""Start the export process."""
|
|
91
|
+
if self._manager is None:
|
|
92
|
+
raise ManagementError(
|
|
93
|
+
msg='No workspace manager is associated with this object.',
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
out = self._manager._post(
|
|
97
|
+
f'workspaceGroups/{self.workspace_group.id}/egress/startTableEgress',
|
|
98
|
+
json=dict(
|
|
99
|
+
databaseName=self.database,
|
|
100
|
+
tableName=self.table,
|
|
101
|
+
storageInfo=self.storage_info,
|
|
102
|
+
catalogInfo=self.catalog_info,
|
|
103
|
+
),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
return ExportStatus(out.json()['egressID'], self.workspace_group)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class ExportStatus(object):
|
|
110
|
+
|
|
111
|
+
export_id: str
|
|
112
|
+
|
|
113
|
+
def __init__(self, export_id: str, workspace_group: WorkspaceGroup):
|
|
114
|
+
self.export_id = export_id
|
|
115
|
+
self.workspace_group = workspace_group
|
|
116
|
+
self._manager: Optional[WorkspaceManager] = workspace_group._manager
|
|
117
|
+
|
|
118
|
+
def _info(self) -> Dict[str, Any]:
|
|
119
|
+
"""Return export status."""
|
|
120
|
+
if self._manager is None:
|
|
121
|
+
raise ManagementError(
|
|
122
|
+
msg='No workspace manager is associated with this object.',
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
out = self._manager._get(
|
|
126
|
+
f'workspaceGroups/{self.workspace_group.id}/egress/tableEgressStatus',
|
|
127
|
+
json=dict(egressID=self.export_id),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
return out.json()
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def status(self) -> str:
|
|
134
|
+
"""Return export status."""
|
|
135
|
+
return self._info().get('status', 'Unknown')
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def message(self) -> str:
|
|
139
|
+
"""Return export status message."""
|
|
140
|
+
return self._info().get('statusMsg', '')
|
|
141
|
+
|
|
142
|
+
def __str__(self) -> str:
|
|
143
|
+
return self.status
|
|
144
|
+
|
|
145
|
+
def __repr__(self) -> str:
|
|
146
|
+
return self.status
|