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.
Files changed (183) hide show
  1. singlestoredb/__init__.py +75 -0
  2. singlestoredb/ai/__init__.py +2 -0
  3. singlestoredb/ai/chat.py +139 -0
  4. singlestoredb/ai/embeddings.py +128 -0
  5. singlestoredb/alchemy/__init__.py +90 -0
  6. singlestoredb/apps/__init__.py +3 -0
  7. singlestoredb/apps/_cloud_functions.py +90 -0
  8. singlestoredb/apps/_config.py +72 -0
  9. singlestoredb/apps/_connection_info.py +18 -0
  10. singlestoredb/apps/_dashboards.py +47 -0
  11. singlestoredb/apps/_process.py +32 -0
  12. singlestoredb/apps/_python_udfs.py +100 -0
  13. singlestoredb/apps/_stdout_supress.py +30 -0
  14. singlestoredb/apps/_uvicorn_util.py +36 -0
  15. singlestoredb/auth.py +245 -0
  16. singlestoredb/config.py +484 -0
  17. singlestoredb/connection.py +1487 -0
  18. singlestoredb/converters.py +950 -0
  19. singlestoredb/docstring/__init__.py +33 -0
  20. singlestoredb/docstring/attrdoc.py +126 -0
  21. singlestoredb/docstring/common.py +230 -0
  22. singlestoredb/docstring/epydoc.py +267 -0
  23. singlestoredb/docstring/google.py +412 -0
  24. singlestoredb/docstring/numpydoc.py +562 -0
  25. singlestoredb/docstring/parser.py +100 -0
  26. singlestoredb/docstring/py.typed +1 -0
  27. singlestoredb/docstring/rest.py +256 -0
  28. singlestoredb/docstring/tests/__init__.py +1 -0
  29. singlestoredb/docstring/tests/_pydoctor.py +21 -0
  30. singlestoredb/docstring/tests/test_epydoc.py +729 -0
  31. singlestoredb/docstring/tests/test_google.py +1007 -0
  32. singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
  33. singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
  34. singlestoredb/docstring/tests/test_parser.py +248 -0
  35. singlestoredb/docstring/tests/test_rest.py +547 -0
  36. singlestoredb/docstring/tests/test_util.py +70 -0
  37. singlestoredb/docstring/util.py +141 -0
  38. singlestoredb/exceptions.py +120 -0
  39. singlestoredb/functions/__init__.py +16 -0
  40. singlestoredb/functions/decorator.py +201 -0
  41. singlestoredb/functions/dtypes.py +1793 -0
  42. singlestoredb/functions/ext/__init__.py +1 -0
  43. singlestoredb/functions/ext/arrow.py +375 -0
  44. singlestoredb/functions/ext/asgi.py +2133 -0
  45. singlestoredb/functions/ext/json.py +420 -0
  46. singlestoredb/functions/ext/mmap.py +413 -0
  47. singlestoredb/functions/ext/rowdat_1.py +724 -0
  48. singlestoredb/functions/ext/timer.py +89 -0
  49. singlestoredb/functions/ext/utils.py +218 -0
  50. singlestoredb/functions/signature.py +1578 -0
  51. singlestoredb/functions/typing/__init__.py +41 -0
  52. singlestoredb/functions/typing/numpy.py +20 -0
  53. singlestoredb/functions/typing/pandas.py +2 -0
  54. singlestoredb/functions/typing/polars.py +2 -0
  55. singlestoredb/functions/typing/pyarrow.py +2 -0
  56. singlestoredb/functions/utils.py +421 -0
  57. singlestoredb/fusion/__init__.py +11 -0
  58. singlestoredb/fusion/graphql.py +213 -0
  59. singlestoredb/fusion/handler.py +916 -0
  60. singlestoredb/fusion/handlers/__init__.py +0 -0
  61. singlestoredb/fusion/handlers/export.py +525 -0
  62. singlestoredb/fusion/handlers/files.py +690 -0
  63. singlestoredb/fusion/handlers/job.py +660 -0
  64. singlestoredb/fusion/handlers/models.py +250 -0
  65. singlestoredb/fusion/handlers/stage.py +502 -0
  66. singlestoredb/fusion/handlers/utils.py +324 -0
  67. singlestoredb/fusion/handlers/workspace.py +956 -0
  68. singlestoredb/fusion/registry.py +249 -0
  69. singlestoredb/fusion/result.py +399 -0
  70. singlestoredb/http/__init__.py +27 -0
  71. singlestoredb/http/connection.py +1267 -0
  72. singlestoredb/magics/__init__.py +34 -0
  73. singlestoredb/magics/run_personal.py +137 -0
  74. singlestoredb/magics/run_shared.py +134 -0
  75. singlestoredb/management/__init__.py +9 -0
  76. singlestoredb/management/billing_usage.py +148 -0
  77. singlestoredb/management/cluster.py +462 -0
  78. singlestoredb/management/export.py +295 -0
  79. singlestoredb/management/files.py +1102 -0
  80. singlestoredb/management/inference_api.py +105 -0
  81. singlestoredb/management/job.py +887 -0
  82. singlestoredb/management/manager.py +373 -0
  83. singlestoredb/management/organization.py +226 -0
  84. singlestoredb/management/region.py +169 -0
  85. singlestoredb/management/utils.py +423 -0
  86. singlestoredb/management/workspace.py +1927 -0
  87. singlestoredb/mysql/__init__.py +177 -0
  88. singlestoredb/mysql/_auth.py +298 -0
  89. singlestoredb/mysql/charset.py +214 -0
  90. singlestoredb/mysql/connection.py +2032 -0
  91. singlestoredb/mysql/constants/CLIENT.py +38 -0
  92. singlestoredb/mysql/constants/COMMAND.py +32 -0
  93. singlestoredb/mysql/constants/CR.py +78 -0
  94. singlestoredb/mysql/constants/ER.py +474 -0
  95. singlestoredb/mysql/constants/EXTENDED_TYPE.py +3 -0
  96. singlestoredb/mysql/constants/FIELD_TYPE.py +48 -0
  97. singlestoredb/mysql/constants/FLAG.py +15 -0
  98. singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
  99. singlestoredb/mysql/constants/VECTOR_TYPE.py +6 -0
  100. singlestoredb/mysql/constants/__init__.py +0 -0
  101. singlestoredb/mysql/converters.py +271 -0
  102. singlestoredb/mysql/cursors.py +896 -0
  103. singlestoredb/mysql/err.py +92 -0
  104. singlestoredb/mysql/optionfile.py +20 -0
  105. singlestoredb/mysql/protocol.py +450 -0
  106. singlestoredb/mysql/tests/__init__.py +19 -0
  107. singlestoredb/mysql/tests/base.py +126 -0
  108. singlestoredb/mysql/tests/conftest.py +37 -0
  109. singlestoredb/mysql/tests/test_DictCursor.py +132 -0
  110. singlestoredb/mysql/tests/test_SSCursor.py +141 -0
  111. singlestoredb/mysql/tests/test_basic.py +452 -0
  112. singlestoredb/mysql/tests/test_connection.py +851 -0
  113. singlestoredb/mysql/tests/test_converters.py +58 -0
  114. singlestoredb/mysql/tests/test_cursor.py +141 -0
  115. singlestoredb/mysql/tests/test_err.py +16 -0
  116. singlestoredb/mysql/tests/test_issues.py +514 -0
  117. singlestoredb/mysql/tests/test_load_local.py +75 -0
  118. singlestoredb/mysql/tests/test_nextset.py +88 -0
  119. singlestoredb/mysql/tests/test_optionfile.py +27 -0
  120. singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
  121. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
  122. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
  123. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
  124. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
  125. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
  126. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
  127. singlestoredb/mysql/times.py +23 -0
  128. singlestoredb/notebook/__init__.py +16 -0
  129. singlestoredb/notebook/_objects.py +213 -0
  130. singlestoredb/notebook/_portal.py +352 -0
  131. singlestoredb/py.typed +0 -0
  132. singlestoredb/pytest.py +352 -0
  133. singlestoredb/server/__init__.py +0 -0
  134. singlestoredb/server/docker.py +452 -0
  135. singlestoredb/server/free_tier.py +267 -0
  136. singlestoredb/tests/__init__.py +0 -0
  137. singlestoredb/tests/alltypes.sql +307 -0
  138. singlestoredb/tests/alltypes_no_nulls.sql +208 -0
  139. singlestoredb/tests/empty.sql +0 -0
  140. singlestoredb/tests/ext_funcs/__init__.py +702 -0
  141. singlestoredb/tests/local_infile.csv +3 -0
  142. singlestoredb/tests/test.ipynb +18 -0
  143. singlestoredb/tests/test.sql +680 -0
  144. singlestoredb/tests/test2.ipynb +18 -0
  145. singlestoredb/tests/test2.sql +1 -0
  146. singlestoredb/tests/test_basics.py +1332 -0
  147. singlestoredb/tests/test_config.py +318 -0
  148. singlestoredb/tests/test_connection.py +3103 -0
  149. singlestoredb/tests/test_dbapi.py +27 -0
  150. singlestoredb/tests/test_exceptions.py +45 -0
  151. singlestoredb/tests/test_ext_func.py +1472 -0
  152. singlestoredb/tests/test_ext_func_data.py +1101 -0
  153. singlestoredb/tests/test_fusion.py +1527 -0
  154. singlestoredb/tests/test_http.py +288 -0
  155. singlestoredb/tests/test_management.py +1599 -0
  156. singlestoredb/tests/test_plugin.py +33 -0
  157. singlestoredb/tests/test_results.py +171 -0
  158. singlestoredb/tests/test_types.py +132 -0
  159. singlestoredb/tests/test_udf.py +737 -0
  160. singlestoredb/tests/test_udf_returns.py +459 -0
  161. singlestoredb/tests/test_vectorstore.py +51 -0
  162. singlestoredb/tests/test_xdict.py +333 -0
  163. singlestoredb/tests/utils.py +141 -0
  164. singlestoredb/types.py +373 -0
  165. singlestoredb/utils/__init__.py +0 -0
  166. singlestoredb/utils/config.py +950 -0
  167. singlestoredb/utils/convert_rows.py +69 -0
  168. singlestoredb/utils/debug.py +13 -0
  169. singlestoredb/utils/dtypes.py +205 -0
  170. singlestoredb/utils/events.py +65 -0
  171. singlestoredb/utils/mogrify.py +151 -0
  172. singlestoredb/utils/results.py +585 -0
  173. singlestoredb/utils/xdict.py +425 -0
  174. singlestoredb/vectorstore.py +192 -0
  175. singlestoredb/warnings.py +5 -0
  176. singlestoredb-1.16.1.dist-info/METADATA +165 -0
  177. singlestoredb-1.16.1.dist-info/RECORD +183 -0
  178. singlestoredb-1.16.1.dist-info/WHEEL +5 -0
  179. singlestoredb-1.16.1.dist-info/entry_points.txt +2 -0
  180. singlestoredb-1.16.1.dist-info/licenses/LICENSE +201 -0
  181. singlestoredb-1.16.1.dist-info/top_level.txt +3 -0
  182. sqlx/__init__.py +4 -0
  183. sqlx/magic.py +113 -0
@@ -0,0 +1,462 @@
1
+ #!/usr/bin/env python
2
+ """SingleStoreDB Cluster Management."""
3
+ import datetime
4
+ import warnings
5
+ from typing import Any
6
+ from typing import Dict
7
+ from typing import List
8
+ from typing import Optional
9
+ from typing import Union
10
+
11
+ from .. import config
12
+ from .. import connection
13
+ from ..exceptions import ManagementError
14
+ from .manager import Manager
15
+ from .region import Region
16
+ from .utils import NamedList
17
+ from .utils import to_datetime
18
+ from .utils import vars_to_str
19
+
20
+
21
+ class Cluster(object):
22
+ """
23
+ SingleStoreDB cluster definition.
24
+
25
+ This object is not instantiated directly. It is used in the results
26
+ of API calls on the :class:`ClusterManager`. Clusters are created using
27
+ :meth:`ClusterManager.create_cluster`, or existing clusters are accessed by either
28
+ :attr:`ClusterManager.clusters` or by calling :meth:`ClusterManager.get_cluster`.
29
+
30
+ See Also
31
+ --------
32
+ :meth:`ClusterManager.create_cluster`
33
+ :meth:`ClusterManager.get_cluster`
34
+ :attr:`ClusterManager.clusters`
35
+
36
+ """
37
+
38
+ def __init__(
39
+ self, name: str, id: str, region: Region, size: str,
40
+ units: float, state: str, version: str,
41
+ created_at: Union[str, datetime.datetime],
42
+ expires_at: Optional[Union[str, datetime.datetime]] = None,
43
+ firewall_ranges: Optional[List[str]] = None,
44
+ terminated_at: Optional[Union[str, datetime.datetime]] = None,
45
+ endpoint: Optional[str] = None,
46
+ ):
47
+ """Use :attr:`ClusterManager.clusters` or :meth:`ClusterManager.get_cluster`."""
48
+ #: Name of the cluster
49
+ self.name = name.strip()
50
+
51
+ #: Unique ID of the cluster
52
+ self.id = id
53
+
54
+ #: Region of the cluster (see :class:`Region`)
55
+ self.region = region
56
+
57
+ #: Size of the cluster in cluster size notation (S-00, S-1, etc.)
58
+ self.size = size
59
+
60
+ #: Size of the cluster in units such as 0.25, 1.0, etc.
61
+ self.units = units
62
+
63
+ #: State of the cluster: PendingCreation, Transitioning, Active,
64
+ #: Terminated, Suspended, Resuming, Failed
65
+ self.state = state.strip()
66
+
67
+ #: Version of the SingleStoreDB server
68
+ self.version = version.strip()
69
+
70
+ #: Timestamp of when the cluster was created
71
+ self.created_at = to_datetime(created_at)
72
+
73
+ #: Timestamp of when the cluster expires
74
+ self.expires_at = to_datetime(expires_at)
75
+
76
+ #: List of allowed incoming IP addresses / ranges
77
+ self.firewall_ranges = firewall_ranges
78
+
79
+ #: Timestamp of when the cluster was terminated
80
+ self.terminated_at = to_datetime(terminated_at)
81
+
82
+ #: Hostname (or IP address) of the cluster database server
83
+ self.endpoint = endpoint
84
+
85
+ self._manager: Optional[ClusterManager] = None
86
+
87
+ def __str__(self) -> str:
88
+ """Return string representation."""
89
+ return vars_to_str(self)
90
+
91
+ def __repr__(self) -> str:
92
+ """Return string representation."""
93
+ return str(self)
94
+
95
+ @classmethod
96
+ def from_dict(cls, obj: Dict[str, Any], manager: 'ClusterManager') -> 'Cluster':
97
+ """
98
+ Construct a Cluster from a dictionary of values.
99
+
100
+ Parameters
101
+ ----------
102
+ obj : dict
103
+ Dictionary of values
104
+ manager : ClusterManager, optional
105
+ The ClusterManager the Cluster belongs to
106
+
107
+ Returns
108
+ -------
109
+ :class:`Cluster`
110
+
111
+ """
112
+ out = cls(
113
+ name=obj['name'], id=obj['clusterID'],
114
+ region=Region.from_dict(obj['region'], manager),
115
+ size=obj.get('size', 'Unknown'), units=obj.get('units', float('nan')),
116
+ state=obj['state'], version=obj['version'],
117
+ created_at=obj['createdAt'], expires_at=obj.get('expiresAt'),
118
+ firewall_ranges=obj.get('firewallRanges'),
119
+ terminated_at=obj.get('terminatedAt'),
120
+ endpoint=obj.get('endpoint'),
121
+ )
122
+ out._manager = manager
123
+ return out
124
+
125
+ def refresh(self) -> 'Cluster':
126
+ """Update the object to the current state."""
127
+ if self._manager is None:
128
+ raise ManagementError(
129
+ msg='No cluster manager is associated with this object.',
130
+ )
131
+ new_obj = self._manager.get_cluster(self.id)
132
+ for name, value in vars(new_obj).items():
133
+ setattr(self, name, value)
134
+ return self
135
+
136
+ def update(
137
+ self, name: Optional[str] = None,
138
+ admin_password: Optional[str] = None,
139
+ expires_at: Optional[str] = None,
140
+ size: Optional[str] = None, firewall_ranges: Optional[List[str]] = None,
141
+ ) -> None:
142
+ """
143
+ Update the cluster definition.
144
+
145
+ Parameters
146
+ ----------
147
+ name : str, optional
148
+ Cluster name
149
+ admim_password : str, optional
150
+ Admin password for the cluster
151
+ expires_at : str, optional
152
+ Timestamp when the cluster expires
153
+ size : str, optional
154
+ Cluster size in cluster size notation (S-00, S-1, etc.)
155
+ firewall_ranges : Sequence[str], optional
156
+ List of allowed incoming IP addresses
157
+
158
+ """
159
+ if self._manager is None:
160
+ raise ManagementError(
161
+ msg='No cluster manager is associated with this object.',
162
+ )
163
+ data = {
164
+ k: v for k, v in dict(
165
+ name=name, adminPassword=admin_password,
166
+ expiresAt=expires_at, size=size,
167
+ firewallRanges=firewall_ranges,
168
+ ).items() if v is not None
169
+ }
170
+ self._manager._patch(f'clusters/{self.id}', json=data)
171
+ self.refresh()
172
+
173
+ def suspend(
174
+ self,
175
+ wait_on_suspended: bool = False,
176
+ wait_interval: int = 20,
177
+ wait_timeout: int = 600,
178
+ ) -> None:
179
+ """
180
+ Suspend the cluster.
181
+
182
+ Parameters
183
+ ----------
184
+ wait_on_suspended : bool, optional
185
+ Wait for the cluster to go into 'Suspended' mode before returning
186
+ wait_interval : int, optional
187
+ Number of seconds between each server check
188
+ wait_timeout : int, optional
189
+ Total number of seconds to check server before giving up
190
+
191
+ Raises
192
+ ------
193
+ ManagementError
194
+ If timeout is reached
195
+
196
+ """
197
+ if self._manager is None:
198
+ raise ManagementError(
199
+ msg='No cluster manager is associated with this object.',
200
+ )
201
+ self._manager._post(
202
+ f'clusters/{self.id}/suspend',
203
+ headers={'Content-Type': 'application/x-www-form-urlencoded'},
204
+ )
205
+ if wait_on_suspended:
206
+ self._manager._wait_on_state(
207
+ self._manager.get_cluster(self.id),
208
+ 'Suspended', interval=wait_interval, timeout=wait_timeout,
209
+ )
210
+ self.refresh()
211
+
212
+ def resume(
213
+ self,
214
+ wait_on_resumed: bool = False,
215
+ wait_interval: int = 20,
216
+ wait_timeout: int = 600,
217
+ ) -> None:
218
+ """
219
+ Resume the cluster.
220
+
221
+ Parameters
222
+ ----------
223
+ wait_on_resumed : bool, optional
224
+ Wait for the cluster to go into 'Resumed' or 'Active' mode before returning
225
+ wait_interval : int, optional
226
+ Number of seconds between each server check
227
+ wait_timeout : int, optional
228
+ Total number of seconds to check server before giving up
229
+
230
+ Raises
231
+ ------
232
+ ManagementError
233
+ If timeout is reached
234
+
235
+ """
236
+ if self._manager is None:
237
+ raise ManagementError(
238
+ msg='No cluster manager is associated with this object.',
239
+ )
240
+ self._manager._post(
241
+ f'clusters/{self.id}/resume',
242
+ headers={'Content-Type': 'application/x-www-form-urlencoded'},
243
+ )
244
+ if wait_on_resumed:
245
+ self._manager._wait_on_state(
246
+ self._manager.get_cluster(self.id),
247
+ ['Resumed', 'Active'], interval=wait_interval, timeout=wait_timeout,
248
+ )
249
+ self.refresh()
250
+
251
+ def terminate(
252
+ self,
253
+ wait_on_terminated: bool = False,
254
+ wait_interval: int = 10,
255
+ wait_timeout: int = 600,
256
+ ) -> None:
257
+ """
258
+ Terminate the cluster.
259
+
260
+ Parameters
261
+ ----------
262
+ wait_on_terminated : bool, optional
263
+ Wait for the cluster to go into 'Terminated' mode before returning
264
+ wait_interval : int, optional
265
+ Number of seconds between each server check
266
+ wait_timeout : int, optional
267
+ Total number of seconds to check server before giving up
268
+
269
+ Raises
270
+ ------
271
+ ManagementError
272
+ If timeout is reached
273
+
274
+ """
275
+ if self._manager is None:
276
+ raise ManagementError(
277
+ msg='No cluster manager is associated with this object.',
278
+ )
279
+ self._manager._delete(f'clusters/{self.id}')
280
+ if wait_on_terminated:
281
+ self._manager._wait_on_state(
282
+ self._manager.get_cluster(self.id),
283
+ 'Terminated', interval=wait_interval, timeout=wait_timeout,
284
+ )
285
+ self.refresh()
286
+
287
+ def connect(self, **kwargs: Any) -> connection.Connection:
288
+ """
289
+ Create a connection to the database server for this cluster.
290
+
291
+ Parameters
292
+ ----------
293
+ **kwargs : keyword-arguments, optional
294
+ Parameters to the SingleStoreDB `connect` function except host
295
+ and port which are supplied by the cluster object
296
+
297
+ Returns
298
+ -------
299
+ :class:`Connection`
300
+
301
+ """
302
+ if not self.endpoint:
303
+ raise ManagementError(
304
+ msg='An endpoint has not been set in '
305
+ 'this cluster configuration',
306
+ )
307
+ kwargs['host'] = self.endpoint
308
+ return connection.connect(**kwargs)
309
+
310
+
311
+ class ClusterManager(Manager):
312
+ """
313
+ SingleStoreDB cluster manager.
314
+
315
+ This class should be instantiated using :func:`singlestoredb.manage_cluster`.
316
+
317
+ Parameters
318
+ ----------
319
+ access_token : str, optional
320
+ The API key or other access token for the cluster management API
321
+ version : str, optional
322
+ Version of the API to use
323
+ base_url : str, optional
324
+ Base URL of the cluster management API
325
+
326
+ See Also
327
+ --------
328
+ :func:`singlestoredb.manage_cluster`
329
+
330
+ """
331
+
332
+ #: Cluster management API version if none is specified.
333
+ default_version = 'v0beta'
334
+
335
+ #: Base URL if none is specified.
336
+ default_base_url = config.get_option('management.base_url') \
337
+ or 'https://api.singlestore.com'
338
+
339
+ #: Object type
340
+ obj_type = 'cluster'
341
+
342
+ @property
343
+ def clusters(self) -> NamedList[Cluster]:
344
+ """Return a list of available clusters."""
345
+ res = self._get('clusters')
346
+ return NamedList([Cluster.from_dict(item, self) for item in res.json()])
347
+
348
+ @property
349
+ def regions(self) -> NamedList[Region]:
350
+ """Return a list of available regions."""
351
+ res = self._get('regions')
352
+ return NamedList([Region.from_dict(item, self) for item in res.json()])
353
+
354
+ def create_cluster(
355
+ self, name: str, region: Union[str, Region], admin_password: str,
356
+ firewall_ranges: List[str], expires_at: Optional[str] = None,
357
+ size: Optional[str] = None, plan: Optional[str] = None,
358
+ wait_on_active: bool = False, wait_timeout: int = 600,
359
+ wait_interval: int = 20,
360
+ ) -> Cluster:
361
+ """
362
+ Create a new cluster.
363
+
364
+ Parameters
365
+ ----------
366
+ name : str
367
+ Name of the cluster
368
+ region : str or Region
369
+ The region ID of the cluster
370
+ admin_password : str
371
+ Admin password for the cluster
372
+ firewall_ranges : Sequence[str], optional
373
+ List of allowed incoming IP addresses
374
+ expires_at : str, optional
375
+ Timestamp of when the cluster expires
376
+ size : str, optional
377
+ Cluster size in cluster size notation (S-00, S-1, etc.)
378
+ plan : str, optional
379
+ Internal use only
380
+ wait_on_active : bool, optional
381
+ Wait for the cluster to be active before returning
382
+ wait_timeout : int, optional
383
+ Maximum number of seconds to wait before raising an exception
384
+ if wait=True
385
+ wait_interval : int, optional
386
+ Number of seconds between each polling interval
387
+
388
+ Returns
389
+ -------
390
+ :class:`Cluster`
391
+
392
+ """
393
+ if isinstance(region, Region) and region.id:
394
+ region = region.id
395
+ res = self._post(
396
+ 'clusters', json=dict(
397
+ name=name, regionID=region, adminPassword=admin_password,
398
+ expiresAt=expires_at, size=size, firewallRanges=firewall_ranges,
399
+ plan=plan,
400
+ ),
401
+ )
402
+ out = self.get_cluster(res.json()['clusterID'])
403
+ if wait_on_active:
404
+ out = self._wait_on_state(
405
+ out, 'Active', interval=wait_interval,
406
+ timeout=wait_timeout,
407
+ )
408
+ return out
409
+
410
+ def get_cluster(self, id: str) -> Cluster:
411
+ """
412
+ Retrieve a cluster definition.
413
+
414
+ Parameters
415
+ ----------
416
+ id : str
417
+ ID of the cluster
418
+
419
+ Returns
420
+ -------
421
+ :class:`Cluster`
422
+
423
+ """
424
+ res = self._get(f'clusters/{id}')
425
+ return Cluster.from_dict(res.json(), manager=self)
426
+
427
+
428
+ def manage_cluster(
429
+ access_token: Optional[str] = None,
430
+ version: Optional[str] = None,
431
+ base_url: Optional[str] = None,
432
+ *,
433
+ organization_id: Optional[str] = None,
434
+ ) -> ClusterManager:
435
+ """
436
+ Retrieve a SingleStoreDB cluster manager.
437
+
438
+ Parameters
439
+ ----------
440
+ access_token : str, optional
441
+ The API key or other access token for the cluster management API
442
+ version : str, optional
443
+ Version of the API to use
444
+ base_url : str, optional
445
+ Base URL of the cluster management API
446
+ organization_id: str, optional
447
+ ID of organization, if using a JWT for authentication
448
+
449
+ Returns
450
+ -------
451
+ :class:`ClusterManager`
452
+
453
+ """
454
+ warnings.warn(
455
+ 'The cluster management API is deprecated; '
456
+ 'use manage_workspaces instead.',
457
+ category=DeprecationWarning,
458
+ )
459
+ return ClusterManager(
460
+ access_token=access_token, base_url=base_url,
461
+ version=version, organization_id=organization_id,
462
+ )