singlestoredb 1.14.2__py3-none-any.whl → 1.15.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.

Files changed (54) hide show
  1. singlestoredb/__init__.py +2 -2
  2. singlestoredb/ai/chat.py +14 -0
  3. singlestoredb/apps/_python_udfs.py +3 -3
  4. singlestoredb/config.py +11 -0
  5. singlestoredb/docstring/__init__.py +33 -0
  6. singlestoredb/docstring/attrdoc.py +126 -0
  7. singlestoredb/docstring/common.py +230 -0
  8. singlestoredb/docstring/epydoc.py +267 -0
  9. singlestoredb/docstring/google.py +412 -0
  10. singlestoredb/docstring/numpydoc.py +562 -0
  11. singlestoredb/docstring/parser.py +100 -0
  12. singlestoredb/docstring/py.typed +1 -0
  13. singlestoredb/docstring/rest.py +256 -0
  14. singlestoredb/docstring/tests/__init__.py +1 -0
  15. singlestoredb/docstring/tests/_pydoctor.py +21 -0
  16. singlestoredb/docstring/tests/test_epydoc.py +729 -0
  17. singlestoredb/docstring/tests/test_google.py +1007 -0
  18. singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
  19. singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
  20. singlestoredb/docstring/tests/test_parser.py +248 -0
  21. singlestoredb/docstring/tests/test_rest.py +547 -0
  22. singlestoredb/docstring/tests/test_util.py +70 -0
  23. singlestoredb/docstring/util.py +141 -0
  24. singlestoredb/functions/decorator.py +51 -31
  25. singlestoredb/functions/ext/asgi.py +381 -35
  26. singlestoredb/functions/ext/timer.py +98 -0
  27. singlestoredb/functions/signature.py +374 -241
  28. singlestoredb/functions/typing/numpy.py +20 -0
  29. singlestoredb/functions/typing/pandas.py +2 -0
  30. singlestoredb/functions/typing/polars.py +2 -0
  31. singlestoredb/functions/typing/pyarrow.py +2 -0
  32. singlestoredb/fusion/handlers/files.py +4 -4
  33. singlestoredb/fusion/handlers/models.py +1 -1
  34. singlestoredb/fusion/handlers/stage.py +4 -4
  35. singlestoredb/magics/run_personal.py +82 -1
  36. singlestoredb/magics/run_shared.py +82 -1
  37. singlestoredb/management/__init__.py +1 -0
  38. singlestoredb/management/cluster.py +1 -1
  39. singlestoredb/management/manager.py +15 -5
  40. singlestoredb/management/region.py +104 -2
  41. singlestoredb/management/workspace.py +174 -3
  42. singlestoredb/tests/ext_funcs/__init__.py +133 -55
  43. singlestoredb/tests/test.sql +22 -0
  44. singlestoredb/tests/test_connection.py +18 -8
  45. singlestoredb/tests/test_ext_func.py +90 -0
  46. singlestoredb/tests/test_management.py +190 -0
  47. singlestoredb/tests/test_udf.py +43 -15
  48. {singlestoredb-1.14.2.dist-info → singlestoredb-1.15.1.dist-info}/METADATA +1 -1
  49. {singlestoredb-1.14.2.dist-info → singlestoredb-1.15.1.dist-info}/RECORD +54 -30
  50. /singlestoredb/functions/{typing.py → typing/__init__.py} +0 -0
  51. {singlestoredb-1.14.2.dist-info → singlestoredb-1.15.1.dist-info}/LICENSE +0 -0
  52. {singlestoredb-1.14.2.dist-info → singlestoredb-1.15.1.dist-info}/WHEEL +0 -0
  53. {singlestoredb-1.14.2.dist-info → singlestoredb-1.15.1.dist-info}/entry_points.txt +0 -0
  54. {singlestoredb-1.14.2.dist-info → singlestoredb-1.15.1.dist-info}/top_level.txt +0 -0
@@ -1074,7 +1074,7 @@ class WorkspaceGroup(object):
1074
1074
  try:
1075
1075
  region = [x for x in manager.regions if x.id == obj['regionID']][0]
1076
1076
  except IndexError:
1077
- region = Region(obj.get('regionID', '<unknown>'), '<unknown>', '<unknown>')
1077
+ region = Region('<unknown>', '<unknown>', obj.get('regionID', '<unknown>'))
1078
1078
  out = cls(
1079
1079
  name=obj['name'],
1080
1080
  id=obj['workspaceGroupID'],
@@ -1301,17 +1301,24 @@ class StarterWorkspace(object):
1301
1301
  See Also
1302
1302
  --------
1303
1303
  :meth:`WorkspaceManager.get_starter_workspace`
1304
+ :meth:`WorkspaceManager.create_starter_workspace`
1305
+ :meth:`WorkspaceManager.terminate_starter_workspace`
1306
+ :meth:`WorkspaceManager.create_starter_workspace_user`
1304
1307
  :attr:`WorkspaceManager.starter_workspaces`
1305
1308
 
1306
1309
  """
1307
1310
 
1308
1311
  name: str
1309
1312
  id: str
1313
+ database_name: str
1314
+ endpoint: Optional[str]
1310
1315
 
1311
1316
  def __init__(
1312
1317
  self,
1313
1318
  name: str,
1314
1319
  id: str,
1320
+ database_name: str,
1321
+ endpoint: Optional[str] = None,
1315
1322
  ):
1316
1323
  #: Name of the starter workspace
1317
1324
  self.name = name
@@ -1319,6 +1326,13 @@ class StarterWorkspace(object):
1319
1326
  #: Unique ID of the starter workspace
1320
1327
  self.id = id
1321
1328
 
1329
+ #: Name of the database associated with the starter workspace
1330
+ self.database_name = database_name
1331
+
1332
+ #: Endpoint to connect to the starter workspace. The endpoint is in the form
1333
+ #: of ``hostname:port``
1334
+ self.endpoint = endpoint
1335
+
1322
1336
  self._manager: Optional[WorkspaceManager] = None
1323
1337
 
1324
1338
  def __str__(self) -> str:
@@ -1351,10 +1365,60 @@ class StarterWorkspace(object):
1351
1365
  out = cls(
1352
1366
  name=obj['name'],
1353
1367
  id=obj['virtualWorkspaceID'],
1368
+ database_name=obj['databaseName'],
1369
+ endpoint=obj.get('endpoint'),
1354
1370
  )
1355
1371
  out._manager = manager
1356
1372
  return out
1357
1373
 
1374
+ def connect(self, **kwargs: Any) -> connection.Connection:
1375
+ """
1376
+ Create a connection to the database server for this starter workspace.
1377
+
1378
+ Parameters
1379
+ ----------
1380
+ **kwargs : keyword-arguments, optional
1381
+ Parameters to the SingleStoreDB `connect` function except host
1382
+ and port which are supplied by the starter workspace object
1383
+
1384
+ Returns
1385
+ -------
1386
+ :class:`Connection`
1387
+
1388
+ """
1389
+ if not self.endpoint:
1390
+ raise ManagementError(
1391
+ msg='An endpoint has not been set in this '
1392
+ 'starter workspace configuration',
1393
+ )
1394
+
1395
+ kwargs['host'] = self.endpoint
1396
+ kwargs['database'] = self.database_name
1397
+
1398
+ return connection.connect(**kwargs)
1399
+
1400
+ def terminate(self) -> None:
1401
+ """Terminate the starter workspace."""
1402
+ if self._manager is None:
1403
+ raise ManagementError(
1404
+ msg='No workspace manager is associated with this object.',
1405
+ )
1406
+ self._manager._delete(f'sharedtier/virtualWorkspaces/{self.id}')
1407
+
1408
+ def refresh(self) -> StarterWorkspace:
1409
+ """Update the object to the current state."""
1410
+ if self._manager is None:
1411
+ raise ManagementError(
1412
+ msg='No workspace manager is associated with this object.',
1413
+ )
1414
+ new_obj = self._manager.get_starter_workspace(self.id)
1415
+ for name, value in vars(new_obj).items():
1416
+ if isinstance(value, Mapping):
1417
+ setattr(self, name, snake_to_camel_dict(value))
1418
+ else:
1419
+ setattr(self, name, value)
1420
+ return self
1421
+
1358
1422
  @property
1359
1423
  def organization(self) -> Organization:
1360
1424
  if self._manager is None:
@@ -1375,7 +1439,7 @@ class StarterWorkspace(object):
1375
1439
  stages = stage
1376
1440
 
1377
1441
  @property
1378
- def starter_workspaces(self) -> NamedList[StarterWorkspace]:
1442
+ def starter_workspaces(self) -> NamedList['StarterWorkspace']:
1379
1443
  """Return a list of available starter workspaces."""
1380
1444
  if self._manager is None:
1381
1445
  raise ManagementError(
@@ -1386,6 +1450,64 @@ class StarterWorkspace(object):
1386
1450
  [StarterWorkspace.from_dict(item, self._manager) for item in res.json()],
1387
1451
  )
1388
1452
 
1453
+ def create_user(
1454
+ self,
1455
+ username: str,
1456
+ password: Optional[str] = None,
1457
+ ) -> Dict[str, str]:
1458
+ """
1459
+ Create a new user for this starter workspace.
1460
+
1461
+ Parameters
1462
+ ----------
1463
+ username : str
1464
+ The starter workspace user name to connect the new user to the database
1465
+ password : str, optional
1466
+ Password for the new user. If not provided, a password will be
1467
+ auto-generated by the system.
1468
+
1469
+ Returns
1470
+ -------
1471
+ Dict[str, str]
1472
+ Dictionary containing 'userID' and 'password' of the created user
1473
+
1474
+ Raises
1475
+ ------
1476
+ ManagementError
1477
+ If no workspace manager is associated with this object.
1478
+ """
1479
+ if self._manager is None:
1480
+ raise ManagementError(
1481
+ msg='No workspace manager is associated with this object.',
1482
+ )
1483
+
1484
+ payload = {
1485
+ 'userName': username,
1486
+ }
1487
+ if password is not None:
1488
+ payload['password'] = password
1489
+
1490
+ res = self._manager._post(
1491
+ f'sharedtier/virtualWorkspaces/{self.id}/users',
1492
+ json=payload,
1493
+ )
1494
+
1495
+ response_data = res.json()
1496
+ user_id = response_data.get('userID')
1497
+ if not user_id:
1498
+ raise ManagementError(msg='No userID returned from API')
1499
+
1500
+ # Return the password provided by user or generated by API
1501
+ returned_password = password if password is not None \
1502
+ else response_data.get('password')
1503
+ if not returned_password:
1504
+ raise ManagementError(msg='No password available from API response')
1505
+
1506
+ return {
1507
+ 'user_id': user_id,
1508
+ 'password': returned_password,
1509
+ }
1510
+
1389
1511
 
1390
1512
  class Billing(object):
1391
1513
  """Billing information."""
@@ -1522,6 +1644,14 @@ class WorkspaceManager(Manager):
1522
1644
  res = self._get('regions')
1523
1645
  return NamedList([Region.from_dict(item, self) for item in res.json()])
1524
1646
 
1647
+ @ttl_property(datetime.timedelta(hours=1))
1648
+ def shared_tier_regions(self) -> NamedList[Region]:
1649
+ """Return a list of regions that support shared tier workspaces."""
1650
+ res = self._get('regions/sharedtier')
1651
+ return NamedList(
1652
+ [Region.from_dict(item, self) for item in res.json()],
1653
+ )
1654
+
1525
1655
  def create_workspace_group(
1526
1656
  self,
1527
1657
  name: str,
@@ -1582,7 +1712,7 @@ class WorkspaceManager(Manager):
1582
1712
  :class:`WorkspaceGroup`
1583
1713
 
1584
1714
  """
1585
- if isinstance(region, Region):
1715
+ if isinstance(region, Region) and region.id:
1586
1716
  region = region.id
1587
1717
  res = self._post(
1588
1718
  'workspaceGroups', json=dict(
@@ -1717,6 +1847,47 @@ class WorkspaceManager(Manager):
1717
1847
  res = self._get(f'sharedtier/virtualWorkspaces/{id}')
1718
1848
  return StarterWorkspace.from_dict(res.json(), manager=self)
1719
1849
 
1850
+ def create_starter_workspace(
1851
+ self,
1852
+ name: str,
1853
+ database_name: str,
1854
+ provider: str,
1855
+ region_name: str,
1856
+ ) -> 'StarterWorkspace':
1857
+ """
1858
+ Create a new starter (shared tier) workspace.
1859
+
1860
+ Parameters
1861
+ ----------
1862
+ name : str
1863
+ Name of the starter workspace
1864
+ database_name : str
1865
+ Name of the database for the starter workspace
1866
+ provider : str
1867
+ Cloud provider for the starter workspace (e.g., 'aws', 'gcp', 'azure')
1868
+ region_name : str
1869
+ Cloud provider region for the starter workspace (e.g., 'us-east-1')
1870
+
1871
+ Returns
1872
+ -------
1873
+ :class:`StarterWorkspace`
1874
+ """
1875
+
1876
+ payload = {
1877
+ 'name': name,
1878
+ 'databaseName': database_name,
1879
+ 'provider': provider,
1880
+ 'regionName': region_name,
1881
+ }
1882
+
1883
+ res = self._post('sharedtier/virtualWorkspaces', json=payload)
1884
+ virtual_workspace_id = res.json().get('virtualWorkspaceID')
1885
+ if not virtual_workspace_id:
1886
+ raise ManagementError(msg='No virtualWorkspaceID returned from API')
1887
+
1888
+ res = self._get(f'sharedtier/virtualWorkspaces/{virtual_workspace_id}')
1889
+ return StarterWorkspace.from_dict(res.json(), self)
1890
+
1720
1891
 
1721
1892
  def manage_workspaces(
1722
1893
  access_token: Optional[str] = None,