singlestoredb 1.15.4__cp38-abi3-macosx_10_9_universal2.whl → 1.15.5__cp38-abi3-macosx_10_9_universal2.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.

Binary file
singlestoredb/__init__.py CHANGED
@@ -13,7 +13,7 @@ Examples
13
13
 
14
14
  """
15
15
 
16
- __version__ = '1.15.4'
16
+ __version__ = '1.15.5'
17
17
 
18
18
  from typing import Any
19
19
 
@@ -708,8 +708,22 @@ class Application(object):
708
708
  # Error response start
709
709
  error_response_dict: Dict[str, Any] = dict(
710
710
  type='http.response.start',
711
- status=401,
712
- headers=[(b'content-type', b'text/plain')],
711
+ status=500,
712
+ headers=[(b'content-type', b'application/json')],
713
+ )
714
+
715
+ # Timeout response start
716
+ timeout_response_dict: Dict[str, Any] = dict(
717
+ type='http.response.start',
718
+ status=504,
719
+ headers=[(b'content-type', b'application/json')],
720
+ )
721
+
722
+ # Cancel response start
723
+ cancel_response_dict: Dict[str, Any] = dict(
724
+ type='http.response.start',
725
+ status=503,
726
+ headers=[(b'content-type', b'application/json')],
713
727
  )
714
728
 
715
729
  # JSON response start
@@ -1233,12 +1247,14 @@ class Application(object):
1233
1247
  'timeout': func_info['timeout'],
1234
1248
  },
1235
1249
  )
1236
- body = (
1237
- '[TimeoutError] Function call timed out after ' +
1238
- str(func_info['timeout']) +
1239
- ' seconds'
1250
+ body = json.dumps(
1251
+ dict(
1252
+ error='[TimeoutError] Function call timed out after ' +
1253
+ str(func_info['timeout']) +
1254
+ ' seconds',
1255
+ ),
1240
1256
  ).encode('utf-8')
1241
- await send(self.error_response_dict)
1257
+ await send(self.timeout_response_dict)
1242
1258
 
1243
1259
  except asyncio.CancelledError:
1244
1260
  self.logger.exception(
@@ -1249,8 +1265,12 @@ class Application(object):
1249
1265
  'function_name': func_name.decode('utf-8'),
1250
1266
  },
1251
1267
  )
1252
- body = b'[CancelledError] Function call was cancelled'
1253
- await send(self.error_response_dict)
1268
+ body = json.dumps(
1269
+ dict(
1270
+ error='[CancelledError] Function call was cancelled',
1271
+ ),
1272
+ ).encode('utf-8')
1273
+ await send(self.cancel_response_dict)
1254
1274
 
1255
1275
  except Exception as e:
1256
1276
  self.logger.exception(
@@ -1262,7 +1282,11 @@ class Application(object):
1262
1282
  'exception_type': type(e).__name__,
1263
1283
  },
1264
1284
  )
1265
- body = f'[{type(e).__name__}] {str(e).strip()}'.encode('utf-8')
1285
+ body = json.dumps(
1286
+ dict(
1287
+ error=f'[{type(e).__name__}] {str(e).strip()}',
1288
+ ),
1289
+ ).encode('utf-8')
1266
1290
  await send(self.error_response_dict)
1267
1291
 
1268
1292
  finally:
@@ -15,7 +15,7 @@ from .utils import get_workspace_manager
15
15
 
16
16
  class UseWorkspaceHandler(SQLHandler):
17
17
  """
18
- USE WORKSPACE workspace [ with_database ];
18
+ USE WORKSPACE workspace [ in_group ] [ with_database ];
19
19
 
20
20
  # Workspace
21
21
  workspace = { workspace_id | workspace_name | current_workspace }
@@ -29,6 +29,15 @@ class UseWorkspaceHandler(SQLHandler):
29
29
  # Current workspace
30
30
  current_workspace = @@CURRENT
31
31
 
32
+ # Workspace group specification
33
+ in_group = IN GROUP { group_id | group_name }
34
+
35
+ # ID of workspace group
36
+ group_id = ID '<group-id>'
37
+
38
+ # Name of workspace group
39
+ group_name = '<group-name>'
40
+
32
41
  # Name of database
33
42
  with_database = WITH DATABASE 'database-name'
34
43
 
@@ -38,13 +47,18 @@ class UseWorkspaceHandler(SQLHandler):
38
47
 
39
48
  Arguments
40
49
  ---------
41
- * ``<workspace-id>``: The ID of the workspace to delete.
42
- * ``<workspace-name>``: The name of the workspace to delete.
50
+ * ``<workspace-id>``: The ID of the workspace to use.
51
+ * ``<workspace-name>``: The name of the workspace to use.
52
+ * ``<group-id>``: The ID of the workspace group to search in.
53
+ * ``<group-name>``: The name of the workspace group to search in.
43
54
 
44
55
  Remarks
45
56
  -------
46
57
  * If you want to specify a database in the current workspace,
47
58
  the workspace name can be specified as ``@@CURRENT``.
59
+ * Use the ``IN GROUP`` clause to specify the ID or name of the workspace
60
+ group where the workspace should be found. If not specified, the current
61
+ workspace group will be used.
48
62
  * Specify the ``WITH DATABASE`` clause to select a default
49
63
  database for the session.
50
64
  * This command only works in a notebook session in the
@@ -57,23 +71,69 @@ class UseWorkspaceHandler(SQLHandler):
57
71
 
58
72
  USE WORKSPACE 'examplews' WITH DATABASE 'dbname';
59
73
 
74
+ The following command sets the workspace to ``examplews`` from a specific
75
+ workspace group::
76
+
77
+ USE WORKSPACE 'examplews' IN GROUP 'my-workspace-group';
78
+
60
79
  """
61
80
  def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
62
81
  from singlestoredb.notebook import portal
82
+
83
+ # Handle current workspace case
63
84
  if params['workspace'].get('current_workspace'):
64
85
  if params.get('with_database'):
65
86
  portal.default_database = params['with_database']
66
- elif params.get('with_database'):
67
- if params['workspace'].get('workspace_name'):
68
- portal.connection = params['workspace']['workspace_name'], \
69
- params['with_database']
87
+ return None
88
+
89
+ # Get workspace name or ID
90
+ workspace_name = params['workspace'].get('workspace_name')
91
+ workspace_id = params['workspace'].get('workspace_id')
92
+
93
+ # If IN GROUP is specified, look up workspace in that group
94
+ if params.get('in_group'):
95
+ workspace_group = get_workspace_group(params)
96
+
97
+ if workspace_name:
98
+ workspace = workspace_group.workspaces[workspace_name]
99
+ elif workspace_id:
100
+ # Find workspace by ID in the specified group
101
+ workspace = next(
102
+ (w for w in workspace_group.workspaces if w.id == workspace_id),
103
+ None,
104
+ )
105
+ if workspace is None:
106
+ raise KeyError(f'no workspace found with ID: {workspace_id}')
107
+
108
+ workspace_id = workspace.id
109
+
110
+ # Set workspace and database
111
+ if params.get('with_database'):
112
+ if params.get('in_group'):
113
+ # Use 3-element tuple: (workspace_group_id, workspace_name_or_id,
114
+ # database)
115
+ portal.connection = ( # type: ignore[assignment]
116
+ workspace_group.id,
117
+ workspace_name or workspace_id,
118
+ params['with_database'],
119
+ )
70
120
  else:
71
- portal.connection = params['workspace']['workspace_id'], \
72
- params['with_database']
73
- elif params['workspace'].get('workspace_name'):
74
- portal.workspace = params['workspace']['workspace_name']
121
+ # Use 2-element tuple: (workspace_name_or_id, database)
122
+ portal.connection = (
123
+ workspace_name or workspace_id,
124
+ params['with_database'],
125
+ )
75
126
  else:
76
- portal.workspace = params['workspace']['workspace_id']
127
+ if params.get('in_group'):
128
+ # Use 2-element tuple: (workspace_group_id, workspace_name_or_id)
129
+ portal.workspace = ( # type: ignore[assignment]
130
+ workspace_group.id,
131
+ workspace_name or workspace_id,
132
+ )
133
+ else:
134
+ # Use string: workspace_name_or_id
135
+ portal.workspace = workspace_name or workspace_id
136
+
77
137
  return None
78
138
 
79
139
 
@@ -460,7 +460,7 @@ class Stage(FileLocation):
460
460
 
461
461
  """
462
462
  res = self._manager._get(
463
- f'stage/{self._deployment_id}/fs/{stage_path}',
463
+ re.sub(r'/+$', r'/', f'stage/{self._deployment_id}/fs/{stage_path}'),
464
464
  ).json()
465
465
  if recursive:
466
466
  out = []
@@ -10,6 +10,7 @@ from typing import Dict
10
10
  from typing import List
11
11
  from typing import Optional
12
12
  from typing import Tuple
13
+ from typing import Union
13
14
 
14
15
  from . import _objects as obj
15
16
  from ..management import workspace as mgr
@@ -167,15 +168,32 @@ class Portal(object):
167
168
  return obj.workspace
168
169
 
169
170
  @workspace.setter
170
- def workspace(self, name_or_id: str) -> None:
171
+ def workspace(self, workspace_spec: Union[str, Tuple[str, str]]) -> None:
171
172
  """Set workspace."""
172
- if re.match(
173
- r'[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}',
174
- name_or_id, flags=re.I,
175
- ):
176
- w = mgr.get_workspace(name_or_id)
173
+ if isinstance(workspace_spec, tuple):
174
+ # 2-element tuple: (workspace_group_id, workspace_name_or_id)
175
+ workspace_group_id, name_or_id = workspace_spec
176
+ uuid_pattern = (
177
+ r'[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}'
178
+ )
179
+ if re.match(uuid_pattern, name_or_id, flags=re.I):
180
+ w = mgr.get_workspace(name_or_id)
181
+ else:
182
+ w = mgr.get_workspace_group(workspace_group_id).workspaces[
183
+ name_or_id
184
+ ]
177
185
  else:
178
- w = mgr.get_workspace_group(self.workspace_group_id).workspaces[name_or_id]
186
+ # String: workspace_name_or_id (existing behavior)
187
+ name_or_id = workspace_spec
188
+ uuid_pattern = (
189
+ r'[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}'
190
+ )
191
+ if re.match(uuid_pattern, name_or_id, flags=re.I):
192
+ w = mgr.get_workspace(name_or_id)
193
+ else:
194
+ w = mgr.get_workspace_group(
195
+ self.workspace_group_id,
196
+ ).workspaces[name_or_id]
179
197
 
180
198
  if w.state and w.state.lower() not in ['active', 'resumed']:
181
199
  raise RuntimeError('workspace is not active')
@@ -196,16 +214,37 @@ class Portal(object):
196
214
  return self.workspace, self.default_database
197
215
 
198
216
  @connection.setter
199
- def connection(self, workspace_and_default_database: Tuple[str, str]) -> None:
217
+ def connection(
218
+ self,
219
+ connection_spec: Union[Tuple[str, str], Tuple[str, str, str]],
220
+ ) -> None:
200
221
  """Set workspace and default database name."""
201
- name_or_id, default_database = workspace_and_default_database
202
- if re.match(
203
- r'[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}',
204
- name_or_id, flags=re.I,
205
- ):
206
- w = mgr.get_workspace(name_or_id)
222
+ if len(connection_spec) == 3:
223
+ # 3-element tuple: (workspace_group_id, workspace_name_or_id,
224
+ # default_database)
225
+ workspace_group_id, name_or_id, default_database = connection_spec
226
+ uuid_pattern = (
227
+ r'[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}'
228
+ )
229
+ if re.match(uuid_pattern, name_or_id, flags=re.I):
230
+ w = mgr.get_workspace(name_or_id)
231
+ else:
232
+ w = mgr.get_workspace_group(workspace_group_id).workspaces[
233
+ name_or_id
234
+ ]
207
235
  else:
208
- w = mgr.get_workspace_group(self.workspace_group_id).workspaces[name_or_id]
236
+ # 2-element tuple: (workspace_name_or_id, default_database)
237
+ # existing behavior
238
+ name_or_id, default_database = connection_spec
239
+ uuid_pattern = (
240
+ r'[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}'
241
+ )
242
+ if re.match(uuid_pattern, name_or_id, flags=re.I):
243
+ w = mgr.get_workspace(name_or_id)
244
+ else:
245
+ w = mgr.get_workspace_group(
246
+ self.workspace_group_id,
247
+ ).workspaces[name_or_id]
209
248
 
210
249
  if w.state and w.state.lower() not in ['active', 'resumed']:
211
250
  raise RuntimeError('workspace is not active')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: singlestoredb
3
- Version: 1.15.4
3
+ Version: 1.15.5
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
@@ -1,16 +1,16 @@
1
- _singlestoredb_accel.abi3.so,sha256=WzLoAGy7KZwVR0DZCtuaSQ5ArfCrLykDYvZEnefRs58,207264
1
+ _singlestoredb_accel.abi3.so,sha256=x1zaDVImJ4CWAfQPrICls-q50fsaCFB1_bbelHM2Y-Q,207264
2
+ singlestoredb-1.15.5.dist-info/RECORD,,
3
+ singlestoredb-1.15.5.dist-info/LICENSE,sha256=Mlq78idURT-9G026aMYswwwnnrLcgzTLuXeAs5hjDLM,11341
4
+ singlestoredb-1.15.5.dist-info/WHEEL,sha256=_VEguvlLpUd-c8RbFMA4yMIVNMBv2LhpxYLCEQ-Bogk,113
5
+ singlestoredb-1.15.5.dist-info/entry_points.txt,sha256=bSLaTWB5zGjpVYPAaI46MkkDup0su-eb3uAhCNYuRV0,48
6
+ singlestoredb-1.15.5.dist-info/top_level.txt,sha256=lA65Vf4qAMfg_s1oG3LEO90h4t1Z-SPDbRqkevI3bSY,40
7
+ singlestoredb-1.15.5.dist-info/METADATA,sha256=deTmpWalhUYHaanjCuaVrQLIld_rfhdAPF6a1Fwa18A,5804
2
8
  sqlx/magic.py,sha256=JsS9_9aBFaOt91Torm1JPN0c8qB2QmYJmNSKtbSQIY0,3509
3
9
  sqlx/__init__.py,sha256=aBYiU8DZXCogvWu3yWafOz7bZS5WWwLZXj7oL0dXGyU,85
4
- singlestoredb-1.15.4.dist-info/RECORD,,
5
- singlestoredb-1.15.4.dist-info/LICENSE,sha256=Mlq78idURT-9G026aMYswwwnnrLcgzTLuXeAs5hjDLM,11341
6
- singlestoredb-1.15.4.dist-info/WHEEL,sha256=_VEguvlLpUd-c8RbFMA4yMIVNMBv2LhpxYLCEQ-Bogk,113
7
- singlestoredb-1.15.4.dist-info/entry_points.txt,sha256=bSLaTWB5zGjpVYPAaI46MkkDup0su-eb3uAhCNYuRV0,48
8
- singlestoredb-1.15.4.dist-info/top_level.txt,sha256=lA65Vf4qAMfg_s1oG3LEO90h4t1Z-SPDbRqkevI3bSY,40
9
- singlestoredb-1.15.4.dist-info/METADATA,sha256=MJiyWzkveAukhfgYP959W0uttZVSmcq7DBTgaj4UnZY,5804
10
10
  singlestoredb/auth.py,sha256=u8D9tpKzrqa4ssaHjyZnGDX1q8XBpGtuoOkTkSv7B28,7599
11
11
  singlestoredb/config.py,sha256=aBdMrPEaNSH-QLi1AXoQaSJsZ9f6ZXoFPN-74Trr6sQ,13935
12
12
  singlestoredb/vectorstore.py,sha256=BZb8e7m02_XVHqOyu8tA94R6kHb3n-BC8F08JyJwDzY,8408
13
- singlestoredb/__init__.py,sha256=2IMVeTNRjiRom1ypTqkQNA1Ro51sGMnrWIMSlxmf3Ls,2272
13
+ singlestoredb/__init__.py,sha256=laZYv8Vwx1AbBnqnp8ESXHckpITWCEmLX7WlFArId-Y,2272
14
14
  singlestoredb/types.py,sha256=Qp_PWYjSYG6PRnmXAZZ7K2QehUqfoG4KSllI3O1stPE,10397
15
15
  singlestoredb/connection.py,sha256=ELk3-UpM6RaB993aIt08MydKiiDnejHQ1s8EFiacrAI,46055
16
16
  singlestoredb/pytest.py,sha256=OyF3BO9mgxenifYhOihnzGk8WzCJ_zN5_mxe8XyFPOc,9074
@@ -29,7 +29,7 @@ singlestoredb/fusion/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
29
29
  singlestoredb/fusion/handlers/export.py,sha256=Af4eIMPGKEOpmf4LXnvQsgmnvx5F8B5FkRI20RvEa7o,15309
30
30
  singlestoredb/fusion/handlers/utils.py,sha256=ozHOWUraoN8XGTK9JZdhv5HV8AQR8zfUd1yh1kLvUXY,10685
31
31
  singlestoredb/fusion/handlers/stage.py,sha256=edViRGlBF7xZUd3ClmpBlMcBc6O4JKdvA9DGgnbGFdU,14272
32
- singlestoredb/fusion/handlers/workspace.py,sha256=4xN2TFO4yF7KZB2Fcht7IuvoDdAT6fDfDLjixiHZN8w,27506
32
+ singlestoredb/fusion/handlers/workspace.py,sha256=8NZwKg9YE9LL1c1JCnO-p4RuNBQ0V4gicQeFXKEZxGA,29672
33
33
  singlestoredb/tests/test.sql,sha256=mErluOEZsN0QH5EuSVR8Ki-NSIpdpR8MStuchec_ZKc,18640
34
34
  singlestoredb/tests/alltypes_no_nulls.sql,sha256=MCeBEoeZC6mmeG9-4J7vy9ZOIvvKWqqMgdpHQlvDDzs,6240
35
35
  singlestoredb/tests/test_xdict.py,sha256=fqHspoi39nbX3fIDVkkRXcd5H50xdOsSvK0bxAMQnaE,10408
@@ -70,7 +70,7 @@ singlestoredb/management/export.py,sha256=yR-yZUE9USFrP5OR_5iLFqEc8GLiKDQypSEp08
70
70
  singlestoredb/management/utils.py,sha256=QIhZCZSRaDbAG35xu1_n7ihmRXON8swc-gEK2FGYutI,13203
71
71
  singlestoredb/management/cluster.py,sha256=vDefpp2IMZRawvueIqZK2pePWVNnPWb6Szrt8mO8gmg,14419
72
72
  singlestoredb/management/inference_api.py,sha256=L6eFqaUaPugF_cmrZ4xlArj8CIv25vWqQs1vwgKPEF4,2583
73
- singlestoredb/management/workspace.py,sha256=XoguxUm2k2MP6Fct8am_735ZgPqUXBkIjPwBOVtIBIY,61931
73
+ singlestoredb/management/workspace.py,sha256=frVNqwfUgth1WWhcf5rZqz9nIcPkMtmCb5hKVx1h5SI,61953
74
74
  singlestoredb/management/manager.py,sha256=k8JKPXyJVHI7gFwqIhxhUtQr_KdBCXw7Dw4GCdCtdKg,9352
75
75
  singlestoredb/management/billing_usage.py,sha256=9ighjIpcopgIyJOktBYQ6pahBZmWGHOPyyCW4gu9FGs,3735
76
76
  singlestoredb/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -156,7 +156,7 @@ singlestoredb/functions/dtypes.py,sha256=DgJaNXouJ2t-qIqDiQlUYU9IhkXXUTigWeE_MAc
156
156
  singlestoredb/functions/utils.py,sha256=1L0Phgzq0XdWK3ecfOOydq4zV955yCwpDoAaCYRGldk,10769
157
157
  singlestoredb/functions/signature.py,sha256=h2vFVNP07d5a3gi7zMiM_sztDUNK_HlJWR-Rl3nMxPA,45545
158
158
  singlestoredb/functions/ext/timer.py,sha256=-PR__KbhwAMW4PXJ4fGri2FfrU0jRyz6e6yvmySmjaw,2706
159
- singlestoredb/functions/ext/asgi.py,sha256=H7YgSsqKzhVun9cj5iXvM_8yXM_Zciuy8BEPBp_dT4Y,71650
159
+ singlestoredb/functions/ext/asgi.py,sha256=HWbSuYpAOfq-iS7oKDdXCkz5OIaMOGnXYwrTIVzFqOM,72370
160
160
  singlestoredb/functions/ext/arrow.py,sha256=WB7n1ACslyd8nlbFzUvlbxn1BVuEjA9-BGBEqCWlSOo,9061
161
161
  singlestoredb/functions/ext/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
162
162
  singlestoredb/functions/ext/utils.py,sha256=oU2NVmkjcS0QHLfdB8SBiRylVq-r0VzTy8nxGvAgjow,6938
@@ -170,7 +170,7 @@ singlestoredb/functions/typing/numpy.py,sha256=WO64_HziveGk0dqRrkuZ51aohULy9qYuq
170
170
  singlestoredb/functions/typing/polars.py,sha256=b_UOIXLkvptHiAB7sXSzC7XPHMWNOglCz6h9amCA6Kg,83
171
171
  singlestoredb/notebook/__init__.py,sha256=v0j1E3MFAtaC8wTrR-F7XY0nytUvQ4XpYhVXddv2xA0,533
172
172
  singlestoredb/notebook/_objects.py,sha256=MkB1eowEq5SQXFHY00xAKAyyeLqHu_uaZiA20BCJPaE,8043
173
- singlestoredb/notebook/_portal.py,sha256=DLerIEQmAUymtYcx8RBeuYJ4pJSy_xl1K6t1Oc-eTf8,9698
173
+ singlestoredb/notebook/_portal.py,sha256=4HFMZPizkBvUDGexYX-KK-sHPj95lsbP2sf0fHFFip4,11357
174
174
  singlestoredb/apps/_python_udfs.py,sha256=CwGt1ehR6CPvtUfLg8SK_ynXvvWHo_SeU_6xoVHQzys,3158
175
175
  singlestoredb/apps/_dashboards.py,sha256=_03fI-GJannamA5lxLvIoC6Mim-H1jTRuI8-dw_P--k,1474
176
176
  singlestoredb/apps/__init__.py,sha256=dfN97AZz7Np6JML3i9GJrv22ZbNCUletXmsJpQnKhKg,170