singlestoredb 1.11.0__py3-none-any.whl → 1.12.0__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.
- singlestoredb/__init__.py +1 -1
- singlestoredb/config.py +6 -0
- singlestoredb/connection.py +7 -0
- singlestoredb/converters.py +5 -5
- singlestoredb/functions/__init__.py +1 -0
- singlestoredb/functions/decorator.py +258 -69
- singlestoredb/functions/ext/asgi.py +121 -27
- singlestoredb/functions/signature.py +100 -9
- singlestoredb/fusion/handlers/export.py +58 -2
- singlestoredb/fusion/handlers/files.py +6 -6
- singlestoredb/fusion/result.py +1 -1
- singlestoredb/http/connection.py +4 -0
- singlestoredb/management/export.py +30 -7
- singlestoredb/mysql/connection.py +24 -19
- singlestoredb/server/__init__.py +0 -0
- singlestoredb/server/docker.py +455 -0
- singlestoredb/server/free_tier.py +267 -0
- singlestoredb/tests/test_udf.py +84 -32
- {singlestoredb-1.11.0.dist-info → singlestoredb-1.12.0.dist-info}/METADATA +3 -1
- {singlestoredb-1.11.0.dist-info → singlestoredb-1.12.0.dist-info}/RECORD +24 -21
- {singlestoredb-1.11.0.dist-info → singlestoredb-1.12.0.dist-info}/LICENSE +0 -0
- {singlestoredb-1.11.0.dist-info → singlestoredb-1.12.0.dist-info}/WHEEL +0 -0
- {singlestoredb-1.11.0.dist-info → singlestoredb-1.12.0.dist-info}/entry_points.txt +0 -0
- {singlestoredb-1.11.0.dist-info → singlestoredb-1.12.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Utilities for running SingleStoreDB in the free tier."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import atexit
|
|
6
|
+
import os
|
|
7
|
+
import platform
|
|
8
|
+
import signal
|
|
9
|
+
import subprocess
|
|
10
|
+
import urllib.parse
|
|
11
|
+
from types import TracebackType
|
|
12
|
+
from typing import Any
|
|
13
|
+
from typing import Dict
|
|
14
|
+
from typing import List
|
|
15
|
+
from typing import Optional
|
|
16
|
+
from typing import Type
|
|
17
|
+
|
|
18
|
+
import requests
|
|
19
|
+
|
|
20
|
+
from .. import connect
|
|
21
|
+
from ..connection import Connection
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
import pymongo
|
|
25
|
+
has_pymongo = True
|
|
26
|
+
except ImportError:
|
|
27
|
+
has_pymongo = False
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SingleStoreDB:
|
|
31
|
+
"""
|
|
32
|
+
Manager for SingleStoreDB server running in Docker.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
-----------
|
|
36
|
+
global_vars : dict, optional
|
|
37
|
+
Global variables to set in the SingleStoreDB server.
|
|
38
|
+
init_sql : str, optional
|
|
39
|
+
Path to an SQL file to run on startup.
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
user: str
|
|
44
|
+
password: str
|
|
45
|
+
kai_enabled: bool
|
|
46
|
+
server_port: int
|
|
47
|
+
data_api_port: int
|
|
48
|
+
kai_port: Optional[int]
|
|
49
|
+
|
|
50
|
+
def __init__(self) -> None:
|
|
51
|
+
r = requests.get('https://shell.singlestore.com/api/session')
|
|
52
|
+
|
|
53
|
+
self._cookies = r.cookies.get_dict()
|
|
54
|
+
|
|
55
|
+
if 'userSessionID' in self._cookies:
|
|
56
|
+
self._session_id = self._cookies['userSessionID']
|
|
57
|
+
else:
|
|
58
|
+
self._session_id = ''
|
|
59
|
+
|
|
60
|
+
d = r.json()
|
|
61
|
+
|
|
62
|
+
self._connected = True
|
|
63
|
+
self.kai_enabled = True
|
|
64
|
+
self.kai_port = 27017
|
|
65
|
+
self.server_port = 3333
|
|
66
|
+
self.data_api_port = 443
|
|
67
|
+
self.user = d['user']
|
|
68
|
+
self.password = d['password']
|
|
69
|
+
self._database = d['databaseName']
|
|
70
|
+
self._endpoint = d['endpoint']
|
|
71
|
+
self._workspace_id = d['workspaceID']
|
|
72
|
+
|
|
73
|
+
self._saved_server_urls: Dict[str, Optional[str]] = {}
|
|
74
|
+
|
|
75
|
+
# Make sure container gets cleaned up at exit
|
|
76
|
+
atexit.register(self.stop)
|
|
77
|
+
signal.signal(signal.SIGINT, self.stop)
|
|
78
|
+
signal.signal(signal.SIGTERM, self.stop)
|
|
79
|
+
|
|
80
|
+
self._set_server_urls()
|
|
81
|
+
|
|
82
|
+
def __str__(self) -> str:
|
|
83
|
+
return f"SingleStoreDB('{self.connection_url}')"
|
|
84
|
+
|
|
85
|
+
def __repr__(self) -> str:
|
|
86
|
+
return str(self)
|
|
87
|
+
|
|
88
|
+
def _set_server_urls(self) -> None:
|
|
89
|
+
self._saved_server_urls['DATABASE_URL'] = os.environ.get('DATABASE_URL')
|
|
90
|
+
os.environ['DATABASE_URL'] = self.connection_url
|
|
91
|
+
self._saved_server_urls['SINGLESTOREDB_URL'] = os.environ.get('SINGLESTOREDB_URL')
|
|
92
|
+
os.environ['SINGLESTOREDB_URL'] = self.connection_url
|
|
93
|
+
|
|
94
|
+
def _restore_server_urls(self) -> None:
|
|
95
|
+
try:
|
|
96
|
+
for k, v in self._saved_server_urls.items():
|
|
97
|
+
if v is None:
|
|
98
|
+
del os.environ[k]
|
|
99
|
+
else:
|
|
100
|
+
os.environ[k] = v
|
|
101
|
+
except KeyError:
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
def logs(self) -> List[str]:
|
|
105
|
+
return []
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def connection_url(self) -> str:
|
|
109
|
+
"""Connection URL for the SingleStoreDB server."""
|
|
110
|
+
dbname = f'/{self._database}' if self._database else ''
|
|
111
|
+
password = urllib.parse.quote_plus(self.password)
|
|
112
|
+
return f'singlestoredb://{self.user}:{password}@' + \
|
|
113
|
+
f'{self._endpoint}:{self.server_port}{dbname}'
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def http_connection_url(self) -> str:
|
|
117
|
+
"""HTTP Connection URL for the SingleStoreDB server."""
|
|
118
|
+
dbname = f'/{self._database}' if self._database else ''
|
|
119
|
+
password = urllib.parse.quote_plus(self.password)
|
|
120
|
+
return f'singlestoredb+https://{self.user}:{password}@' + \
|
|
121
|
+
f'{self._endpoint}:{self.data_api_port}{dbname}'
|
|
122
|
+
|
|
123
|
+
def connect(
|
|
124
|
+
self,
|
|
125
|
+
use_data_api: bool = False,
|
|
126
|
+
**kwargs: Any,
|
|
127
|
+
) -> Connection:
|
|
128
|
+
"""
|
|
129
|
+
Connect to the SingleStoreDB server.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
-----------
|
|
133
|
+
use_data_api : bool, optional
|
|
134
|
+
Use the Data API for the connection.
|
|
135
|
+
**kwargs : Any, optional
|
|
136
|
+
Additional keyword arguments to pass to the connection.
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
--------
|
|
140
|
+
Connection : Connection to the SingleStoreDB server.
|
|
141
|
+
|
|
142
|
+
"""
|
|
143
|
+
if use_data_api:
|
|
144
|
+
return connect(self.http_connection_url, **kwargs)
|
|
145
|
+
return connect(self.connection_url, **kwargs)
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def kai_url(self) -> Optional[str]:
|
|
149
|
+
"""Connection URL for the Kai (MongoDB) server."""
|
|
150
|
+
if not self.kai_enabled:
|
|
151
|
+
return None
|
|
152
|
+
password = urllib.parse.quote_plus(self.password)
|
|
153
|
+
endpoint = self._endpoint.replace('shared-dml', 'shared-mongo')
|
|
154
|
+
return f'mongodb://{self.user}^{self._database}:{password}@' + \
|
|
155
|
+
f'{endpoint}:{self.kai_port}/' + \
|
|
156
|
+
'?authMechanism=PLAIN&tls=true&loadBalanced=true' + \
|
|
157
|
+
f'&dbName={self._database}'
|
|
158
|
+
|
|
159
|
+
def connect_kai(self) -> 'pymongo.MongoClient':
|
|
160
|
+
"""Connect to the Kai (MongoDB) server."""
|
|
161
|
+
if not self.kai_enabled:
|
|
162
|
+
raise RuntimeError('kai is not enabled')
|
|
163
|
+
if not has_pymongo:
|
|
164
|
+
raise RuntimeError('pymongo is not installed')
|
|
165
|
+
return pymongo.MongoClient(self.kai_url)
|
|
166
|
+
|
|
167
|
+
def open_shell(self) -> None:
|
|
168
|
+
"""Open a shell in the SingleStoreDB server."""
|
|
169
|
+
if platform.platform().lower().startswith('macos'):
|
|
170
|
+
subprocess.call(
|
|
171
|
+
' '.join([
|
|
172
|
+
'osascript', '-e',
|
|
173
|
+
'tell app "Terminal" to do script "' +
|
|
174
|
+
' '.join([
|
|
175
|
+
'mysql', '-h', self._endpoint,
|
|
176
|
+
'-P', str(self.server_port),
|
|
177
|
+
'-u', self.user,
|
|
178
|
+
f'--password=\'{self.password}\'',
|
|
179
|
+
self._database,
|
|
180
|
+
]) +
|
|
181
|
+
'"',
|
|
182
|
+
]), shell=True,
|
|
183
|
+
)
|
|
184
|
+
elif platform.platform().lower().startswith('linux'):
|
|
185
|
+
subprocess.call(
|
|
186
|
+
' '.join([
|
|
187
|
+
'gnome-terminal', '--',
|
|
188
|
+
'mysql', '-h', self._endpoint,
|
|
189
|
+
'-P', str(self.server_port),
|
|
190
|
+
'-u', self.user,
|
|
191
|
+
f'--password="{self.password}"',
|
|
192
|
+
self._database,
|
|
193
|
+
]), shell=True,
|
|
194
|
+
)
|
|
195
|
+
elif platform.platform().lower().startswith('windows'):
|
|
196
|
+
subprocess.call(
|
|
197
|
+
' '.join([
|
|
198
|
+
'start', 'cmd', '/k'
|
|
199
|
+
'mysql', '-h', self._endpoint,
|
|
200
|
+
'-P', str(self.server_port),
|
|
201
|
+
'-u', self.user,
|
|
202
|
+
f'--password="{self.password}"',
|
|
203
|
+
self._database,
|
|
204
|
+
]), shell=True,
|
|
205
|
+
)
|
|
206
|
+
else:
|
|
207
|
+
raise RuntimeError('unsupported platform')
|
|
208
|
+
|
|
209
|
+
def open_mongosh(self) -> None:
|
|
210
|
+
"""Open a mongosh in the SingleStoreDB server."""
|
|
211
|
+
if not self.kai_enabled:
|
|
212
|
+
raise RuntimeError('kai interface is not enabled')
|
|
213
|
+
if platform.platform().lower().startswith('macos'):
|
|
214
|
+
subprocess.call([
|
|
215
|
+
'osascript', '-e',
|
|
216
|
+
'tell app "Terminal" to do script "' +
|
|
217
|
+
' '.join(['mongosh', str(self.kai_url)]) +
|
|
218
|
+
'"',
|
|
219
|
+
])
|
|
220
|
+
elif platform.platform().lower().startswith('linux'):
|
|
221
|
+
subprocess.call([
|
|
222
|
+
'gnome-terminal', '--',
|
|
223
|
+
'mongosh', str(self.kai_url),
|
|
224
|
+
])
|
|
225
|
+
elif platform.platform().lower().startswith('windows'):
|
|
226
|
+
subprocess.call([
|
|
227
|
+
'start', 'cmd', '/k'
|
|
228
|
+
'mongosh', str(self.kai_url),
|
|
229
|
+
])
|
|
230
|
+
else:
|
|
231
|
+
raise RuntimeError('unsupported platform')
|
|
232
|
+
|
|
233
|
+
def __enter__(self) -> SingleStoreDB:
|
|
234
|
+
return self
|
|
235
|
+
|
|
236
|
+
def __exit__(
|
|
237
|
+
self,
|
|
238
|
+
exc_type: Optional[Type[BaseException]],
|
|
239
|
+
exc_val: Optional[BaseException],
|
|
240
|
+
exc_tb: Optional[TracebackType],
|
|
241
|
+
) -> Optional[bool]:
|
|
242
|
+
self.stop()
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
def stop(self, *args: Any) -> None:
|
|
246
|
+
"""Stop the SingleStoreDB server."""
|
|
247
|
+
if self._connected is not None:
|
|
248
|
+
self._restore_server_urls()
|
|
249
|
+
try:
|
|
250
|
+
requests.get(
|
|
251
|
+
'https://shell.singlestore.com/api/terminate',
|
|
252
|
+
cookies=self._cookies,
|
|
253
|
+
)
|
|
254
|
+
finally:
|
|
255
|
+
self._connected = False
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def start() -> SingleStoreDB:
|
|
259
|
+
"""
|
|
260
|
+
Manager for SingleStoreDB server running in Docker.
|
|
261
|
+
|
|
262
|
+
Returns
|
|
263
|
+
-------
|
|
264
|
+
SingleStoreDB
|
|
265
|
+
|
|
266
|
+
"""
|
|
267
|
+
return SingleStoreDB()
|
singlestoredb/tests/test_udf.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
# type: ignore
|
|
3
3
|
"""SingleStoreDB UDF testing."""
|
|
4
|
+
import dataclasses
|
|
4
5
|
import datetime
|
|
5
6
|
import re
|
|
6
7
|
import unittest
|
|
@@ -11,9 +12,11 @@ from typing import TypeVar
|
|
|
11
12
|
from typing import Union
|
|
12
13
|
|
|
13
14
|
import numpy as np
|
|
15
|
+
import pydantic
|
|
14
16
|
|
|
15
17
|
from ..functions import dtypes as dt
|
|
16
18
|
from ..functions import signature as sig
|
|
19
|
+
from ..functions import tvf
|
|
17
20
|
from ..functions import udf
|
|
18
21
|
|
|
19
22
|
|
|
@@ -28,7 +31,7 @@ def to_sql(x):
|
|
|
28
31
|
out = sig.signature_to_sql(sig.get_signature(x))
|
|
29
32
|
out = re.sub(r'^CREATE EXTERNAL FUNCTION ', r'', out)
|
|
30
33
|
out = re.sub(r' AS REMOTE SERVICE.+$', r'', out)
|
|
31
|
-
return out
|
|
34
|
+
return out.strip()
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
class TestUDF(unittest.TestCase):
|
|
@@ -99,27 +102,27 @@ class TestUDF(unittest.TestCase):
|
|
|
99
102
|
|
|
100
103
|
# Tuple
|
|
101
104
|
def foo() -> Tuple[int, float, str]: ...
|
|
102
|
-
assert to_sql(foo) == '`foo`() RETURNS RECORD(a BIGINT NOT NULL, ' \
|
|
103
|
-
'b DOUBLE NOT NULL, ' \
|
|
104
|
-
'c TEXT NOT NULL) NOT NULL'
|
|
105
|
+
assert to_sql(foo) == '`foo`() RETURNS RECORD(`a` BIGINT NOT NULL, ' \
|
|
106
|
+
'`b` DOUBLE NOT NULL, ' \
|
|
107
|
+
'`c` TEXT NOT NULL) NOT NULL'
|
|
105
108
|
|
|
106
109
|
# Optional tuple
|
|
107
110
|
def foo() -> Optional[Tuple[int, float, str]]: ...
|
|
108
|
-
assert to_sql(foo) == '`foo`() RETURNS RECORD(a BIGINT NOT NULL, ' \
|
|
109
|
-
'b DOUBLE NOT NULL, ' \
|
|
110
|
-
'c TEXT NOT NULL) NULL'
|
|
111
|
+
assert to_sql(foo) == '`foo`() RETURNS RECORD(`a` BIGINT NOT NULL, ' \
|
|
112
|
+
'`b` DOUBLE NOT NULL, ' \
|
|
113
|
+
'`c` TEXT NOT NULL) NULL'
|
|
111
114
|
|
|
112
115
|
# Optional tuple with optional element
|
|
113
116
|
def foo() -> Optional[Tuple[int, float, Optional[str]]]: ...
|
|
114
|
-
assert to_sql(foo) == '`foo`() RETURNS RECORD(a BIGINT NOT NULL, ' \
|
|
115
|
-
'b DOUBLE NOT NULL, ' \
|
|
116
|
-
'c TEXT NULL) NULL'
|
|
117
|
+
assert to_sql(foo) == '`foo`() RETURNS RECORD(`a` BIGINT NOT NULL, ' \
|
|
118
|
+
'`b` DOUBLE NOT NULL, ' \
|
|
119
|
+
'`c` TEXT NULL) NULL'
|
|
117
120
|
|
|
118
121
|
# Optional tuple with optional union element
|
|
119
122
|
def foo() -> Optional[Tuple[int, Optional[Union[float, int]], str]]: ...
|
|
120
|
-
assert to_sql(foo) == '`foo`() RETURNS RECORD(a BIGINT NOT NULL, ' \
|
|
121
|
-
'b DOUBLE NULL, ' \
|
|
122
|
-
'c TEXT NOT NULL) NULL'
|
|
123
|
+
assert to_sql(foo) == '`foo`() RETURNS RECORD(`a` BIGINT NOT NULL, ' \
|
|
124
|
+
'`b` DOUBLE NULL, ' \
|
|
125
|
+
'`c` TEXT NOT NULL) NULL'
|
|
123
126
|
|
|
124
127
|
# Unknown type
|
|
125
128
|
def foo() -> set: ...
|
|
@@ -182,21 +185,21 @@ class TestUDF(unittest.TestCase):
|
|
|
182
185
|
|
|
183
186
|
# Tuple
|
|
184
187
|
def foo(x: Tuple[int, float, str]) -> None: ...
|
|
185
|
-
assert to_sql(foo) == '`foo`(`x` RECORD(a BIGINT NOT NULL, ' \
|
|
186
|
-
'b DOUBLE NOT NULL, ' \
|
|
187
|
-
'c TEXT NOT NULL) NOT NULL) RETURNS NULL'
|
|
188
|
+
assert to_sql(foo) == '`foo`(`x` RECORD(`a` BIGINT NOT NULL, ' \
|
|
189
|
+
'`b` DOUBLE NOT NULL, ' \
|
|
190
|
+
'`c` TEXT NOT NULL) NOT NULL) RETURNS NULL'
|
|
188
191
|
|
|
189
192
|
# Optional tuple with optional element
|
|
190
193
|
def foo(x: Optional[Tuple[int, float, Optional[str]]]) -> None: ...
|
|
191
|
-
assert to_sql(foo) == '`foo`(`x` RECORD(a BIGINT NOT NULL, ' \
|
|
192
|
-
'b DOUBLE NOT NULL, ' \
|
|
193
|
-
'c TEXT NULL) NULL) RETURNS NULL'
|
|
194
|
+
assert to_sql(foo) == '`foo`(`x` RECORD(`a` BIGINT NOT NULL, ' \
|
|
195
|
+
'`b` DOUBLE NOT NULL, ' \
|
|
196
|
+
'`c` TEXT NULL) NULL) RETURNS NULL'
|
|
194
197
|
|
|
195
198
|
# Optional tuple with optional union element
|
|
196
199
|
def foo(x: Optional[Tuple[int, Optional[Union[float, int]], str]]) -> None: ...
|
|
197
|
-
assert to_sql(foo) == '`foo`(`x` RECORD(a BIGINT NOT NULL, ' \
|
|
198
|
-
'b DOUBLE NULL, ' \
|
|
199
|
-
'c TEXT NOT NULL) NULL) RETURNS NULL'
|
|
200
|
+
assert to_sql(foo) == '`foo`(`x` RECORD(`a` BIGINT NOT NULL, ' \
|
|
201
|
+
'`b` DOUBLE NULL, ' \
|
|
202
|
+
'`c` TEXT NOT NULL) NULL) RETURNS NULL'
|
|
200
203
|
|
|
201
204
|
# Unknown type
|
|
202
205
|
def foo(x: set) -> None: ...
|
|
@@ -391,16 +394,6 @@ class TestUDF(unittest.TestCase):
|
|
|
391
394
|
'`y` DOUBLE NOT NULL, ' \
|
|
392
395
|
'`z` CHAR(30) NULL) RETURNS SMALLINT NOT NULL'
|
|
393
396
|
|
|
394
|
-
# Override parameter with incorrect type
|
|
395
|
-
with self.assertRaises(TypeError):
|
|
396
|
-
@udf(args=dict(x=int))
|
|
397
|
-
def foo(x: int, y: float, z: str) -> int: ...
|
|
398
|
-
|
|
399
|
-
# Override return value with incorrect type
|
|
400
|
-
with self.assertRaises(TypeError):
|
|
401
|
-
@udf(returns=int)
|
|
402
|
-
def foo(x: int, y: float, z: str) -> int: ...
|
|
403
|
-
|
|
404
397
|
# Change function name
|
|
405
398
|
@udf(name='hello_world')
|
|
406
399
|
def foo(x: int) -> int: ...
|
|
@@ -412,6 +405,65 @@ class TestUDF(unittest.TestCase):
|
|
|
412
405
|
assert to_sql(foo) == '`hello``_``world`(`x` BIGINT NOT NULL) ' \
|
|
413
406
|
'RETURNS BIGINT NOT NULL'
|
|
414
407
|
|
|
408
|
+
@dataclasses.dataclass
|
|
409
|
+
class MyData:
|
|
410
|
+
one: Optional[int]
|
|
411
|
+
two: str
|
|
412
|
+
three: float
|
|
413
|
+
|
|
414
|
+
@udf
|
|
415
|
+
def foo(x: int) -> MyData: ...
|
|
416
|
+
assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \
|
|
417
|
+
'RETURNS RECORD(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \
|
|
418
|
+
'`three` DOUBLE NOT NULL) NOT NULL'
|
|
419
|
+
|
|
420
|
+
@udf(returns=MyData)
|
|
421
|
+
def foo(x: int) -> Tuple[int, int, int]: ...
|
|
422
|
+
assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \
|
|
423
|
+
'RETURNS RECORD(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \
|
|
424
|
+
'`three` DOUBLE NOT NULL) NOT NULL'
|
|
425
|
+
|
|
426
|
+
@tvf
|
|
427
|
+
def foo(x: int) -> MyData: ...
|
|
428
|
+
assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \
|
|
429
|
+
'RETURNS TABLE(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \
|
|
430
|
+
'`three` DOUBLE NOT NULL)'
|
|
431
|
+
|
|
432
|
+
@tvf(returns=MyData)
|
|
433
|
+
def foo(x: int) -> Tuple[int, int, int]: ...
|
|
434
|
+
assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \
|
|
435
|
+
'RETURNS TABLE(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \
|
|
436
|
+
'`three` DOUBLE NOT NULL)'
|
|
437
|
+
|
|
438
|
+
class MyData(pydantic.BaseModel):
|
|
439
|
+
one: Optional[int]
|
|
440
|
+
two: str
|
|
441
|
+
three: float
|
|
442
|
+
|
|
443
|
+
@udf
|
|
444
|
+
def foo(x: int) -> MyData: ...
|
|
445
|
+
assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \
|
|
446
|
+
'RETURNS RECORD(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \
|
|
447
|
+
'`three` DOUBLE NOT NULL) NOT NULL'
|
|
448
|
+
|
|
449
|
+
@udf(returns=MyData)
|
|
450
|
+
def foo(x: int) -> Tuple[int, int, int]: ...
|
|
451
|
+
assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \
|
|
452
|
+
'RETURNS RECORD(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \
|
|
453
|
+
'`three` DOUBLE NOT NULL) NOT NULL'
|
|
454
|
+
|
|
455
|
+
@tvf
|
|
456
|
+
def foo(x: int) -> MyData: ...
|
|
457
|
+
assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \
|
|
458
|
+
'RETURNS TABLE(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \
|
|
459
|
+
'`three` DOUBLE NOT NULL)'
|
|
460
|
+
|
|
461
|
+
@tvf(returns=MyData)
|
|
462
|
+
def foo(x: int) -> Tuple[int, int, int]: ...
|
|
463
|
+
assert to_sql(foo) == '`foo`(`x` BIGINT NOT NULL) ' \
|
|
464
|
+
'RETURNS TABLE(`one` BIGINT NULL, `two` TEXT NOT NULL, ' \
|
|
465
|
+
'`three` DOUBLE NOT NULL)'
|
|
466
|
+
|
|
415
467
|
def test_dtypes(self):
|
|
416
468
|
assert dt.BOOL() == 'BOOL NULL'
|
|
417
469
|
assert dt.BOOL(nullable=False) == 'BOOL NOT NULL'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: singlestoredb
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.12.0
|
|
4
4
|
Summary: Interface to the SingleStoreDB database and workspace management APIs
|
|
5
5
|
Home-page: https://github.com/singlestore-labs/singlestoredb-python
|
|
6
6
|
Author: SingleStore
|
|
@@ -26,6 +26,8 @@ Provides-Extra: dataframe
|
|
|
26
26
|
Requires-Dist: ibis-singlestoredb; extra == "dataframe"
|
|
27
27
|
Provides-Extra: dbt
|
|
28
28
|
Requires-Dist: dbt-singlestore; extra == "dbt"
|
|
29
|
+
Provides-Extra: docker
|
|
30
|
+
Requires-Dist: docker; extra == "docker"
|
|
29
31
|
Provides-Extra: ed22519
|
|
30
32
|
Requires-Dist: PyNaCl>=1.4.0; extra == "ed22519"
|
|
31
33
|
Provides-Extra: gssapi
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
singlestoredb/__init__.py,sha256=
|
|
1
|
+
singlestoredb/__init__.py,sha256=rMEoyZJpkhiOhcoZLCItPxn7d2AppFdBTIwmK7t_Y7E,1649
|
|
2
2
|
singlestoredb/auth.py,sha256=u8D9tpKzrqa4ssaHjyZnGDX1q8XBpGtuoOkTkSv7B28,7599
|
|
3
|
-
singlestoredb/config.py,sha256=
|
|
4
|
-
singlestoredb/connection.py,sha256=
|
|
5
|
-
singlestoredb/converters.py,sha256=
|
|
3
|
+
singlestoredb/config.py,sha256=rlF69SiclYyKghNRckX77Ls1ZT23RhSssO1cyYBiHmA,12589
|
|
4
|
+
singlestoredb/connection.py,sha256=0HEpjBZXLqQwOTEfveMkgej1H3Kyof47prIHvJJZtoo,45831
|
|
5
|
+
singlestoredb/converters.py,sha256=Ui-AqdW3pRAQ8A_YcK9EqVYyM4Pt1_Q-tjlotbpK6Cw,20686
|
|
6
6
|
singlestoredb/exceptions.py,sha256=HuoA6sMRL5qiCiee-_5ddTGmFbYC9Euk8TYUsh5GvTw,3234
|
|
7
7
|
singlestoredb/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
singlestoredb/pytest.py,sha256=OyF3BO9mgxenifYhOihnzGk8WzCJ_zN5_mxe8XyFPOc,9074
|
|
@@ -18,13 +18,13 @@ singlestoredb/apps/_dashboards.py,sha256=_03fI-GJannamA5lxLvIoC6Mim-H1jTRuI8-dw_
|
|
|
18
18
|
singlestoredb/apps/_process.py,sha256=G37fk6bzIxzhfEqp2aJBk3JCij-T2HFtTd078k5Xq9I,944
|
|
19
19
|
singlestoredb/apps/_stdout_supress.py,sha256=8s9zMIIRPpeu44yluJFc_0VueAxZDmr9QVGT6TGiFeY,659
|
|
20
20
|
singlestoredb/apps/_uvicorn_util.py,sha256=rEK4nEmq5hbpRgsmK16UVlxe2DyQSq7C5w5WZSp0kX8,962
|
|
21
|
-
singlestoredb/functions/__init__.py,sha256=
|
|
22
|
-
singlestoredb/functions/decorator.py,sha256=
|
|
21
|
+
singlestoredb/functions/__init__.py,sha256=nPaLVgtb5XDxbRucDFFwjePPh4n40_6jcbxE8HPebkQ,82
|
|
22
|
+
singlestoredb/functions/decorator.py,sha256=0gfYVCi_GvxKcuDmAcpfIFTTElLD0CBT8RYN_dUrEvU,11485
|
|
23
23
|
singlestoredb/functions/dtypes.py,sha256=a2vevIug8NhiUCFiSOKwRPpdWU69Gn13ZoQ6Aovskhc,31408
|
|
24
|
-
singlestoredb/functions/signature.py,sha256=
|
|
24
|
+
singlestoredb/functions/signature.py,sha256=y3QKjjM9weZjIZyFE-E4SEFx5i3sgP8rqTC0iJ0hhaM,22396
|
|
25
25
|
singlestoredb/functions/ext/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
|
|
26
26
|
singlestoredb/functions/ext/arrow.py,sha256=WB7n1ACslyd8nlbFzUvlbxn1BVuEjA9-BGBEqCWlSOo,9061
|
|
27
|
-
singlestoredb/functions/ext/asgi.py,sha256=
|
|
27
|
+
singlestoredb/functions/ext/asgi.py,sha256=UMZVrw2G_a5SDNy4X7uVJeidfR5HobJN1qLMLqPBAeM,43535
|
|
28
28
|
singlestoredb/functions/ext/json.py,sha256=XkI8jirxi1T9F-M0p9NpLezph0MRAhYmDiPuU2Id0Uo,10404
|
|
29
29
|
singlestoredb/functions/ext/mmap.py,sha256=OB6CIYoLe_AYuJM10lE0I6QhZJ5kMhLNbQo2Sp1wiZA,13711
|
|
30
30
|
singlestoredb/functions/ext/rowdat_1.py,sha256=JgKRsVSQYczFD6cmo2xLilbNPYpyLL2tPOWO1Gh25ow,22306
|
|
@@ -33,24 +33,24 @@ singlestoredb/fusion/__init__.py,sha256=Qo7SuqGw-l-vE8-EI2jhm6hXJkYfOLUKIws9c7LF
|
|
|
33
33
|
singlestoredb/fusion/graphql.py,sha256=ZA3HcDq5rER-dCEavwTqnF7KM0D2LCYIY7nLQk7lSso,5207
|
|
34
34
|
singlestoredb/fusion/handler.py,sha256=HEW83De1zj94hvG7rbqlOszIIgBKiag0UGO5I0WoJ6A,27400
|
|
35
35
|
singlestoredb/fusion/registry.py,sha256=jjdRTYZ3ylhy6gAoW5xBj0tkxGFBT-2yLQ0tztTgDIY,6112
|
|
36
|
-
singlestoredb/fusion/result.py,sha256=
|
|
36
|
+
singlestoredb/fusion/result.py,sha256=p5I65C-Dhhl1yeZwetXXZabwritr8Ph2mFvJJ3ovcBM,11790
|
|
37
37
|
singlestoredb/fusion/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
-
singlestoredb/fusion/handlers/export.py,sha256=
|
|
39
|
-
singlestoredb/fusion/handlers/files.py,sha256=
|
|
38
|
+
singlestoredb/fusion/handlers/export.py,sha256=3moTJeqsHkDDpitUUAE6x95JYH2rmb28MALbO4x0dcc,8981
|
|
39
|
+
singlestoredb/fusion/handlers/files.py,sha256=McoRacihcQn0-qILujBi0HCNyuFcrBoIUGlkWlg1cII,18991
|
|
40
40
|
singlestoredb/fusion/handlers/job.py,sha256=r0KdOD55VUDw-SymC__5Mn-fzJTZE_xcBgH-O8DYVHc,21095
|
|
41
41
|
singlestoredb/fusion/handlers/models.py,sha256=xJPIG0_GgF-VrmPoIsU2U4AsS7ytDz8JMRaqchglAR0,6236
|
|
42
42
|
singlestoredb/fusion/handlers/stage.py,sha256=kYVjbPys83kf3jX6jWwN8Ju0oEocKVZ3TIOt2HiC5Ew,14287
|
|
43
43
|
singlestoredb/fusion/handlers/utils.py,sha256=mYRfGMFv2mxZVILeb_B0S55SWsb0gaye8RnjAyylbhE,10064
|
|
44
44
|
singlestoredb/fusion/handlers/workspace.py,sha256=4xN2TFO4yF7KZB2Fcht7IuvoDdAT6fDfDLjixiHZN8w,27506
|
|
45
45
|
singlestoredb/http/__init__.py,sha256=A_2ZUCCpvRYIA6YDpPy57wL5R1eZ5SfP6I1To5nfJ2s,912
|
|
46
|
-
singlestoredb/http/connection.py,sha256=
|
|
46
|
+
singlestoredb/http/connection.py,sha256=gSqlCxHbjR1745LgUugfDAXU47Uoksu3jVicYI-gO1M,39609
|
|
47
47
|
singlestoredb/magics/__init__.py,sha256=lZjkT3Webo9c1EQAzlRCRh6B2pckQH8uvNrrB__abcI,1210
|
|
48
48
|
singlestoredb/magics/run_personal.py,sha256=2f7u1T7iblxGzZurHNgNXLrPBvsvPADZKo_RD_IjYuE,1844
|
|
49
49
|
singlestoredb/magics/run_shared.py,sha256=SI8dCBRMaGn-xZU7dto4jsAqKBi-Ll14htUsMUSBpJM,1752
|
|
50
50
|
singlestoredb/management/__init__.py,sha256=ofNTPCdkZ1dS_aX2aUujd8aMHQi8Lle5Ced0aaO3RH4,269
|
|
51
51
|
singlestoredb/management/billing_usage.py,sha256=9ighjIpcopgIyJOktBYQ6pahBZmWGHOPyyCW4gu9FGs,3735
|
|
52
52
|
singlestoredb/management/cluster.py,sha256=h75grXSxq4Anr4RxwKxcZW4TkWJ4bFg_ql5iRWCNLdQ,14405
|
|
53
|
-
singlestoredb/management/export.py,sha256=
|
|
53
|
+
singlestoredb/management/export.py,sha256=jJCe25ecH_LzKSDc7vS1-5DQaWFrZipeawLPpArByJE,5108
|
|
54
54
|
singlestoredb/management/files.py,sha256=0sp3UDDHbiY5lP0QYkNgVcZ2v9zz3Kba3CeLU_xtE4Y,30575
|
|
55
55
|
singlestoredb/management/job.py,sha256=4-xLWzbE8odQogVVaFer80UEoTAZY1T28VZ9Ug4rbmM,24611
|
|
56
56
|
singlestoredb/management/manager.py,sha256=X29VEHlUEzmWvGo_bQMzo8a6d4nYMLE1CewlNBjrD7M,8851
|
|
@@ -61,7 +61,7 @@ singlestoredb/management/workspace.py,sha256=fNUiz3XNTGgXdOACsQz56Gox2qt9lOVGAtH
|
|
|
61
61
|
singlestoredb/mysql/__init__.py,sha256=olUTAvkiERhDW41JXQMawkg-i0tvBEkoTkII1tt6lxU,4492
|
|
62
62
|
singlestoredb/mysql/_auth.py,sha256=AugRitoUwgRIDFuJxuAH4MWIAmckY7Ji2pP6r_Ng9dY,8043
|
|
63
63
|
singlestoredb/mysql/charset.py,sha256=-FlONDS_oAUF5B3mIgeHBPb_SCt4zHD33arUeBNctU0,10510
|
|
64
|
-
singlestoredb/mysql/connection.py,sha256=
|
|
64
|
+
singlestoredb/mysql/connection.py,sha256=TN-_c8JSFSEnpsHNtQ_3DQyOshp-BTx2PlF8g_hDeGQ,73087
|
|
65
65
|
singlestoredb/mysql/converters.py,sha256=CVe8SDmjbIAhy1xpQ2N5OKWw6t5eWpw-EU3QTlA0Hh0,7500
|
|
66
66
|
singlestoredb/mysql/cursors.py,sha256=Eqe7jITRvOo4P_TxIarTumg_2PG1DcCfZ4Uo9IFdDa8,26794
|
|
67
67
|
singlestoredb/mysql/err.py,sha256=-m5rqXi8yhq6b8SCEJ2h0E5Rudh_15dlAU_WbJ1YrM8,2388
|
|
@@ -102,6 +102,9 @@ singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py,sh
|
|
|
102
102
|
singlestoredb/notebook/__init__.py,sha256=v0j1E3MFAtaC8wTrR-F7XY0nytUvQ4XpYhVXddv2xA0,533
|
|
103
103
|
singlestoredb/notebook/_objects.py,sha256=MkB1eowEq5SQXFHY00xAKAyyeLqHu_uaZiA20BCJPaE,8043
|
|
104
104
|
singlestoredb/notebook/_portal.py,sha256=DLerIEQmAUymtYcx8RBeuYJ4pJSy_xl1K6t1Oc-eTf8,9698
|
|
105
|
+
singlestoredb/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
106
|
+
singlestoredb/server/docker.py,sha256=r7b8tOYTGBD9NtS4_KuSDbj4bO9rarBC63BY6TdxheM,14640
|
|
107
|
+
singlestoredb/server/free_tier.py,sha256=YPtUX6idwcez9LGBaVllcTpKo8Qk2RZp3MaAZvsZcOg,8386
|
|
105
108
|
singlestoredb/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
106
109
|
singlestoredb/tests/empty.sql,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
107
110
|
singlestoredb/tests/local_infile.csv,sha256=sBtqjvfkS9aoOVx8nMXYgYv4rDuT4OuYhqUhNRu0O68,42
|
|
@@ -122,7 +125,7 @@ singlestoredb/tests/test_management.py,sha256=biqwuHfzaH5Jay1yj-nHnX7fhvLB9DPcju
|
|
|
122
125
|
singlestoredb/tests/test_plugin.py,sha256=qpO9wmWc62VaijN1sJ97YSYIX7I7Y5C6sY-WzwrutDQ,812
|
|
123
126
|
singlestoredb/tests/test_results.py,sha256=wg93sujwt-R9_eJCgSCElgAZhLDkIiAo3qPkPydOv78,6582
|
|
124
127
|
singlestoredb/tests/test_types.py,sha256=jqoAaSjhbgwB3vt0KsTcl7XBWoMMIa0mPFKhEi5bBjo,4500
|
|
125
|
-
singlestoredb/tests/test_udf.py,sha256=
|
|
128
|
+
singlestoredb/tests/test_udf.py,sha256=G6MgAzu5ZiMHmtHaGbWYXRZ-naEvwYzT5MRB900BU3I,30029
|
|
126
129
|
singlestoredb/tests/test_xdict.py,sha256=fqHspoi39nbX3fIDVkkRXcd5H50xdOsSvK0bxAMQnaE,10408
|
|
127
130
|
singlestoredb/tests/utils.py,sha256=2A2tEdD3t8aXWUnHtAIcFlWrflsz2MlMcCbUDaAG29c,4995
|
|
128
131
|
singlestoredb/tests/ext_funcs/__init__.py,sha256=qZLnDI_Ck0tguVi-K-BKXDHAcC0jui3dsm93Djj4x08,9290
|
|
@@ -137,9 +140,9 @@ singlestoredb/utils/results.py,sha256=bJtaUaDiFq26IsPAKZ2FHGB7csMn94EAxLKrP4HaEE
|
|
|
137
140
|
singlestoredb/utils/xdict.py,sha256=S9HKgrPrnu_6b7iOwa2KrW8CmU1Uqx0BWdEyogFzWbE,12896
|
|
138
141
|
sqlx/__init__.py,sha256=aBYiU8DZXCogvWu3yWafOz7bZS5WWwLZXj7oL0dXGyU,85
|
|
139
142
|
sqlx/magic.py,sha256=JsS9_9aBFaOt91Torm1JPN0c8qB2QmYJmNSKtbSQIY0,3509
|
|
140
|
-
singlestoredb-1.
|
|
141
|
-
singlestoredb-1.
|
|
142
|
-
singlestoredb-1.
|
|
143
|
-
singlestoredb-1.
|
|
144
|
-
singlestoredb-1.
|
|
145
|
-
singlestoredb-1.
|
|
143
|
+
singlestoredb-1.12.0.dist-info/LICENSE,sha256=Mlq78idURT-9G026aMYswwwnnrLcgzTLuXeAs5hjDLM,11341
|
|
144
|
+
singlestoredb-1.12.0.dist-info/METADATA,sha256=FYAe2Jnc0F4-vk4fZkPtFyMY9ufN65uUxqNDPgqVgDk,5622
|
|
145
|
+
singlestoredb-1.12.0.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
146
|
+
singlestoredb-1.12.0.dist-info/entry_points.txt,sha256=bSLaTWB5zGjpVYPAaI46MkkDup0su-eb3uAhCNYuRV0,48
|
|
147
|
+
singlestoredb-1.12.0.dist-info/top_level.txt,sha256=DfFGz7bM4XrshloiCeTABgylT3BUnS8T5pJam3ewT6Q,19
|
|
148
|
+
singlestoredb-1.12.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|