singlestoredb 0.4.0__py3-none-any.whl → 1.0.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of singlestoredb might be problematic. Click here for more details.

Files changed (120) hide show
  1. singlestoredb/__init__.py +33 -1
  2. singlestoredb/alchemy/__init__.py +90 -0
  3. singlestoredb/auth.py +5 -1
  4. singlestoredb/config.py +116 -14
  5. singlestoredb/connection.py +483 -516
  6. singlestoredb/converters.py +238 -135
  7. singlestoredb/exceptions.py +30 -2
  8. singlestoredb/functions/__init__.py +1 -0
  9. singlestoredb/functions/decorator.py +142 -0
  10. singlestoredb/functions/dtypes.py +1639 -0
  11. singlestoredb/functions/ext/__init__.py +2 -0
  12. singlestoredb/functions/ext/arrow.py +375 -0
  13. singlestoredb/functions/ext/asgi.py +661 -0
  14. singlestoredb/functions/ext/json.py +427 -0
  15. singlestoredb/functions/ext/mmap.py +306 -0
  16. singlestoredb/functions/ext/rowdat_1.py +744 -0
  17. singlestoredb/functions/signature.py +673 -0
  18. singlestoredb/fusion/__init__.py +11 -0
  19. singlestoredb/fusion/graphql.py +213 -0
  20. singlestoredb/fusion/handler.py +621 -0
  21. singlestoredb/fusion/handlers/stage.py +257 -0
  22. singlestoredb/fusion/handlers/utils.py +162 -0
  23. singlestoredb/fusion/handlers/workspace.py +412 -0
  24. singlestoredb/fusion/registry.py +164 -0
  25. singlestoredb/fusion/result.py +399 -0
  26. singlestoredb/http/__init__.py +27 -0
  27. singlestoredb/{http.py → http/connection.py} +555 -154
  28. singlestoredb/management/__init__.py +3 -0
  29. singlestoredb/management/billing_usage.py +148 -0
  30. singlestoredb/management/cluster.py +14 -6
  31. singlestoredb/management/manager.py +100 -38
  32. singlestoredb/management/organization.py +188 -0
  33. singlestoredb/management/region.py +5 -5
  34. singlestoredb/management/utils.py +281 -2
  35. singlestoredb/management/workspace.py +1344 -49
  36. singlestoredb/{clients/pymysqlsv → mysql}/__init__.py +16 -21
  37. singlestoredb/{clients/pymysqlsv → mysql}/_auth.py +39 -8
  38. singlestoredb/{clients/pymysqlsv → mysql}/charset.py +26 -23
  39. singlestoredb/{clients/pymysqlsv/connections.py → mysql/connection.py} +532 -165
  40. singlestoredb/{clients/pymysqlsv → mysql}/constants/CLIENT.py +0 -1
  41. singlestoredb/{clients/pymysqlsv → mysql}/constants/COMMAND.py +0 -1
  42. singlestoredb/{clients/pymysqlsv → mysql}/constants/CR.py +0 -2
  43. singlestoredb/{clients/pymysqlsv → mysql}/constants/ER.py +0 -1
  44. singlestoredb/{clients/pymysqlsv → mysql}/constants/FIELD_TYPE.py +1 -1
  45. singlestoredb/{clients/pymysqlsv → mysql}/constants/FLAG.py +0 -1
  46. singlestoredb/{clients/pymysqlsv → mysql}/constants/SERVER_STATUS.py +0 -1
  47. singlestoredb/mysql/converters.py +271 -0
  48. singlestoredb/{clients/pymysqlsv → mysql}/cursors.py +228 -112
  49. singlestoredb/mysql/err.py +92 -0
  50. singlestoredb/{clients/pymysqlsv → mysql}/optionfile.py +5 -4
  51. singlestoredb/{clients/pymysqlsv → mysql}/protocol.py +49 -20
  52. singlestoredb/mysql/tests/__init__.py +19 -0
  53. singlestoredb/{clients/pymysqlsv → mysql}/tests/base.py +32 -12
  54. singlestoredb/mysql/tests/conftest.py +37 -0
  55. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_DictCursor.py +11 -7
  56. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_SSCursor.py +17 -12
  57. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_basic.py +32 -24
  58. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_connection.py +130 -119
  59. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_converters.py +9 -7
  60. singlestoredb/mysql/tests/test_cursor.py +141 -0
  61. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_err.py +3 -2
  62. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_issues.py +35 -27
  63. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_load_local.py +13 -11
  64. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_nextset.py +7 -3
  65. singlestoredb/{clients/pymysqlsv → mysql}/tests/test_optionfile.py +2 -1
  66. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/__init__.py +1 -1
  67. singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
  68. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/capabilities.py +19 -17
  69. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/dbapi20.py +31 -22
  70. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +3 -4
  71. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +24 -20
  72. singlestoredb/{clients/pymysqlsv → mysql}/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +4 -4
  73. singlestoredb/{clients/pymysqlsv → mysql}/times.py +3 -4
  74. singlestoredb/pytest.py +283 -0
  75. singlestoredb/tests/empty.sql +0 -0
  76. singlestoredb/tests/ext_funcs/__init__.py +385 -0
  77. singlestoredb/tests/test.sql +210 -0
  78. singlestoredb/tests/test2.sql +1 -0
  79. singlestoredb/tests/test_basics.py +482 -115
  80. singlestoredb/tests/test_config.py +13 -13
  81. singlestoredb/tests/test_connection.py +241 -305
  82. singlestoredb/tests/test_dbapi.py +27 -0
  83. singlestoredb/tests/test_ext_func.py +1193 -0
  84. singlestoredb/tests/test_ext_func_data.py +1101 -0
  85. singlestoredb/tests/test_fusion.py +465 -0
  86. singlestoredb/tests/test_http.py +32 -26
  87. singlestoredb/tests/test_management.py +588 -8
  88. singlestoredb/tests/test_plugin.py +33 -0
  89. singlestoredb/tests/test_results.py +11 -12
  90. singlestoredb/tests/test_udf.py +687 -0
  91. singlestoredb/tests/utils.py +3 -2
  92. singlestoredb/utils/config.py +58 -0
  93. singlestoredb/utils/debug.py +13 -0
  94. singlestoredb/utils/mogrify.py +151 -0
  95. singlestoredb/utils/results.py +4 -1
  96. singlestoredb-1.0.4.dist-info/METADATA +139 -0
  97. singlestoredb-1.0.4.dist-info/RECORD +112 -0
  98. {singlestoredb-0.4.0.dist-info → singlestoredb-1.0.4.dist-info}/WHEEL +1 -1
  99. singlestoredb-1.0.4.dist-info/entry_points.txt +2 -0
  100. singlestoredb/clients/pymysqlsv/converters.py +0 -365
  101. singlestoredb/clients/pymysqlsv/err.py +0 -144
  102. singlestoredb/clients/pymysqlsv/tests/__init__.py +0 -19
  103. singlestoredb/clients/pymysqlsv/tests/test_cursor.py +0 -133
  104. singlestoredb/clients/pymysqlsv/tests/thirdparty/test_MySQLdb/__init__.py +0 -9
  105. singlestoredb/drivers/__init__.py +0 -45
  106. singlestoredb/drivers/base.py +0 -198
  107. singlestoredb/drivers/cymysql.py +0 -38
  108. singlestoredb/drivers/http.py +0 -47
  109. singlestoredb/drivers/mariadb.py +0 -40
  110. singlestoredb/drivers/mysqlconnector.py +0 -49
  111. singlestoredb/drivers/mysqldb.py +0 -60
  112. singlestoredb/drivers/pymysql.py +0 -37
  113. singlestoredb/drivers/pymysqlsv.py +0 -35
  114. singlestoredb/drivers/pyodbc.py +0 -65
  115. singlestoredb-0.4.0.dist-info/METADATA +0 -111
  116. singlestoredb-0.4.0.dist-info/RECORD +0 -86
  117. /singlestoredb/{clients → fusion/handlers}/__init__.py +0 -0
  118. /singlestoredb/{clients/pymysqlsv → mysql}/constants/__init__.py +0 -0
  119. {singlestoredb-0.4.0.dist-info → singlestoredb-1.0.4.dist-info}/LICENSE +0 -0
  120. {singlestoredb-0.4.0.dist-info → singlestoredb-1.0.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,427 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ from typing import Any
4
+ from typing import List
5
+ from typing import Tuple
6
+
7
+ from ..dtypes import DEFAULT_VALUES
8
+ from ..dtypes import NUMPY_TYPE_MAP
9
+ from ..dtypes import PANDAS_TYPE_MAP
10
+ from ..dtypes import POLARS_TYPE_MAP
11
+ from ..dtypes import PYARROW_TYPE_MAP
12
+ from ..dtypes import PYTHON_CONVERTERS
13
+
14
+ try:
15
+ import numpy as np
16
+ has_numpy = True
17
+ except ImportError:
18
+ has_numpy = False
19
+
20
+ try:
21
+ import polars as pl
22
+ has_polars = True
23
+ except ImportError:
24
+ has_polars = False
25
+
26
+ try:
27
+ import pandas as pd
28
+ has_pandas = True
29
+ except ImportError:
30
+ has_pandas = False
31
+
32
+ try:
33
+ import pyarrow as pa
34
+ has_pyarrow = True
35
+ except ImportError:
36
+ has_pyarrow = False
37
+
38
+
39
+ class JSONEncoder(json.JSONEncoder):
40
+
41
+ def default(self, obj: Any) -> Any:
42
+ if isinstance(obj, bytes):
43
+ return obj.hex()
44
+ return json.JSONEncoder.default(self, obj)
45
+
46
+
47
+ def decode_row(coltypes: List[int], row: List[Any]) -> List[Any]:
48
+ out = []
49
+ for dtype, item in zip(coltypes, row):
50
+ out.append(PYTHON_CONVERTERS[dtype](item)) # type: ignore
51
+ return out
52
+
53
+
54
+ def decode_value(coltype: int, data: Any) -> Any:
55
+ return PYTHON_CONVERTERS[coltype](data) # type: ignore
56
+
57
+
58
+ def load(
59
+ colspec: List[Tuple[str, int]],
60
+ data: bytes,
61
+ ) -> Tuple[List[int], List[Any]]:
62
+ '''
63
+ Convert bytes in JSON format into rows of data.
64
+
65
+ Parameters
66
+ ----------
67
+ colspec : Iterable[Tuple[str, int]]
68
+ An Iterable of column data types
69
+ data : bytes
70
+ The data in JSON format
71
+
72
+ Returns
73
+ -------
74
+ Tuple[List[int], List[Any]]
75
+
76
+ '''
77
+ row_ids = []
78
+ rows = []
79
+ for row_id, *row in json.loads(data.decode('utf-8'))['data']:
80
+ row_ids.append(row_id)
81
+ rows.append(decode_row([x[1] for x in colspec], row))
82
+ return row_ids, rows
83
+
84
+
85
+ def _load_vectors(
86
+ colspec: List[Tuple[str, int]],
87
+ data: bytes,
88
+ ) -> Tuple[List[int], List[Any]]:
89
+ '''
90
+ Convert bytes in JSON format into rows of data.
91
+
92
+ Parameters
93
+ ----------
94
+ colspec : Iterable[Tuple[str, int]]
95
+ An Iterable of column data types
96
+ data : bytes
97
+ The data in JSON format
98
+
99
+ Returns
100
+ -------
101
+ Tuple[List[int] List[List[Any]]]
102
+
103
+ '''
104
+ row_ids = []
105
+ cols: List[Tuple[Any, Any]] = []
106
+ defaults: List[Any] = []
107
+ for row_id, *row in json.loads(data.decode('utf-8'))['data']:
108
+ row_ids.append(row_id)
109
+ if not defaults:
110
+ defaults = [DEFAULT_VALUES[colspec[i][1]] for i, _ in enumerate(row)]
111
+ if not cols:
112
+ cols = [([], []) for _ in row]
113
+ for i, (spec, x) in enumerate(zip(colspec, row)):
114
+ cols[i][0].append(decode_value(spec[1], x) if x is not None else defaults[i])
115
+ cols[i][1].append(False if x is not None else True)
116
+ return row_ids, cols
117
+
118
+
119
+ def load_pandas(
120
+ colspec: List[Tuple[str, int]],
121
+ data: bytes,
122
+ ) -> Tuple[List[int], List[Any]]:
123
+ '''
124
+ Convert bytes in JSON format into pd.Series
125
+
126
+ Parameters
127
+ ----------
128
+ colspec : Iterable[Tuple[str, int]]
129
+ An Iterable of column data types
130
+ data : bytes
131
+ The data in JSON format
132
+
133
+ Returns
134
+ -------
135
+ Tuple[pd.Series[int], List[pd.Series[Any]]
136
+
137
+ '''
138
+ if not has_pandas or not has_numpy:
139
+ raise RuntimeError('This operation requires pandas and numpy to be installed')
140
+
141
+ row_ids, cols = _load_vectors(colspec, data)
142
+ index = pd.Series(row_ids, dtype=np.longlong)
143
+ return index, \
144
+ [
145
+ (
146
+ pd.Series(
147
+ data, index=index, name=spec[0],
148
+ dtype=PANDAS_TYPE_MAP[spec[1]],
149
+ ),
150
+ pd.Series(mask, index=index, dtype=np.longlong),
151
+ )
152
+ for (data, mask), spec in zip(cols, colspec)
153
+ ]
154
+
155
+
156
+ def load_polars(
157
+ colspec: List[Tuple[str, int]],
158
+ data: bytes,
159
+ ) -> Tuple[List[int], List[Any]]:
160
+ '''
161
+ Convert bytes in JSON format into polars.Series
162
+
163
+ Parameters
164
+ ----------
165
+ colspec : Iterable[Tuple[str, int]]
166
+ An Iterable of column data types
167
+ data : bytes
168
+ The data in JSON format
169
+
170
+ Returns
171
+ -------
172
+ Tuple[polars.Series[int], List[polars.Series[Any]]
173
+
174
+ '''
175
+ if not has_polars or not has_numpy:
176
+ raise RuntimeError('This operation requires polars and numpy to be installed')
177
+
178
+ row_ids, cols = _load_vectors(colspec, data)
179
+ return pl.Series(None, row_ids, dtype=pl.Int64), \
180
+ [
181
+ (
182
+ pl.Series(spec[0], data, dtype=POLARS_TYPE_MAP[spec[1]]),
183
+ pl.Series(None, mask, dtype=pl.Boolean),
184
+ )
185
+ for (data, mask), spec in zip(cols, colspec)
186
+ ]
187
+
188
+
189
+ def load_numpy(
190
+ colspec: List[Tuple[str, int]],
191
+ data: bytes,
192
+ ) -> Tuple[Any, List[Any]]:
193
+ '''
194
+ Convert bytes in JSON format into np.ndarrays
195
+
196
+ Parameters
197
+ ----------
198
+ colspec : Iterable[Tuple[str, int]]
199
+ An Iterable of column data types
200
+ data : bytes
201
+ The data in JSON format
202
+
203
+ Returns
204
+ -------
205
+ Tuple[np.ndarray[int], List[np.ndarray[Any]]
206
+
207
+ '''
208
+ if not has_numpy:
209
+ raise RuntimeError('This operation requires numpy to be installed')
210
+
211
+ row_ids, cols = _load_vectors(colspec, data)
212
+ return np.asarray(row_ids, dtype=np.longlong), \
213
+ [
214
+ (
215
+ np.asarray(data, dtype=NUMPY_TYPE_MAP[spec[1]]),
216
+ np.asarray(mask, dtype=np.bool_),
217
+ )
218
+ for (data, mask), spec in zip(cols, colspec)
219
+ ]
220
+
221
+
222
+ def load_arrow(
223
+ colspec: List[Tuple[str, int]],
224
+ data: bytes,
225
+ ) -> Tuple[Any, List[Any]]:
226
+ '''
227
+ Convert bytes in JSON format into pyarrow.Arrays
228
+
229
+ Parameters
230
+ ----------
231
+ colspec : Iterable[Tuple[str, int]]
232
+ An Iterable of column data types
233
+ data : bytes
234
+ The data in JSON format
235
+
236
+ Returns
237
+ -------
238
+ Tuple[pyarrow.Array[int], List[pyarrow.Array[Any]]
239
+
240
+ '''
241
+ if not has_pyarrow or not has_numpy:
242
+ raise RuntimeError('This operation requires pyarrow and numpy to be installed')
243
+
244
+ row_ids, cols = _load_vectors(colspec, data)
245
+ return pa.array(row_ids, type=pa.int64()), \
246
+ [
247
+ (
248
+ pa.array(
249
+ data, type=PYARROW_TYPE_MAP[dtype],
250
+ mask=pa.array(mask, type=pa.bool_()),
251
+ ),
252
+ pa.array(mask, type=pa.bool_()),
253
+ )
254
+ for (data, mask), (name, dtype) in zip(cols, colspec)
255
+ ]
256
+
257
+
258
+ def dump(
259
+ returns: List[int],
260
+ row_ids: List[int],
261
+ rows: List[List[Any]],
262
+ ) -> bytes:
263
+ '''
264
+ Convert a list of lists of data into JSON format.
265
+
266
+ Parameters
267
+ ----------
268
+ returns : List[int]
269
+ The returned data type
270
+ row_ids : List[int]
271
+ Row IDs
272
+ rows : List[List[Any]]
273
+ The rows of data to serialize
274
+
275
+ Returns
276
+ -------
277
+ bytes
278
+
279
+ '''
280
+ data = list(zip(row_ids, *list(zip(*rows))))
281
+ return json.dumps(dict(data=data), cls=JSONEncoder).encode('utf-8')
282
+
283
+
284
+ def _dump_vectors(
285
+ returns: List[int],
286
+ row_ids: List[int],
287
+ cols: List[Tuple[Any, Any]],
288
+ ) -> bytes:
289
+ '''
290
+ Convert a list of lists of data into JSON format.
291
+
292
+ Parameters
293
+ ----------
294
+ returns : List[int]
295
+ The returned data type
296
+ row_ids : List[int]
297
+ Row IDs
298
+ cols : List[Tuple[Any, Any]]
299
+ The rows of data to serialize
300
+
301
+ Returns
302
+ -------
303
+ bytes
304
+
305
+ '''
306
+ masked_cols = []
307
+ for i, (data, mask) in enumerate(cols):
308
+ if mask is not None:
309
+ masked_cols.append([d if m is not None else None for d, m in zip(data, mask)])
310
+ else:
311
+ masked_cols.append(cols[i][0])
312
+ data = list(zip(row_ids, *masked_cols))
313
+ return json.dumps(dict(data=data), cls=JSONEncoder).encode('utf-8')
314
+
315
+
316
+ def dump_pandas(
317
+ returns: List[int],
318
+ row_ids: 'pd.Series[int]',
319
+ cols: List[Tuple['pd.Series[int]', 'pd.Series[bool]']],
320
+ ) -> bytes:
321
+ '''
322
+ Convert a list of pd.Series of data into JSON format.
323
+
324
+ Parameters
325
+ ----------
326
+ returns : List[int]
327
+ The returned data type
328
+ row_ids : pd.Series[int]
329
+ Row IDs
330
+ cols : List[Tuple[pd.Series[Any], pd.Series[bool]]]
331
+ The rows of data to serialize
332
+
333
+ Returns
334
+ -------
335
+ bytes
336
+
337
+ '''
338
+ import pandas as pd
339
+ row_ids.index = row_ids
340
+ df = pd.concat([row_ids] + [x[0] for x in cols], axis=1)
341
+ return ('{"data": %s}' % df.to_json(orient='values')).encode('utf-8')
342
+
343
+
344
+ def dump_polars(
345
+ returns: List[int],
346
+ row_ids: 'pl.Series[int]',
347
+ cols: List[Tuple['pl.Series[Any]', 'pl.Series[int]']],
348
+ ) -> bytes:
349
+ '''
350
+ Convert a list of polars.Series of data into JSON format.
351
+
352
+ Parameters
353
+ ----------
354
+ returns : List[int]
355
+ The returned data type
356
+ row_ids : List[int]
357
+ cols : List[Tuple[polars.Series[Any], polars.Series[bool]]
358
+ The rows of data to serialize
359
+
360
+ Returns
361
+ -------
362
+ bytes
363
+
364
+ '''
365
+ return _dump_vectors(
366
+ returns,
367
+ row_ids.to_list(),
368
+ [(x[0].to_list(), x[1].to_list() if x[1] is not None else None) for x in cols],
369
+ )
370
+
371
+
372
+ def dump_numpy(
373
+ returns: List[int],
374
+ row_ids: 'np.typing.NDArray[np.int64]',
375
+ cols: List[Tuple['np.typing.NDArray[Any]', 'np.typing.NDArray[np.bool_]']],
376
+ ) -> bytes:
377
+ '''
378
+ Convert a list of np.ndarrays of data into JSON format.
379
+
380
+ Parameters
381
+ ----------
382
+ returns : List[int]
383
+ The returned data type
384
+ row_ids : List[int]
385
+ Row IDs
386
+ cols : List[Tuple[np.ndarray[Any], np.ndarray[bool]]]
387
+ The rows of data to serialize
388
+
389
+ Returns
390
+ -------
391
+ bytes
392
+
393
+ '''
394
+ return _dump_vectors(
395
+ returns,
396
+ row_ids.tolist(),
397
+ [(x[0].tolist(), x[1].tolist() if x[1] is not None else None) for x in cols],
398
+ )
399
+
400
+
401
+ def dump_arrow(
402
+ returns: List[int],
403
+ row_ids: 'pa.Array[int]',
404
+ cols: List[Tuple['pa.Array[int]', 'pa.Array[bool]']],
405
+ ) -> bytes:
406
+ '''
407
+ Convert a list of pyarrow.Arrays of data into JSON format.
408
+
409
+ Parameters
410
+ ----------
411
+ returns : List[int]
412
+ The returned data type
413
+ row_ids : pyarrow.Array[int]
414
+ Row IDs
415
+ cols : List[Tuple[pyarrow.Array[Any], pyarrow.Array[Any]]]
416
+ The rows of data to serialize
417
+
418
+ Returns
419
+ -------
420
+ bytes
421
+
422
+ '''
423
+ return _dump_vectors(
424
+ returns,
425
+ row_ids.tolist(),
426
+ [(x[0].tolist(), x[1].tolist() if x[1] is not None else None) for x in cols],
427
+ )