singlestoredb 1.4.0__py3-none-any.whl → 1.4.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.
Potentially problematic release.
This version of singlestoredb might be problematic. Click here for more details.
- singlestoredb/__init__.py +1 -1
- singlestoredb/connection.py +4 -0
- singlestoredb/functions/signature.py +4 -2
- singlestoredb/management/__init__.py +1 -1
- singlestoredb/management/cluster.py +4 -3
- singlestoredb/management/manager.py +1 -2
- singlestoredb/management/utils.py +68 -21
- singlestoredb/management/workspace.py +5 -4
- singlestoredb/mysql/connection.py +33 -4
- singlestoredb/notebook/__init__.py +1 -0
- singlestoredb/notebook/_portal.py +281 -0
- singlestoredb/tests/test_connection.py +24 -20
- singlestoredb/utils/events.py +49 -0
- {singlestoredb-1.4.0.dist-info → singlestoredb-1.4.1.dist-info}/METADATA +1 -1
- {singlestoredb-1.4.0.dist-info → singlestoredb-1.4.1.dist-info}/RECORD +19 -17
- {singlestoredb-1.4.0.dist-info → singlestoredb-1.4.1.dist-info}/LICENSE +0 -0
- {singlestoredb-1.4.0.dist-info → singlestoredb-1.4.1.dist-info}/WHEEL +0 -0
- {singlestoredb-1.4.0.dist-info → singlestoredb-1.4.1.dist-info}/entry_points.txt +0 -0
- {singlestoredb-1.4.0.dist-info → singlestoredb-1.4.1.dist-info}/top_level.txt +0 -0
singlestoredb/__init__.py
CHANGED
singlestoredb/connection.py
CHANGED
|
@@ -1359,6 +1359,10 @@ def connect(
|
|
|
1359
1359
|
results_type : str, optional
|
|
1360
1360
|
The form of the query results: tuples, namedtuples, dicts,
|
|
1361
1361
|
numpy, polars, pandas, arrow
|
|
1362
|
+
buffered : bool, optional
|
|
1363
|
+
Should the entire query result be buffered in memory? This is the default
|
|
1364
|
+
behavior which allows full cursor control of the result, but does consume
|
|
1365
|
+
more memory.
|
|
1362
1366
|
results_format : str, optional
|
|
1363
1367
|
Deprecated. This option has been renamed to results_type.
|
|
1364
1368
|
program_name : str, optional
|
|
@@ -45,15 +45,17 @@ if has_numpy:
|
|
|
45
45
|
np.uint8: 'uint8',
|
|
46
46
|
np.longlong: 'uint64',
|
|
47
47
|
np.ulonglong: 'uint64',
|
|
48
|
-
np.unicode_: 'str',
|
|
49
48
|
np.str_: 'str',
|
|
50
49
|
np.bytes_: 'bytes',
|
|
51
|
-
np.float_: 'float64',
|
|
52
50
|
np.float64: 'float64',
|
|
53
51
|
np.float32: 'float32',
|
|
54
52
|
np.float16: 'float16',
|
|
55
53
|
np.double: 'float64',
|
|
56
54
|
}
|
|
55
|
+
if hasattr(np, 'unicode_'):
|
|
56
|
+
numpy_type_map[np.unicode_] = 'str'
|
|
57
|
+
if hasattr(np, 'float_'):
|
|
58
|
+
numpy_type_map[np.float_] = 'float64'
|
|
57
59
|
else:
|
|
58
60
|
array_types = (Sequence,)
|
|
59
61
|
numpy_type_map = {}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
from .cluster import manage_cluster
|
|
3
|
-
from .manager import get_organization
|
|
4
3
|
from .manager import get_token
|
|
4
|
+
from .workspace import get_organization
|
|
5
5
|
from .workspace import get_secret
|
|
6
6
|
from .workspace import get_stage
|
|
7
7
|
from .workspace import manage_workspaces
|
|
@@ -8,6 +8,7 @@ from typing import List
|
|
|
8
8
|
from typing import Optional
|
|
9
9
|
from typing import Union
|
|
10
10
|
|
|
11
|
+
from .. import config
|
|
11
12
|
from .. import connection
|
|
12
13
|
from ..exceptions import ManagementError
|
|
13
14
|
from .manager import Manager
|
|
@@ -332,7 +333,7 @@ class ClusterManager(Manager):
|
|
|
332
333
|
default_version = 'v0beta'
|
|
333
334
|
|
|
334
335
|
#: Base URL if none is specified.
|
|
335
|
-
default_base_url = '
|
|
336
|
+
default_base_url = config.get_option('management.base_url')
|
|
336
337
|
|
|
337
338
|
#: Object type
|
|
338
339
|
obj_type = 'cluster'
|
|
@@ -425,8 +426,8 @@ class ClusterManager(Manager):
|
|
|
425
426
|
|
|
426
427
|
def manage_cluster(
|
|
427
428
|
access_token: Optional[str] = None,
|
|
428
|
-
version: str =
|
|
429
|
-
base_url: str =
|
|
429
|
+
version: Optional[str] = None,
|
|
430
|
+
base_url: Optional[str] = None,
|
|
430
431
|
*,
|
|
431
432
|
organization_id: Optional[str] = None,
|
|
432
433
|
) -> ClusterManager:
|
|
@@ -15,7 +15,6 @@ import requests
|
|
|
15
15
|
|
|
16
16
|
from .. import config
|
|
17
17
|
from ..exceptions import ManagementError
|
|
18
|
-
from .utils import get_organization
|
|
19
18
|
from .utils import get_token
|
|
20
19
|
|
|
21
20
|
|
|
@@ -24,7 +23,7 @@ def set_organization(kwargs: Dict[str, Any]) -> None:
|
|
|
24
23
|
if kwargs.get('params', {}).get('organizationID', None):
|
|
25
24
|
return
|
|
26
25
|
|
|
27
|
-
org =
|
|
26
|
+
org = os.environ.get('SINGLESTOREDB_ORGANIZATION')
|
|
28
27
|
if org:
|
|
29
28
|
if 'params' not in kwargs:
|
|
30
29
|
kwargs['params'] = {}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""SingleStoreDB Cluster Management."""
|
|
3
3
|
import datetime
|
|
4
4
|
import functools
|
|
5
|
+
import itertools
|
|
5
6
|
import os
|
|
6
7
|
import re
|
|
7
8
|
import sys
|
|
@@ -12,6 +13,7 @@ from typing import List
|
|
|
12
13
|
from typing import Mapping
|
|
13
14
|
from typing import Optional
|
|
14
15
|
from typing import SupportsIndex
|
|
16
|
+
from typing import Tuple
|
|
15
17
|
from typing import TypeVar
|
|
16
18
|
from typing import Union
|
|
17
19
|
from urllib.parse import urlparse
|
|
@@ -20,6 +22,7 @@ import jwt
|
|
|
20
22
|
|
|
21
23
|
from .. import converters
|
|
22
24
|
from ..config import get_option
|
|
25
|
+
from ..utils import events
|
|
23
26
|
|
|
24
27
|
JSON = Union[str, List[str], Dict[str, 'JSON']]
|
|
25
28
|
JSONObj = Dict[str, JSON]
|
|
@@ -117,6 +120,66 @@ class NamedList(List[T]):
|
|
|
117
120
|
raise
|
|
118
121
|
|
|
119
122
|
|
|
123
|
+
def _setup_authentication_info_handler() -> Callable[..., Dict[str, Any]]:
|
|
124
|
+
"""Setup authentication info event handler."""
|
|
125
|
+
|
|
126
|
+
authentication_info: List[Tuple[str, Any]] = []
|
|
127
|
+
|
|
128
|
+
def handle_authentication_info(msg: Dict[str, Any]) -> None:
|
|
129
|
+
"""Handle authentication info events."""
|
|
130
|
+
nonlocal authentication_info
|
|
131
|
+
if msg.get('name', '') != 'singlestore.portal.authentication_updated':
|
|
132
|
+
return
|
|
133
|
+
authentication_info = list(msg.get('data', {}).items())
|
|
134
|
+
|
|
135
|
+
events.subscribe(handle_authentication_info)
|
|
136
|
+
|
|
137
|
+
def handle_connection_info(msg: Dict[str, Any]) -> None:
|
|
138
|
+
"""Handle connection info events."""
|
|
139
|
+
nonlocal authentication_info
|
|
140
|
+
if msg.get('name', '') != 'singlestore.portal.connection_updated':
|
|
141
|
+
return
|
|
142
|
+
data = msg.get('data', {})
|
|
143
|
+
out = {}
|
|
144
|
+
if 'user' in data:
|
|
145
|
+
out['user'] = data['user']
|
|
146
|
+
if 'password' in data:
|
|
147
|
+
out['password'] = data['password']
|
|
148
|
+
authentication_info = list(out.items())
|
|
149
|
+
|
|
150
|
+
events.subscribe(handle_authentication_info)
|
|
151
|
+
|
|
152
|
+
def get_env() -> List[Tuple[str, Any]]:
|
|
153
|
+
conn = {}
|
|
154
|
+
url = os.environ.get('SINGLESTOREDB_URL') or get_option('host')
|
|
155
|
+
if url:
|
|
156
|
+
urlp = urlparse(url, scheme='singlestoredb', allow_fragments=True)
|
|
157
|
+
conn = dict(
|
|
158
|
+
user=urlp.username or None,
|
|
159
|
+
password=urlp.password or None,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
return [
|
|
163
|
+
x for x in dict(
|
|
164
|
+
**conn,
|
|
165
|
+
).items() if x[1] is not None
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
def get_authentication_info(include_env: bool = True) -> Dict[str, Any]:
|
|
169
|
+
"""Return authentication info from event."""
|
|
170
|
+
return dict(
|
|
171
|
+
itertools.chain(
|
|
172
|
+
(get_env() if include_env else []),
|
|
173
|
+
authentication_info,
|
|
174
|
+
),
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return get_authentication_info
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
get_authentication_info = _setup_authentication_info_handler()
|
|
181
|
+
|
|
182
|
+
|
|
120
183
|
def get_token() -> Optional[str]:
|
|
121
184
|
"""Return the token for the Management API."""
|
|
122
185
|
# See if an API key is configured
|
|
@@ -124,18 +187,11 @@ def get_token() -> Optional[str]:
|
|
|
124
187
|
if tok:
|
|
125
188
|
return tok
|
|
126
189
|
|
|
127
|
-
|
|
128
|
-
if
|
|
129
|
-
# See if the connection URL contains a JWT
|
|
130
|
-
url = get_option('host')
|
|
131
|
-
if not url:
|
|
132
|
-
return None
|
|
133
|
-
|
|
134
|
-
urlp = urlparse(url, scheme='singlestoredb', allow_fragments=True)
|
|
135
|
-
if urlp.password:
|
|
190
|
+
tok = get_authentication_info(include_env=True).get('password')
|
|
191
|
+
if tok:
|
|
136
192
|
try:
|
|
137
|
-
jwt.decode(
|
|
138
|
-
return
|
|
193
|
+
jwt.decode(tok, options={'verify_signature': False})
|
|
194
|
+
return tok
|
|
139
195
|
except jwt.DecodeError:
|
|
140
196
|
pass
|
|
141
197
|
|
|
@@ -143,15 +199,6 @@ def get_token() -> Optional[str]:
|
|
|
143
199
|
return None
|
|
144
200
|
|
|
145
201
|
|
|
146
|
-
def get_organization() -> Optional[str]:
|
|
147
|
-
"""Return the organization for the current token or environment."""
|
|
148
|
-
org = os.environ.get('SINGLESTOREDB_ORGANIZATION')
|
|
149
|
-
if org:
|
|
150
|
-
return org
|
|
151
|
-
|
|
152
|
-
return None
|
|
153
|
-
|
|
154
|
-
|
|
155
202
|
def enable_http_tracing() -> None:
|
|
156
203
|
"""Enable tracing of HTTP requests."""
|
|
157
204
|
import logging
|
|
@@ -269,7 +316,7 @@ def snake_to_camel(s: Optional[str], cap_first: bool = False) -> Optional[str]:
|
|
|
269
316
|
"""Convert snake-case to camel-case."""
|
|
270
317
|
if s is None:
|
|
271
318
|
return None
|
|
272
|
-
out = re.sub(r'_[A-Za-z]', _upper_match, s.lower())
|
|
319
|
+
out = re.sub(r'_([A-Za-z])', _upper_match, s.lower())
|
|
273
320
|
if cap_first and out:
|
|
274
321
|
return out[0].upper() + out[1:]
|
|
275
322
|
return out
|
|
@@ -17,6 +17,7 @@ from typing import Optional
|
|
|
17
17
|
from typing import TextIO
|
|
18
18
|
from typing import Union
|
|
19
19
|
|
|
20
|
+
from .. import config
|
|
20
21
|
from .. import connection
|
|
21
22
|
from ..exceptions import ManagementError
|
|
22
23
|
from .billing_usage import BillingUsageItem
|
|
@@ -1690,10 +1691,10 @@ class WorkspaceManager(Manager):
|
|
|
1690
1691
|
"""
|
|
1691
1692
|
|
|
1692
1693
|
#: Workspace management API version if none is specified.
|
|
1693
|
-
default_version = '
|
|
1694
|
+
default_version = config.get_option('management.version')
|
|
1694
1695
|
|
|
1695
1696
|
#: Base URL if none is specified.
|
|
1696
|
-
default_base_url = '
|
|
1697
|
+
default_base_url = config.get_option('management.base_url')
|
|
1697
1698
|
|
|
1698
1699
|
#: Object type
|
|
1699
1700
|
obj_type = 'workspace'
|
|
@@ -1906,8 +1907,8 @@ class WorkspaceManager(Manager):
|
|
|
1906
1907
|
|
|
1907
1908
|
def manage_workspaces(
|
|
1908
1909
|
access_token: Optional[str] = None,
|
|
1909
|
-
version: str =
|
|
1910
|
-
base_url: str =
|
|
1910
|
+
version: Optional[str] = None,
|
|
1911
|
+
base_url: Optional[str] = None,
|
|
1911
1912
|
*,
|
|
1912
1913
|
organization_id: Optional[str] = None,
|
|
1913
1914
|
) -> WorkspaceManager:
|
|
@@ -13,6 +13,8 @@ import struct
|
|
|
13
13
|
import sys
|
|
14
14
|
import traceback
|
|
15
15
|
import warnings
|
|
16
|
+
from typing import Any
|
|
17
|
+
from typing import Dict
|
|
16
18
|
from typing import Iterable
|
|
17
19
|
|
|
18
20
|
try:
|
|
@@ -21,6 +23,7 @@ except (ImportError, ModuleNotFoundError):
|
|
|
21
23
|
_singlestoredb_accel = None
|
|
22
24
|
|
|
23
25
|
from . import _auth
|
|
26
|
+
from ..utils import events
|
|
24
27
|
|
|
25
28
|
from .charset import charset_by_name, charset_by_id
|
|
26
29
|
from .constants import CLIENT, COMMAND, CR, ER, FIELD_TYPE, SERVER_STATUS
|
|
@@ -100,6 +103,19 @@ TEXT_TYPES = {
|
|
|
100
103
|
FIELD_TYPE.VAR_STRING,
|
|
101
104
|
FIELD_TYPE.VARCHAR,
|
|
102
105
|
FIELD_TYPE.GEOMETRY,
|
|
106
|
+
FIELD_TYPE.BSON,
|
|
107
|
+
FIELD_TYPE.FLOAT32_VECTOR_JSON,
|
|
108
|
+
FIELD_TYPE.FLOAT64_VECTOR_JSON,
|
|
109
|
+
FIELD_TYPE.INT8_VECTOR_JSON,
|
|
110
|
+
FIELD_TYPE.INT16_VECTOR_JSON,
|
|
111
|
+
FIELD_TYPE.INT32_VECTOR_JSON,
|
|
112
|
+
FIELD_TYPE.INT64_VECTOR_JSON,
|
|
113
|
+
FIELD_TYPE.FLOAT32_VECTOR,
|
|
114
|
+
FIELD_TYPE.FLOAT64_VECTOR,
|
|
115
|
+
FIELD_TYPE.INT8_VECTOR,
|
|
116
|
+
FIELD_TYPE.INT16_VECTOR,
|
|
117
|
+
FIELD_TYPE.INT32_VECTOR,
|
|
118
|
+
FIELD_TYPE.INT64_VECTOR,
|
|
103
119
|
}
|
|
104
120
|
|
|
105
121
|
UNSET = 'unset'
|
|
@@ -614,15 +630,22 @@ class Connection(BaseConnection):
|
|
|
614
630
|
if k not in self._connect_attrs:
|
|
615
631
|
self._connect_attrs[k] = v
|
|
616
632
|
|
|
633
|
+
self._is_committable = True
|
|
617
634
|
self._in_sync = False
|
|
618
635
|
self._track_env = bool(track_env) or self.host == 'singlestore.com'
|
|
619
636
|
self._enable_extended_data_types = enable_extended_data_types
|
|
637
|
+
self._connection_info = {}
|
|
638
|
+
events.subscribe(self._handle_event)
|
|
620
639
|
|
|
621
640
|
if defer_connect or self._track_env:
|
|
622
641
|
self._sock = None
|
|
623
642
|
else:
|
|
624
643
|
self.connect()
|
|
625
644
|
|
|
645
|
+
def _handle_event(self, data: Dict[str, Any]) -> None:
|
|
646
|
+
if data.get('name', '') == 'singlestore.portal.connection_updated':
|
|
647
|
+
self._connection_info = dict(data)
|
|
648
|
+
|
|
626
649
|
@property
|
|
627
650
|
def messages(self):
|
|
628
651
|
# TODO
|
|
@@ -766,7 +789,8 @@ class Connection(BaseConnection):
|
|
|
766
789
|
|
|
767
790
|
"""
|
|
768
791
|
log_query('COMMIT')
|
|
769
|
-
if self.host == 'singlestore.com':
|
|
792
|
+
if not self._is_committable or self.host == 'singlestore.com':
|
|
793
|
+
self._is_committable = True
|
|
770
794
|
return
|
|
771
795
|
self._execute_command(COMMAND.COM_QUERY, 'COMMIT')
|
|
772
796
|
self._read_ok_packet()
|
|
@@ -780,7 +804,8 @@ class Connection(BaseConnection):
|
|
|
780
804
|
|
|
781
805
|
"""
|
|
782
806
|
log_query('ROLLBACK')
|
|
783
|
-
if self.host == 'singlestore.com':
|
|
807
|
+
if not self._is_committable or self.host == 'singlestore.com':
|
|
808
|
+
self._is_committable = True
|
|
784
809
|
return
|
|
785
810
|
self._execute_command(COMMAND.COM_QUERY, 'ROLLBACK')
|
|
786
811
|
self._read_ok_packet()
|
|
@@ -858,9 +883,11 @@ class Connection(BaseConnection):
|
|
|
858
883
|
# print("DEBUG: sending query:", sql)
|
|
859
884
|
handler = fusion.get_handler(sql)
|
|
860
885
|
if handler is not None:
|
|
886
|
+
self._is_committable = False
|
|
861
887
|
self._result = fusion.execute(self, sql, handler=handler)
|
|
862
888
|
self._affected_rows = self._result.affected_rows
|
|
863
889
|
else:
|
|
890
|
+
self._is_committable = True
|
|
864
891
|
if isinstance(sql, str):
|
|
865
892
|
sql = sql.encode(self.encoding, 'surrogateescape')
|
|
866
893
|
self._local_infile_stream = infile_stream
|
|
@@ -973,9 +1000,11 @@ class Connection(BaseConnection):
|
|
|
973
1000
|
if not self._track_env:
|
|
974
1001
|
return
|
|
975
1002
|
|
|
976
|
-
url =
|
|
1003
|
+
url = self._connection_info.get('connection_url')
|
|
977
1004
|
if not url:
|
|
978
|
-
|
|
1005
|
+
url = os.environ.get('SINGLESTOREDB_URL')
|
|
1006
|
+
if not url:
|
|
1007
|
+
return
|
|
979
1008
|
|
|
980
1009
|
out = {}
|
|
981
1010
|
urlp = connection._parse_url(url)
|
|
@@ -7,6 +7,7 @@ from ._objects import secrets # noqa: F401
|
|
|
7
7
|
from ._objects import stage # noqa: F401
|
|
8
8
|
from ._objects import workspace # noqa: F401
|
|
9
9
|
from ._objects import workspace_group # noqa: F401
|
|
10
|
+
from ._portal import portal # noqa: F401
|
|
10
11
|
|
|
11
12
|
if 'SINGLESTOREDB_ORGANIZATION' not in _os.environ:
|
|
12
13
|
_warnings.warn(
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import time
|
|
6
|
+
import urllib.parse
|
|
7
|
+
from typing import Any
|
|
8
|
+
from typing import Callable
|
|
9
|
+
from typing import Dict
|
|
10
|
+
from typing import List
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
from . import _objects as obj
|
|
14
|
+
from ..management import workspace as mgr
|
|
15
|
+
from ..utils import events
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
from IPython import display
|
|
19
|
+
has_ipython = True
|
|
20
|
+
except ImportError:
|
|
21
|
+
has_ipython = False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Portal(object):
|
|
25
|
+
"""SingleStore Portal information."""
|
|
26
|
+
|
|
27
|
+
def __init__(self) -> None:
|
|
28
|
+
self._connection_info: Dict[str, Any] = {}
|
|
29
|
+
self._authentication_info: Dict[str, Any] = {}
|
|
30
|
+
self._theme_info: Dict[str, Any] = {}
|
|
31
|
+
events.subscribe(self._request)
|
|
32
|
+
|
|
33
|
+
def __str__(self) -> str:
|
|
34
|
+
attrs = []
|
|
35
|
+
for name in [
|
|
36
|
+
'organization_id', 'workspace_group_id', 'workspace_id',
|
|
37
|
+
'host', 'port', 'user', 'password', 'default_database',
|
|
38
|
+
]:
|
|
39
|
+
if name == 'password':
|
|
40
|
+
if self.password is not None:
|
|
41
|
+
attrs.append("password='***'")
|
|
42
|
+
else:
|
|
43
|
+
attrs.append('password=None')
|
|
44
|
+
else:
|
|
45
|
+
attrs.append(f'{name}={getattr(self, name)!r}')
|
|
46
|
+
return f'{type(self).__name__}({", ".join(attrs)})'
|
|
47
|
+
|
|
48
|
+
def __repr__(self) -> str:
|
|
49
|
+
return str(self)
|
|
50
|
+
|
|
51
|
+
def _call_javascript(
|
|
52
|
+
self,
|
|
53
|
+
func: str,
|
|
54
|
+
args: Optional[List[Any]] = None,
|
|
55
|
+
wait_on_condition: Optional[Callable[[], bool]] = None,
|
|
56
|
+
timeout_message: str = 'timed out waiting on condition',
|
|
57
|
+
wait_interval: float = 0.2,
|
|
58
|
+
timeout: float = 5.0,
|
|
59
|
+
) -> None:
|
|
60
|
+
if not has_ipython or not func:
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
if not re.match(r'^[A-Z_][\w\._]*$', func, flags=re.I):
|
|
64
|
+
raise ValueError(f'function name is not valid: {func}')
|
|
65
|
+
|
|
66
|
+
args = args if args else []
|
|
67
|
+
|
|
68
|
+
code = f'''
|
|
69
|
+
if (window.singlestore && window.singlestore.portal) {{
|
|
70
|
+
window.singlestore.portal.{func}.apply(
|
|
71
|
+
window,
|
|
72
|
+
JSON.parse({repr(json.dumps(args))})
|
|
73
|
+
)
|
|
74
|
+
}}
|
|
75
|
+
'''
|
|
76
|
+
|
|
77
|
+
display.display(display.Javascript(code))
|
|
78
|
+
|
|
79
|
+
if wait_on_condition is not None:
|
|
80
|
+
elapsed = 0.0
|
|
81
|
+
while True:
|
|
82
|
+
if wait_on_condition():
|
|
83
|
+
break
|
|
84
|
+
if elapsed > timeout:
|
|
85
|
+
raise RuntimeError(timeout_message)
|
|
86
|
+
time.sleep(wait_interval)
|
|
87
|
+
elapsed += wait_interval
|
|
88
|
+
|
|
89
|
+
def _request(self, msg: Dict[str, Any]) -> None:
|
|
90
|
+
"""Handle request on the control stream."""
|
|
91
|
+
func = getattr(self, '_handle_' + msg.get('name', 'unknown').split('.')[-1])
|
|
92
|
+
if func is not None:
|
|
93
|
+
func(msg.get('data', {}))
|
|
94
|
+
|
|
95
|
+
def _handle_connection_updated(self, data: Dict[str, Any]) -> None:
|
|
96
|
+
"""Handle connection_updated event."""
|
|
97
|
+
self._connection_info = dict(data)
|
|
98
|
+
|
|
99
|
+
def _handle_authentication_updated(self, data: Dict[str, Any]) -> None:
|
|
100
|
+
"""Handle authentication_updated event."""
|
|
101
|
+
self._authentication_info = dict(data)
|
|
102
|
+
|
|
103
|
+
def _handle_theme_updated(self, data: Dict[str, Any]) -> None:
|
|
104
|
+
"""Handle theme_updated event."""
|
|
105
|
+
self._theme_info = dict(data)
|
|
106
|
+
|
|
107
|
+
def _handle_unknown(self, data: Dict[str, Any]) -> None:
|
|
108
|
+
"""Handle unknown events."""
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def organization_id(self) -> Optional[str]:
|
|
113
|
+
"""Organization ID."""
|
|
114
|
+
try:
|
|
115
|
+
return self._connection_info['organization']
|
|
116
|
+
except KeyError:
|
|
117
|
+
return os.environ.get('SINGLESTOREDB_ORGANIZATION')
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def organization(self) -> obj.Organization:
|
|
121
|
+
"""Organization."""
|
|
122
|
+
return obj.organization
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def stage(self) -> obj.Stage:
|
|
126
|
+
"""Stage."""
|
|
127
|
+
return obj.stage
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def secrets(self) -> obj.Secrets:
|
|
131
|
+
"""Secrets."""
|
|
132
|
+
return obj.secrets
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def workspace_group_id(self) -> Optional[str]:
|
|
136
|
+
"""Workspace Group ID."""
|
|
137
|
+
try:
|
|
138
|
+
return self._connection_info['workspace_group']
|
|
139
|
+
except KeyError:
|
|
140
|
+
return os.environ.get('SINGLESTOREDB_WORKSPACE_GROUP')
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def workspace_group(self) -> obj.WorkspaceGroup:
|
|
144
|
+
"""Workspace group."""
|
|
145
|
+
return obj.workspace_group
|
|
146
|
+
|
|
147
|
+
@workspace_group.setter
|
|
148
|
+
def workspace_group(self) -> None:
|
|
149
|
+
"""Set workspace group."""
|
|
150
|
+
raise AttributeError(
|
|
151
|
+
'workspace group can not be set explictly; ' +
|
|
152
|
+
'you can only set a workspace',
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def workspace_id(self) -> Optional[str]:
|
|
157
|
+
"""Workspace ID."""
|
|
158
|
+
try:
|
|
159
|
+
return self._connection_info['workspace']
|
|
160
|
+
except KeyError:
|
|
161
|
+
return os.environ.get('SINGLESTOREDB_WORKSPACE')
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def workspace(self) -> obj.Workspace:
|
|
165
|
+
"""Workspace."""
|
|
166
|
+
return obj.workspace
|
|
167
|
+
|
|
168
|
+
@workspace.setter
|
|
169
|
+
def workspace(self, name_or_id: str) -> None:
|
|
170
|
+
"""Set workspace."""
|
|
171
|
+
if re.match(
|
|
172
|
+
r'[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}',
|
|
173
|
+
name_or_id, flags=re.I,
|
|
174
|
+
):
|
|
175
|
+
w = mgr.get_workspace(name_or_id)
|
|
176
|
+
else:
|
|
177
|
+
w = mgr.get_workspace_group(self.workspace_group_id).workspaces[name_or_id]
|
|
178
|
+
|
|
179
|
+
if w.state and w.state.lower() not in ['active', 'resumed']:
|
|
180
|
+
raise RuntimeError('workspace is not active')
|
|
181
|
+
|
|
182
|
+
id = w.id
|
|
183
|
+
|
|
184
|
+
self._call_javascript(
|
|
185
|
+
'changeWorkspace', [id],
|
|
186
|
+
wait_on_condition=lambda: self.workspace_id == id, # type: ignore
|
|
187
|
+
timeout_message='timeout waiting for workspace update',
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def cluster_id(self) -> Optional[str]:
|
|
192
|
+
"""Cluster ID."""
|
|
193
|
+
try:
|
|
194
|
+
return self._connection_info['cluster']
|
|
195
|
+
except KeyError:
|
|
196
|
+
return os.environ.get('SINGLESTOREDB_CLUSTER')
|
|
197
|
+
|
|
198
|
+
def _parse_url(self) -> Dict[str, Any]:
|
|
199
|
+
url = urllib.parse.urlparse(
|
|
200
|
+
os.environ.get('SINGLESTOREDB_URL', ''),
|
|
201
|
+
)
|
|
202
|
+
return dict(
|
|
203
|
+
host=url.hostname or None,
|
|
204
|
+
port=url.port or None,
|
|
205
|
+
user=url.username or None,
|
|
206
|
+
password=url.password or None,
|
|
207
|
+
default_database=url.path.split('/')[-1] or None,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
@property
|
|
211
|
+
def connection_url(self) -> Optional[str]:
|
|
212
|
+
"""Connection URL."""
|
|
213
|
+
try:
|
|
214
|
+
return self._connection_info['connection_url']
|
|
215
|
+
except KeyError:
|
|
216
|
+
return os.environ.get('SINGLESTOREDB_URL')
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def connection_url_kai(self) -> Optional[str]:
|
|
220
|
+
"""Kai connectionURL."""
|
|
221
|
+
try:
|
|
222
|
+
return self._connection_info.get('connection_url_kai')
|
|
223
|
+
except KeyError:
|
|
224
|
+
return os.environ.get('SINGLESTOREDB_URL_KAI')
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def host(self) -> Optional[str]:
|
|
228
|
+
"""Hostname."""
|
|
229
|
+
try:
|
|
230
|
+
return self._connection_info['host']
|
|
231
|
+
except KeyError:
|
|
232
|
+
return self._parse_url()['host']
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def port(self) -> Optional[int]:
|
|
236
|
+
"""Database server port."""
|
|
237
|
+
try:
|
|
238
|
+
return self._connection_info['port']
|
|
239
|
+
except KeyError:
|
|
240
|
+
return self._parse_url()['port']
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def user(self) -> Optional[str]:
|
|
244
|
+
"""Username."""
|
|
245
|
+
try:
|
|
246
|
+
return self._authentication_info['user']
|
|
247
|
+
except KeyError:
|
|
248
|
+
return self._parse_url()['user']
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def password(self) -> Optional[str]:
|
|
252
|
+
"""Password."""
|
|
253
|
+
try:
|
|
254
|
+
return self._authentication_info['password']
|
|
255
|
+
except KeyError:
|
|
256
|
+
return self._parse_url()['password']
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
def default_database(self) -> Optional[str]:
|
|
260
|
+
"""Default database."""
|
|
261
|
+
try:
|
|
262
|
+
return self._connection_info['default_database']
|
|
263
|
+
except KeyError:
|
|
264
|
+
return self._parse_url()['default_database']
|
|
265
|
+
|
|
266
|
+
@default_database.setter
|
|
267
|
+
def default_database(self, name: str) -> None:
|
|
268
|
+
"""Set default database."""
|
|
269
|
+
self._call_javascript(
|
|
270
|
+
'changeDefaultDatabase', [name],
|
|
271
|
+
wait_on_condition=lambda: self.default_database == name, # type: ignore
|
|
272
|
+
timeout_message='timeout waiting for database update',
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def version(self) -> Optional[str]:
|
|
277
|
+
"""Version."""
|
|
278
|
+
return self._connection_info.get('version')
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
portal = Portal()
|
|
@@ -1849,8 +1849,6 @@ class TestConnection(unittest.TestCase):
|
|
|
1849
1849
|
|
|
1850
1850
|
bits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
1851
1851
|
|
|
1852
|
-
print(row)
|
|
1853
|
-
|
|
1854
1852
|
assert row['id'] == 0, row['id']
|
|
1855
1853
|
assert row['tinyint'] == 80, row['tinyint']
|
|
1856
1854
|
assert row['unsigned_tinyint'] == 85, row['unsigned_tinyint']
|
|
@@ -2888,9 +2886,10 @@ class TestConnection(unittest.TestCase):
|
|
|
2888
2886
|
self.cur.execute('select a from f32_vectors order by id')
|
|
2889
2887
|
out = list(self.cur)
|
|
2890
2888
|
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2889
|
+
if hasattr(out[0][0], 'dtype'):
|
|
2890
|
+
assert out[0][0].dtype is np.dtype('float32')
|
|
2891
|
+
assert out[1][0].dtype is np.dtype('float32')
|
|
2892
|
+
assert out[2][0].dtype is np.dtype('float32')
|
|
2894
2893
|
|
|
2895
2894
|
np.testing.assert_array_equal(
|
|
2896
2895
|
out[0][0],
|
|
@@ -2917,9 +2916,10 @@ class TestConnection(unittest.TestCase):
|
|
|
2917
2916
|
self.cur.execute('select a from f64_vectors order by id')
|
|
2918
2917
|
out = list(self.cur)
|
|
2919
2918
|
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2919
|
+
if hasattr(out[0][0], 'dtype'):
|
|
2920
|
+
assert out[0][0].dtype is np.dtype('float64')
|
|
2921
|
+
assert out[1][0].dtype is np.dtype('float64')
|
|
2922
|
+
assert out[2][0].dtype is np.dtype('float64')
|
|
2923
2923
|
|
|
2924
2924
|
np.testing.assert_array_equal(
|
|
2925
2925
|
out[0][0],
|
|
@@ -2946,9 +2946,10 @@ class TestConnection(unittest.TestCase):
|
|
|
2946
2946
|
self.cur.execute('select a from i8_vectors order by id')
|
|
2947
2947
|
out = list(self.cur)
|
|
2948
2948
|
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2949
|
+
if hasattr(out[0][0], 'dtype'):
|
|
2950
|
+
assert out[0][0].dtype is np.dtype('int8')
|
|
2951
|
+
assert out[1][0].dtype is np.dtype('int8')
|
|
2952
|
+
assert out[2][0].dtype is np.dtype('int8')
|
|
2952
2953
|
|
|
2953
2954
|
np.testing.assert_array_equal(
|
|
2954
2955
|
out[0][0],
|
|
@@ -2975,9 +2976,10 @@ class TestConnection(unittest.TestCase):
|
|
|
2975
2976
|
self.cur.execute('select a from i16_vectors order by id')
|
|
2976
2977
|
out = list(self.cur)
|
|
2977
2978
|
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2979
|
+
if hasattr(out[0][0], 'dtype'):
|
|
2980
|
+
assert out[0][0].dtype is np.dtype('int16')
|
|
2981
|
+
assert out[1][0].dtype is np.dtype('int16')
|
|
2982
|
+
assert out[2][0].dtype is np.dtype('int16')
|
|
2981
2983
|
|
|
2982
2984
|
np.testing.assert_array_equal(
|
|
2983
2985
|
out[0][0],
|
|
@@ -3004,9 +3006,10 @@ class TestConnection(unittest.TestCase):
|
|
|
3004
3006
|
self.cur.execute('select a from i32_vectors order by id')
|
|
3005
3007
|
out = list(self.cur)
|
|
3006
3008
|
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3009
|
+
if hasattr(out[0][0], 'dtype'):
|
|
3010
|
+
assert out[0][0].dtype is np.dtype('int32')
|
|
3011
|
+
assert out[1][0].dtype is np.dtype('int32')
|
|
3012
|
+
assert out[2][0].dtype is np.dtype('int32')
|
|
3010
3013
|
|
|
3011
3014
|
np.testing.assert_array_equal(
|
|
3012
3015
|
out[0][0],
|
|
@@ -3033,9 +3036,10 @@ class TestConnection(unittest.TestCase):
|
|
|
3033
3036
|
self.cur.execute('select a from i64_vectors order by id')
|
|
3034
3037
|
out = list(self.cur)
|
|
3035
3038
|
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
+
if hasattr(out[0][0], 'dtype'):
|
|
3040
|
+
assert out[0][0].dtype is np.dtype('int64')
|
|
3041
|
+
assert out[1][0].dtype is np.dtype('int64')
|
|
3042
|
+
assert out[2][0].dtype is np.dtype('int64')
|
|
3039
3043
|
|
|
3040
3044
|
np.testing.assert_array_equal(
|
|
3041
3045
|
out[0][0],
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import Callable
|
|
4
|
+
from typing import Dict
|
|
5
|
+
from typing import Set
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from IPython import get_ipython
|
|
9
|
+
has_ipython = True
|
|
10
|
+
except ImportError:
|
|
11
|
+
has_ipython = False
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_subscribers: Set[Callable[[Dict[str, Any]], None]] = set()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def subscribe(func: Callable[[Dict[str, Any]], None]) -> None:
|
|
18
|
+
"""
|
|
19
|
+
Subscribe to SingleStore portal events.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
func : Callable
|
|
24
|
+
The function to call when an event is received
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
_subscribers.add(func)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _event_handler(stream: Any, ident: Any, msg: Dict[str, Any]) -> None:
|
|
31
|
+
"""Handle request on the control stream."""
|
|
32
|
+
if not _subscribers or not isinstance(msg, dict):
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
content = msg.get('content', {})
|
|
36
|
+
if content.get('type', '') != 'event':
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
for func in _subscribers:
|
|
40
|
+
func(content)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# Inject a control handler to receive SingleStore events
|
|
44
|
+
if has_ipython:
|
|
45
|
+
try:
|
|
46
|
+
_handlers = get_ipython().kernel.control_handlers
|
|
47
|
+
_handlers['singlestore_portal_request'] = _event_handler
|
|
48
|
+
except AttributeError:
|
|
49
|
+
pass
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
singlestoredb/__init__.py,sha256=
|
|
1
|
+
singlestoredb/__init__.py,sha256=P2EmifYW3g7dPP3gIrZyeec6uJpf9rZUbYwUeW_YGTE,1634
|
|
2
2
|
singlestoredb/auth.py,sha256=u8D9tpKzrqa4ssaHjyZnGDX1q8XBpGtuoOkTkSv7B28,7599
|
|
3
3
|
singlestoredb/config.py,sha256=H4pQxqBEGGCmVHg40VEnAdqGXHun8ougZzj-Ed6ZLH4,11822
|
|
4
|
-
singlestoredb/connection.py,sha256=
|
|
4
|
+
singlestoredb/connection.py,sha256=WL_TSSHhhjLV0pnJOtaeMAf0o1DI-PJv9xnLFf_cM08,45173
|
|
5
5
|
singlestoredb/converters.py,sha256=t1hRMZfccWJs_WyOw-W-Kh87fxsOkpOnKXAeh_Nr-zU,20681
|
|
6
6
|
singlestoredb/exceptions.py,sha256=HuoA6sMRL5qiCiee-_5ddTGmFbYC9Euk8TYUsh5GvTw,3234
|
|
7
7
|
singlestoredb/pytest.py,sha256=OyF3BO9mgxenifYhOihnzGk8WzCJ_zN5_mxe8XyFPOc,9074
|
|
@@ -12,7 +12,7 @@ singlestoredb/alchemy/__init__.py,sha256=dXRThusYrs_9GjrhPOw0-vw94in_T8yY9jE7SGC
|
|
|
12
12
|
singlestoredb/functions/__init__.py,sha256=WL1LqgMTdnGOse3tQqmD-HH8TdfCPS89GNO7hO0v_aw,41
|
|
13
13
|
singlestoredb/functions/decorator.py,sha256=H12MUeBw8VOppx6esntaR43ukeIffbnAr716CBpYJ4g,5193
|
|
14
14
|
singlestoredb/functions/dtypes.py,sha256=a2vevIug8NhiUCFiSOKwRPpdWU69Gn13ZoQ6Aovskhc,31408
|
|
15
|
-
singlestoredb/functions/signature.py,sha256=
|
|
15
|
+
singlestoredb/functions/signature.py,sha256=1CRtE_Dp47ahYoPzB8oCVNS_gmEQz91xDH8FEKqWGL8,18960
|
|
16
16
|
singlestoredb/functions/ext/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
|
|
17
17
|
singlestoredb/functions/ext/arrow.py,sha256=WB7n1ACslyd8nlbFzUvlbxn1BVuEjA9-BGBEqCWlSOo,9061
|
|
18
18
|
singlestoredb/functions/ext/asgi.py,sha256=YV4i5RmnSsPvdJPM7_z9X3oR9b1zdZq2ylTSEAM_G54,40017
|
|
@@ -31,18 +31,18 @@ singlestoredb/fusion/handlers/utils.py,sha256=oYbf13Y3orEkJfHMNnO7B_W1anEdK-0S9v
|
|
|
31
31
|
singlestoredb/fusion/handlers/workspace.py,sha256=EGxu-dAWNfHsknMNSk1n9cri_zhlMJap4ypywPFiMZQ,25000
|
|
32
32
|
singlestoredb/http/__init__.py,sha256=A_2ZUCCpvRYIA6YDpPy57wL5R1eZ5SfP6I1To5nfJ2s,912
|
|
33
33
|
singlestoredb/http/connection.py,sha256=HUYzgiGYRUblHhgDi-ghfXykGkdB9iQ3i_XVvhtqH88,39349
|
|
34
|
-
singlestoredb/management/__init__.py,sha256=
|
|
34
|
+
singlestoredb/management/__init__.py,sha256=mhWXjLhp5-t8dhl0vl7SjayKrvJlDb5_hl1YWvDgiMA,237
|
|
35
35
|
singlestoredb/management/billing_usage.py,sha256=9ighjIpcopgIyJOktBYQ6pahBZmWGHOPyyCW4gu9FGs,3735
|
|
36
|
-
singlestoredb/management/cluster.py,sha256=
|
|
37
|
-
singlestoredb/management/manager.py,sha256=
|
|
36
|
+
singlestoredb/management/cluster.py,sha256=i23Smr1PBrDZ8NO_VPd_-bEYkyHvVe9CCRGUjHn_1yQ,14362
|
|
37
|
+
singlestoredb/management/manager.py,sha256=sFP1vZGS8WpN8E0XLu1N7Mxtq6Sixalln44HlTQEyXI,8800
|
|
38
38
|
singlestoredb/management/organization.py,sha256=Y0JFSxYF_UOjip53gcbBXWPCe_t92zo3d99jZNrhkx4,4995
|
|
39
39
|
singlestoredb/management/region.py,sha256=HnLcWUh7r_aLECliplCDHak4a_F3B7LOSXEYMW66qD0,1611
|
|
40
|
-
singlestoredb/management/utils.py,sha256=
|
|
41
|
-
singlestoredb/management/workspace.py,sha256=
|
|
40
|
+
singlestoredb/management/utils.py,sha256=nTsGTDgl8lmjwcfl2nMS6feRn5P-jUjHlkVGzG5qrXM,10783
|
|
41
|
+
singlestoredb/management/workspace.py,sha256=9oamNIaE5vLZNAlpl5SK-xu27qPqx2Ff3ZIdKckNfmc,61673
|
|
42
42
|
singlestoredb/mysql/__init__.py,sha256=olUTAvkiERhDW41JXQMawkg-i0tvBEkoTkII1tt6lxU,4492
|
|
43
43
|
singlestoredb/mysql/_auth.py,sha256=AugRitoUwgRIDFuJxuAH4MWIAmckY7Ji2pP6r_Ng9dY,8043
|
|
44
44
|
singlestoredb/mysql/charset.py,sha256=-FlONDS_oAUF5B3mIgeHBPb_SCt4zHD33arUeBNctU0,10510
|
|
45
|
-
singlestoredb/mysql/connection.py,sha256=
|
|
45
|
+
singlestoredb/mysql/connection.py,sha256=Z3xJ-yFY4yc-rMGp2ty7V2NZ6Ixb74UfnlwLcypJ7d4,71446
|
|
46
46
|
singlestoredb/mysql/converters.py,sha256=CVe8SDmjbIAhy1xpQ2N5OKWw6t5eWpw-EU3QTlA0Hh0,7500
|
|
47
47
|
singlestoredb/mysql/cursors.py,sha256=Eqe7jITRvOo4P_TxIarTumg_2PG1DcCfZ4Uo9IFdDa8,26794
|
|
48
48
|
singlestoredb/mysql/err.py,sha256=-m5rqXi8yhq6b8SCEJ2h0E5Rudh_15dlAU_WbJ1YrM8,2388
|
|
@@ -80,8 +80,9 @@ singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py,sha256=E5_jnyZEZ7_m
|
|
|
80
80
|
singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py,sha256=szE4Zodgf7YwhkMBOrCvUwhTWppVtaodsqlV-vJ7fmY,3090
|
|
81
81
|
singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py,sha256=t_OzqsVnj_ReBbmY_wx51ZcWbLz9nASZ0hno-9YeiyQ,8022
|
|
82
82
|
singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py,sha256=pl0bvuZo_nzAlYOINxRiR-Zi9khz0W2Pc7vP-K3sQYQ,2819
|
|
83
|
-
singlestoredb/notebook/__init__.py,sha256=
|
|
83
|
+
singlestoredb/notebook/__init__.py,sha256=v0j1E3MFAtaC8wTrR-F7XY0nytUvQ4XpYhVXddv2xA0,533
|
|
84
84
|
singlestoredb/notebook/_objects.py,sha256=MkB1eowEq5SQXFHY00xAKAyyeLqHu_uaZiA20BCJPaE,8043
|
|
85
|
+
singlestoredb/notebook/_portal.py,sha256=a0UeRwXQl-tBEfV_IOOL_UK2Zzrs-RgGswvjJiZk8Wc,8485
|
|
85
86
|
singlestoredb/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
86
87
|
singlestoredb/tests/empty.sql,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
87
88
|
singlestoredb/tests/local_infile.csv,sha256=sBtqjvfkS9aoOVx8nMXYgYv4rDuT4OuYhqUhNRu0O68,42
|
|
@@ -89,7 +90,7 @@ singlestoredb/tests/test.sql,sha256=dfMehVCQ9wObSVTQKyQi-fRFDZeqRxV4Cj8doBCPEFM,
|
|
|
89
90
|
singlestoredb/tests/test2.sql,sha256=D4U2GSlOVeo39U8-RMM4YziJzYFfi4Ztm2YXJVJVAS8,37
|
|
90
91
|
singlestoredb/tests/test_basics.py,sha256=rUfUGZ54xybvgp11XYWdqnUYMKa6VckB3XkX9LFnxRw,44180
|
|
91
92
|
singlestoredb/tests/test_config.py,sha256=63lyIQ2KrvGE6C9403B_4Mc90mX4tp42ys5Bih2sXrE,11184
|
|
92
|
-
singlestoredb/tests/test_connection.py,sha256=
|
|
93
|
+
singlestoredb/tests/test_connection.py,sha256=ZmhnECusipQAuc6bfZOfMMZULrtxUhnxjxNNSSi6xH4,117697
|
|
93
94
|
singlestoredb/tests/test_dbapi.py,sha256=IKq5Hcwx8WikASP8_AB5fo3TXv7ryWPCVGonoly00gI,652
|
|
94
95
|
singlestoredb/tests/test_exceptions.py,sha256=tfr_8X2w1UmG4nkSBzWGB0C7ehrf1GAVgj6_ODaG-TM,1131
|
|
95
96
|
singlestoredb/tests/test_ext_func.py,sha256=OWd-CJ1Owhx72nikSWWEF2EQFCJk7vEXZM2Oy9EbYQo,37357
|
|
@@ -109,12 +110,13 @@ singlestoredb/utils/config.py,sha256=m3Xn6hsbdKyLufSnbokhFJ9Vfaz9Qpkj1IEnIiH9oJQ
|
|
|
109
110
|
singlestoredb/utils/convert_rows.py,sha256=A6up7a8Bq-eV2BXdGCotQviqp1Q7XdJ2MA9339hLYVQ,1816
|
|
110
111
|
singlestoredb/utils/debug.py,sha256=0JiLA37u_9CKiDGiN9BK_PtFMUku3vIcNjERWaTNRSU,349
|
|
111
112
|
singlestoredb/utils/dtypes.py,sha256=1qUiB4BJFJ7rOVh2mItQssYbJupV7uq1x8uwX-Eu2Ks,5898
|
|
113
|
+
singlestoredb/utils/events.py,sha256=9IB84T3pKQjs7aaoSSJCw7soNngnhoTDWIC52M51R9Y,1139
|
|
112
114
|
singlestoredb/utils/mogrify.py,sha256=-a56IF70U6CkfadeaZgfjRSVsAD3PuqRrzPpjZlgbwY,4050
|
|
113
115
|
singlestoredb/utils/results.py,sha256=bJtaUaDiFq26IsPAKZ2FHGB7csMn94EAxLKrP4HaEEA,15277
|
|
114
116
|
singlestoredb/utils/xdict.py,sha256=S9HKgrPrnu_6b7iOwa2KrW8CmU1Uqx0BWdEyogFzWbE,12896
|
|
115
|
-
singlestoredb-1.4.
|
|
116
|
-
singlestoredb-1.4.
|
|
117
|
-
singlestoredb-1.4.
|
|
118
|
-
singlestoredb-1.4.
|
|
119
|
-
singlestoredb-1.4.
|
|
120
|
-
singlestoredb-1.4.
|
|
117
|
+
singlestoredb-1.4.1.dist-info/LICENSE,sha256=Mlq78idURT-9G026aMYswwwnnrLcgzTLuXeAs5hjDLM,11341
|
|
118
|
+
singlestoredb-1.4.1.dist-info/METADATA,sha256=e3LgU-lYTxOTjgFy24CcG69A9Vvq6Ke5YV0bV0oT2XA,5570
|
|
119
|
+
singlestoredb-1.4.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
120
|
+
singlestoredb-1.4.1.dist-info/entry_points.txt,sha256=bSLaTWB5zGjpVYPAaI46MkkDup0su-eb3uAhCNYuRV0,48
|
|
121
|
+
singlestoredb-1.4.1.dist-info/top_level.txt,sha256=eet8bVPNRqiGeY0PrO5ERH2UpamwlrKHEQCffz4dOh8,14
|
|
122
|
+
singlestoredb-1.4.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|