singlestoredb 1.0.3__cp38-abi3-win32.whl → 1.1.0__cp38-abi3-win32.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 (31) hide show
  1. _singlestoredb_accel.pyd +0 -0
  2. singlestoredb/__init__.py +1 -1
  3. singlestoredb/config.py +125 -0
  4. singlestoredb/functions/dtypes.py +5 -198
  5. singlestoredb/functions/ext/__init__.py +0 -1
  6. singlestoredb/functions/ext/asgi.py +665 -153
  7. singlestoredb/functions/ext/json.py +2 -2
  8. singlestoredb/functions/ext/mmap.py +174 -67
  9. singlestoredb/functions/ext/rowdat_1.py +2 -2
  10. singlestoredb/functions/ext/utils.py +169 -0
  11. singlestoredb/fusion/handler.py +109 -9
  12. singlestoredb/fusion/handlers/stage.py +150 -0
  13. singlestoredb/fusion/handlers/workspace.py +265 -4
  14. singlestoredb/fusion/registry.py +69 -1
  15. singlestoredb/http/connection.py +40 -2
  16. singlestoredb/management/utils.py +30 -0
  17. singlestoredb/management/workspace.py +209 -35
  18. singlestoredb/mysql/connection.py +69 -0
  19. singlestoredb/mysql/cursors.py +176 -4
  20. singlestoredb/tests/test.sql +210 -0
  21. singlestoredb/tests/test_connection.py +1408 -0
  22. singlestoredb/tests/test_ext_func.py +2 -2
  23. singlestoredb/tests/test_ext_func_data.py +1 -1
  24. singlestoredb/utils/dtypes.py +205 -0
  25. singlestoredb/utils/results.py +367 -14
  26. {singlestoredb-1.0.3.dist-info → singlestoredb-1.1.0.dist-info}/METADATA +2 -1
  27. {singlestoredb-1.0.3.dist-info → singlestoredb-1.1.0.dist-info}/RECORD +31 -29
  28. {singlestoredb-1.0.3.dist-info → singlestoredb-1.1.0.dist-info}/LICENSE +0 -0
  29. {singlestoredb-1.0.3.dist-info → singlestoredb-1.1.0.dist-info}/WHEEL +0 -0
  30. {singlestoredb-1.0.3.dist-info → singlestoredb-1.1.0.dist-info}/entry_points.txt +0 -0
  31. {singlestoredb-1.0.3.dist-info → singlestoredb-1.1.0.dist-info}/top_level.txt +0 -0
@@ -7,8 +7,8 @@ import glob
7
7
  import io
8
8
  import os
9
9
  import re
10
- import socket
11
10
  import time
11
+ from collections.abc import Mapping
12
12
  from typing import Any
13
13
  from typing import BinaryIO
14
14
  from typing import Dict
@@ -23,10 +23,12 @@ from .billing_usage import BillingUsageItem
23
23
  from .manager import Manager
24
24
  from .organization import Organization
25
25
  from .region import Region
26
+ from .utils import camel_to_snake_dict
26
27
  from .utils import from_datetime
27
28
  from .utils import NamedList
28
29
  from .utils import PathLike
29
30
  from .utils import snake_to_camel
31
+ from .utils import snake_to_camel_dict
30
32
  from .utils import to_datetime
31
33
  from .utils import ttl_property
32
34
  from .utils import vars_to_str
@@ -934,6 +936,12 @@ class Workspace(object):
934
936
  created_at: Union[str, datetime.datetime],
935
937
  terminated_at: Optional[Union[str, datetime.datetime]] = None,
936
938
  endpoint: Optional[str] = None,
939
+ auto_suspend: Optional[Dict[str, Any]] = None,
940
+ cache_config: Optional[int] = None,
941
+ deployment_type: Optional[str] = None,
942
+ resume_attachments: Optional[Dict[str, Any]] = None,
943
+ scaling_progress: Optional[int] = None,
944
+ last_resumed_at: Optional[str] = None,
937
945
  ):
938
946
  #: Name of the workspace
939
947
  self.name = name
@@ -963,6 +971,24 @@ class Workspace(object):
963
971
  #: Hostname (or IP address) of the workspace database server
964
972
  self.endpoint = endpoint
965
973
 
974
+ #: Current auto-suspend settings
975
+ self.auto_suspend = camel_to_snake_dict(auto_suspend)
976
+
977
+ #: Multiplier for the persistent cache
978
+ self.cache_config = cache_config
979
+
980
+ #: Deployment type of the workspace
981
+ self.deployment_type = deployment_type
982
+
983
+ #: Database attachments
984
+ self.resume_attachments = camel_to_snake_dict(resume_attachments)
985
+
986
+ #: Current progress percentage for scaling the workspace
987
+ self.scaling_progress = scaling_progress
988
+
989
+ #: Timestamp when workspace was last resumed
990
+ self.last_resumed_at = to_datetime(last_resumed_at)
991
+
966
992
  self._manager: Optional[WorkspaceManager] = None
967
993
 
968
994
  def __str__(self) -> str:
@@ -991,15 +1017,64 @@ class Workspace(object):
991
1017
 
992
1018
  """
993
1019
  out = cls(
994
- name=obj['name'], workspace_id=obj['workspaceID'],
1020
+ name=obj['name'],
1021
+ workspace_id=obj['workspaceID'],
995
1022
  workspace_group=obj['workspaceGroupID'],
996
- size=obj.get('size', 'Unknown'), state=obj['state'],
997
- created_at=obj['createdAt'], terminated_at=obj.get('terminatedAt'),
1023
+ size=obj.get('size', 'Unknown'),
1024
+ state=obj['state'],
1025
+ created_at=obj['createdAt'],
1026
+ terminated_at=obj.get('terminatedAt'),
998
1027
  endpoint=obj.get('endpoint'),
1028
+ auto_suspend=obj.get('autoSuspend'),
1029
+ cache_config=obj.get('cacheConfig'),
1030
+ deployment_type=obj.get('deploymentType'),
1031
+ last_resumed_at=obj.get('lastResumedAt'),
1032
+ resume_attachments=obj.get('resumeAttachments'),
1033
+ scaling_progress=obj.get('scalingProgress'),
999
1034
  )
1000
1035
  out._manager = manager
1001
1036
  return out
1002
1037
 
1038
+ def update(
1039
+ self,
1040
+ auto_suspend: Optional[Dict[str, Any]] = None,
1041
+ cache_config: Optional[int] = None,
1042
+ deployment_type: Optional[str] = None,
1043
+ size: Optional[str] = None,
1044
+ ) -> None:
1045
+ """
1046
+ Update the workspace definition.
1047
+
1048
+ Parameters
1049
+ ----------
1050
+ auto_suspend : Dict[str, Any], optional
1051
+ Auto-suspend mode for the workspace: IDLE, SCHEDULED, DISABLED
1052
+ cache_config : int, optional
1053
+ Specifies the multiplier for the persistent cache associated
1054
+ with the workspace. If specified, it enables the cache configuration
1055
+ multiplier. It can have one of the following values: 1, 2, or 4.
1056
+ deployment_type : str, optional
1057
+ The deployment type that will be applied to all the workspaces
1058
+ within the group
1059
+ size : str, optional
1060
+ Size of the workspace (in workspace size notation), such as "S-1".
1061
+
1062
+ """
1063
+ if self._manager is None:
1064
+ raise ManagementError(
1065
+ msg='No workspace manager is associated with this object.',
1066
+ )
1067
+ data = {
1068
+ k: v for k, v in dict(
1069
+ autoSuspend=snake_to_camel_dict(auto_suspend),
1070
+ cacheConfig=cache_config,
1071
+ deploymentType=deployment_type,
1072
+ size=size,
1073
+ ).items() if v is not None
1074
+ }
1075
+ self._manager._patch(f'workspaces/{self.id}', json=data)
1076
+ self.refresh()
1077
+
1003
1078
  def refresh(self) -> Workspace:
1004
1079
  """Update the object to the current state."""
1005
1080
  if self._manager is None:
@@ -1008,7 +1083,10 @@ class Workspace(object):
1008
1083
  )
1009
1084
  new_obj = self._manager.get_workspace(self.id)
1010
1085
  for name, value in vars(new_obj).items():
1011
- setattr(self, name, value)
1086
+ if isinstance(value, Mapping):
1087
+ setattr(self, name, snake_to_camel_dict(value))
1088
+ else:
1089
+ setattr(self, name, value)
1012
1090
  return self
1013
1091
 
1014
1092
  def terminate(
@@ -1111,6 +1189,7 @@ class Workspace(object):
1111
1189
 
1112
1190
  def resume(
1113
1191
  self,
1192
+ disable_auto_suspend: bool = False,
1114
1193
  wait_on_resumed: bool = False,
1115
1194
  wait_interval: int = 20,
1116
1195
  wait_timeout: int = 600,
@@ -1120,6 +1199,8 @@ class Workspace(object):
1120
1199
 
1121
1200
  Parameters
1122
1201
  ----------
1202
+ disable_auto_suspend : bool, optional
1203
+ Should auto-suspend be disabled?
1123
1204
  wait_on_resumed : bool, optional
1124
1205
  Wait for the workspace to go into 'Resumed' or 'Active' mode before returning
1125
1206
  wait_interval : int, optional
@@ -1137,7 +1218,10 @@ class Workspace(object):
1137
1218
  raise ManagementError(
1138
1219
  msg='No workspace manager is associated with this object.',
1139
1220
  )
1140
- self._manager._post(f'workspaces/{self.id}/resume')
1221
+ self._manager._post(
1222
+ f'workspaces/{self.id}/resume',
1223
+ json=dict(disableAutoSuspend=disable_auto_suspend),
1224
+ )
1141
1225
  if wait_on_resumed:
1142
1226
  self._manager._wait_on_state(
1143
1227
  self._manager.get_workspace(self.id),
@@ -1170,6 +1254,7 @@ class WorkspaceGroup(object):
1170
1254
  region: Optional[Region],
1171
1255
  firewall_ranges: List[str],
1172
1256
  terminated_at: Optional[Union[str, datetime.datetime]],
1257
+ allow_all_traffic: Optional[bool],
1173
1258
  ):
1174
1259
  #: Name of the workspace group
1175
1260
  self.name = name
@@ -1189,6 +1274,9 @@ class WorkspaceGroup(object):
1189
1274
  #: Timestamp of when the workspace group was terminated
1190
1275
  self.terminated_at = to_datetime(terminated_at)
1191
1276
 
1277
+ #: Should all traffic be allowed?
1278
+ self.allow_all_traffic = allow_all_traffic
1279
+
1192
1280
  self._manager: Optional[WorkspaceManager] = None
1193
1281
 
1194
1282
  def __str__(self) -> str:
@@ -1229,6 +1317,7 @@ class WorkspaceGroup(object):
1229
1317
  region=region,
1230
1318
  firewall_ranges=obj.get('firewallRanges', []),
1231
1319
  terminated_at=obj.get('terminatedAt'),
1320
+ allow_all_traffic=obj.get('allowAllTraffic'),
1232
1321
  )
1233
1322
  out._manager = manager
1234
1323
  return out
@@ -1260,13 +1349,20 @@ class WorkspaceGroup(object):
1260
1349
  )
1261
1350
  new_obj = self._manager.get_workspace_group(self.id)
1262
1351
  for name, value in vars(new_obj).items():
1263
- setattr(self, name, value)
1352
+ if isinstance(value, Mapping):
1353
+ setattr(self, name, camel_to_snake_dict(value))
1354
+ else:
1355
+ setattr(self, name, value)
1264
1356
  return self
1265
1357
 
1266
1358
  def update(
1267
- self, name: Optional[str] = None,
1268
- admin_password: Optional[str] = None,
1359
+ self,
1360
+ name: Optional[str] = None,
1269
1361
  firewall_ranges: Optional[List[str]] = None,
1362
+ admin_password: Optional[str] = None,
1363
+ expires_at: Optional[str] = None,
1364
+ allow_all_traffic: Optional[bool] = None,
1365
+ update_window: Optional[Dict[str, int]] = None,
1270
1366
  ) -> None:
1271
1367
  """
1272
1368
  Update the workspace group definition.
@@ -1274,11 +1370,24 @@ class WorkspaceGroup(object):
1274
1370
  Parameters
1275
1371
  ----------
1276
1372
  name : str, optional
1277
- Workspace group name
1278
- admim_password : str, optional
1279
- Admin password for the workspace group
1280
- firewall_ranges : Sequence[str], optional
1281
- List of allowed incoming IP addresses
1373
+ Name of the workspace group
1374
+ firewall_ranges : list[str], optional
1375
+ List of allowed CIDR ranges. An empty list indicates that all
1376
+ inbound requests are allowed.
1377
+ admin_password : str, optional
1378
+ Admin password for the workspace group. If no password is supplied,
1379
+ a password will be generated and retured in the response.
1380
+ expires_at : str, optional
1381
+ The timestamp of when the workspace group will expire.
1382
+ If the expiration time is not specified,
1383
+ the workspace group will have no expiration time.
1384
+ At expiration, the workspace group is terminated and all the data is lost.
1385
+ Expiration time can be specified as a timestamp or duration.
1386
+ Example: "2021-01-02T15:04:05Z07:00", "2021-01-02", "3h30m"
1387
+ allow_all_traffic : bool, optional
1388
+ Allow all traffic to the workspace group
1389
+ update_window : Dict[str, int], optional
1390
+ Specify the day and hour of an update window: dict(day=0-6, hour=0-23)
1282
1391
 
1283
1392
  """
1284
1393
  if self._manager is None:
@@ -1287,8 +1396,12 @@ class WorkspaceGroup(object):
1287
1396
  )
1288
1397
  data = {
1289
1398
  k: v for k, v in dict(
1290
- name=name, adminPassword=admin_password,
1399
+ name=name,
1291
1400
  firewallRanges=firewall_ranges,
1401
+ adminPassword=admin_password,
1402
+ expiresAt=expires_at,
1403
+ allowAllTraffic=allow_all_traffic,
1404
+ updateWindow=snake_to_camel_dict(update_window),
1292
1405
  ).items() if v is not None
1293
1406
  }
1294
1407
  self._manager._patch(f'workspaceGroups/{self.id}', json=data)
@@ -1338,9 +1451,15 @@ class WorkspaceGroup(object):
1338
1451
  wait_timeout -= wait_interval
1339
1452
 
1340
1453
  def create_workspace(
1341
- self, name: str, size: Optional[str] = None,
1342
- wait_on_active: bool = False, wait_interval: int = 10,
1343
- wait_timeout: int = 600, add_endpoint_to_firewall_ranges: bool = True,
1454
+ self,
1455
+ name: str,
1456
+ size: Optional[str] = None,
1457
+ auto_suspend: Optional[Dict[str, Any]] = None,
1458
+ cache_config: Optional[int] = None,
1459
+ enable_kai: Optional[bool] = None,
1460
+ wait_on_active: bool = False,
1461
+ wait_interval: int = 10,
1462
+ wait_timeout: int = 600,
1344
1463
  ) -> Workspace:
1345
1464
  """
1346
1465
  Create a new workspace.
@@ -1351,6 +1470,15 @@ class WorkspaceGroup(object):
1351
1470
  Name of the workspace
1352
1471
  size : str, optional
1353
1472
  Workspace size in workspace size notation (S-00, S-1, etc.)
1473
+ auto_suspend : Dict[str, Any], optional
1474
+ Auto suspend settings for the workspace. If this field is not
1475
+ provided, no settings will be enabled.
1476
+ cache_config : int, optional
1477
+ Specifies the multiplier for the persistent cache associated
1478
+ with the workspace. If specified, it enables the cache configuration
1479
+ multiplier. It can have one of the following values: 1, 2, or 4.
1480
+ enable_kai : bool, optional
1481
+ Whether to create a SingleStore Kai-enabled workspace
1354
1482
  wait_on_active : bool, optional
1355
1483
  Wait for the workspace to be active before returning
1356
1484
  wait_timeout : int, optional
@@ -1358,9 +1486,6 @@ class WorkspaceGroup(object):
1358
1486
  if wait=True
1359
1487
  wait_interval : int, optional
1360
1488
  Number of seconds between each polling interval
1361
- add_endpoint_to_firewall_ranges : bool, optional
1362
- Should the workspace endpoint be added to the workspace group
1363
- firewall ranges?
1364
1489
 
1365
1490
  Returns
1366
1491
  -------
@@ -1373,14 +1498,17 @@ class WorkspaceGroup(object):
1373
1498
  )
1374
1499
 
1375
1500
  out = self._manager.create_workspace(
1376
- name=name, workspace_group=self, size=size, wait_on_active=wait_on_active,
1377
- wait_interval=wait_interval, wait_timeout=wait_timeout,
1501
+ name=name,
1502
+ workspace_group=self,
1503
+ size=size,
1504
+ auto_suspend=snake_to_camel_dict(auto_suspend),
1505
+ cache_config=cache_config,
1506
+ enable_kai=enable_kai,
1507
+ wait_on_active=wait_on_active,
1508
+ wait_interval=wait_interval,
1509
+ wait_timeout=wait_timeout,
1378
1510
  )
1379
1511
 
1380
- if add_endpoint_to_firewall_ranges and out.endpoint is not None:
1381
- ip_address = '{}/32'.format(socket.gethostbyname(out.endpoint))
1382
- self.update(firewall_ranges=self.firewall_ranges+[ip_address])
1383
-
1384
1512
  return out
1385
1513
 
1386
1514
  @property
@@ -1525,9 +1653,15 @@ class WorkspaceManager(Manager):
1525
1653
  return NamedList([Region.from_dict(item, self) for item in res.json()])
1526
1654
 
1527
1655
  def create_workspace_group(
1528
- self, name: str, region: Union[str, Region],
1529
- firewall_ranges: List[str], admin_password: Optional[str] = None,
1656
+ self,
1657
+ name: str,
1658
+ region: Union[str, Region],
1659
+ firewall_ranges: List[str],
1660
+ admin_password: Optional[str] = None,
1661
+ backup_bucket_kms_key_id: Optional[str] = None,
1662
+ data_bucket_kms_key_id: Optional[str] = None,
1530
1663
  expires_at: Optional[str] = None,
1664
+ smart_dr: Optional[bool] = None,
1531
1665
  allow_all_traffic: Optional[bool] = None,
1532
1666
  update_window: Optional[Dict[str, int]] = None,
1533
1667
  ) -> WorkspaceGroup:
@@ -1546,6 +1680,17 @@ class WorkspaceManager(Manager):
1546
1680
  admin_password : str, optional
1547
1681
  Admin password for the workspace group. If no password is supplied,
1548
1682
  a password will be generated and retured in the response.
1683
+ backup_bucket_kms_key_id : str, optional
1684
+ Specifies the KMS key ID associated with the backup bucket.
1685
+ If specified, enables Customer-Managed Encryption Keys (CMEK)
1686
+ encryption for the backup bucket of the workspace group.
1687
+ This feature is only supported in workspace groups deployed in AWS.
1688
+ data_bucket_kms_key_id : str, optional
1689
+ Specifies the KMS key ID associated with the data bucket.
1690
+ If specified, enables Customer-Managed Encryption Keys (CMEK)
1691
+ encryption for the data bucket and Amazon Elastic Block Store
1692
+ (EBS) volumes of the workspace group. This feature is only supported
1693
+ in workspace groups deployed in AWS.
1549
1694
  expires_at : str, optional
1550
1695
  The timestamp of when the workspace group will expire.
1551
1696
  If the expiration time is not specified,
@@ -1553,6 +1698,10 @@ class WorkspaceManager(Manager):
1553
1698
  At expiration, the workspace group is terminated and all the data is lost.
1554
1699
  Expiration time can be specified as a timestamp or duration.
1555
1700
  Example: "2021-01-02T15:04:05Z07:00", "2021-01-02", "3h30m"
1701
+ smart_dr : bool, optional
1702
+ Enables Smart Disaster Recovery (SmartDR) for the workspace group.
1703
+ SmartDR is a disaster recovery solution that ensures seamless and
1704
+ continuous replication of data from the primary region to a secondary region
1556
1705
  allow_all_traffic : bool, optional
1557
1706
  Allow all traffic to the workspace group
1558
1707
  update_window : Dict[str, int], optional
@@ -1569,18 +1718,28 @@ class WorkspaceManager(Manager):
1569
1718
  'workspaceGroups', json=dict(
1570
1719
  name=name, regionID=region,
1571
1720
  adminPassword=admin_password,
1721
+ backupBucketKMSKeyID=backup_bucket_kms_key_id,
1722
+ dataBucketKMSKeyID=data_bucket_kms_key_id,
1572
1723
  firewallRanges=firewall_ranges or [],
1573
1724
  expiresAt=expires_at,
1725
+ smartDR=smart_dr,
1574
1726
  allowAllTraffic=allow_all_traffic,
1575
- updateWindow=update_window,
1727
+ updateWindow=snake_to_camel_dict(update_window),
1576
1728
  ),
1577
1729
  )
1578
1730
  return self.get_workspace_group(res.json()['workspaceGroupID'])
1579
1731
 
1580
1732
  def create_workspace(
1581
- self, name: str, workspace_group: Union[str, WorkspaceGroup],
1582
- size: Optional[str] = None, wait_on_active: bool = False,
1583
- wait_interval: int = 10, wait_timeout: int = 600,
1733
+ self,
1734
+ name: str,
1735
+ workspace_group: Union[str, WorkspaceGroup],
1736
+ size: Optional[str] = None,
1737
+ auto_suspend: Optional[Dict[str, Any]] = None,
1738
+ cache_config: Optional[int] = None,
1739
+ enable_kai: Optional[bool] = None,
1740
+ wait_on_active: bool = False,
1741
+ wait_interval: int = 10,
1742
+ wait_timeout: int = 600,
1584
1743
  ) -> Workspace:
1585
1744
  """
1586
1745
  Create a new workspace.
@@ -1593,6 +1752,15 @@ class WorkspaceManager(Manager):
1593
1752
  The workspace ID of the workspace
1594
1753
  size : str, optional
1595
1754
  Workspace size in workspace size notation (S-00, S-1, etc.)
1755
+ auto_suspend : Dict[str, Any], optional
1756
+ Auto suspend settings for the workspace. If this field is not
1757
+ provided, no settings will be enabled.
1758
+ cache_config : int, optional
1759
+ Specifies the multiplier for the persistent cache associated
1760
+ with the workspace. If specified, it enables the cache configuration
1761
+ multiplier. It can have one of the following values: 1, 2, or 4.
1762
+ enable_kai : bool, optional
1763
+ Whether to create a SingleStore Kai-enabled workspace
1596
1764
  wait_on_active : bool, optional
1597
1765
  Wait for the workspace to be active before returning
1598
1766
  wait_timeout : int, optional
@@ -1610,14 +1778,20 @@ class WorkspaceManager(Manager):
1610
1778
  workspace_group = workspace_group.id
1611
1779
  res = self._post(
1612
1780
  'workspaces', json=dict(
1613
- name=name, workspaceGroupID=workspace_group,
1781
+ name=name,
1782
+ workspaceGroupID=workspace_group,
1614
1783
  size=size,
1784
+ autoSuspend=snake_to_camel_dict(auto_suspend),
1785
+ cacheConfig=cache_config,
1786
+ enableKai=enable_kai,
1615
1787
  ),
1616
1788
  )
1617
1789
  out = self.get_workspace(res.json()['workspaceID'])
1618
1790
  if wait_on_active:
1619
1791
  out = self._wait_on_state(
1620
- out, 'Active', interval=wait_interval,
1792
+ out,
1793
+ 'Active',
1794
+ interval=wait_interval,
1621
1795
  timeout=wait_timeout,
1622
1796
  )
1623
1797
  return out
@@ -29,12 +29,28 @@ from .cursors import (
29
29
  DictCursorSV,
30
30
  NamedtupleCursor,
31
31
  NamedtupleCursorSV,
32
+ ArrowCursor,
33
+ ArrowCursorSV,
34
+ NumpyCursor,
35
+ NumpyCursorSV,
36
+ PandasCursor,
37
+ PandasCursorSV,
38
+ PolarsCursor,
39
+ PolarsCursorSV,
32
40
  SSCursor,
33
41
  SSCursorSV,
34
42
  SSDictCursor,
35
43
  SSDictCursorSV,
36
44
  SSNamedtupleCursor,
37
45
  SSNamedtupleCursorSV,
46
+ SSArrowCursor,
47
+ SSArrowCursorSV,
48
+ SSNumpyCursor,
49
+ SSNumpyCursorSV,
50
+ SSPandasCursor,
51
+ SSPandasCursorSV,
52
+ SSPolarsCursor,
53
+ SSPolarsCursorSV,
38
54
  )
39
55
  from .optionfile import Parser
40
56
  from .protocol import (
@@ -443,6 +459,14 @@ class Connection(BaseConnection):
443
459
  self.cursorclass = DictCursor
444
460
  elif 'namedtuple' in self.results_type:
445
461
  self.cursorclass = NamedtupleCursor
462
+ elif 'numpy' in self.results_type:
463
+ self.cursorclass = NumpyCursor
464
+ elif 'arrow' in self.results_type:
465
+ self.cursorclass = ArrowCursor
466
+ elif 'pandas' in self.results_type:
467
+ self.cursorclass = PandasCursor
468
+ elif 'polars' in self.results_type:
469
+ self.cursorclass = PolarsCursor
446
470
  else:
447
471
  self.cursorclass = Cursor
448
472
  else:
@@ -450,6 +474,14 @@ class Connection(BaseConnection):
450
474
  self.cursorclass = SSDictCursor
451
475
  elif 'namedtuple' in self.results_type:
452
476
  self.cursorclass = SSNamedtupleCursor
477
+ elif 'numpy' in self.results_type:
478
+ self.cursorclass = SSNumpyCursor
479
+ elif 'arrow' in self.results_type:
480
+ self.cursorclass = SSArrowCursor
481
+ elif 'pandas' in self.results_type:
482
+ self.cursorclass = SSPandasCursor
483
+ elif 'polars' in self.results_type:
484
+ self.cursorclass = SSPolarsCursor
453
485
  else:
454
486
  self.cursorclass = SSCursor
455
487
 
@@ -487,6 +519,30 @@ class Connection(BaseConnection):
487
519
  elif self.cursorclass is SSNamedtupleCursor:
488
520
  self.cursorclass = SSNamedtupleCursorSV
489
521
  self.results_type = 'namedtuples'
522
+ elif self.cursorclass is NumpyCursor:
523
+ self.cursorclass = NumpyCursorSV
524
+ self.results_type = 'numpy'
525
+ elif self.cursorclass is SSNumpyCursor:
526
+ self.cursorclass = SSNumpyCursorSV
527
+ self.results_type = 'numpy'
528
+ elif self.cursorclass is ArrowCursor:
529
+ self.cursorclass = ArrowCursorSV
530
+ self.results_type = 'arrow'
531
+ elif self.cursorclass is SSArrowCursor:
532
+ self.cursorclass = SSArrowCursorSV
533
+ self.results_type = 'arrow'
534
+ elif self.cursorclass is PandasCursor:
535
+ self.cursorclass = PandasCursorSV
536
+ self.results_type = 'pandas'
537
+ elif self.cursorclass is SSPandasCursor:
538
+ self.cursorclass = SSPandasCursorSV
539
+ self.results_type = 'pandas'
540
+ elif self.cursorclass is PolarsCursor:
541
+ self.cursorclass = PolarsCursorSV
542
+ self.results_type = 'polars'
543
+ elif self.cursorclass is SSPolarsCursor:
544
+ self.cursorclass = SSPolarsCursorSV
545
+ self.results_type = 'polars'
490
546
 
491
547
  self._result = None
492
548
  self._affected_rows = 0
@@ -498,9 +554,22 @@ class Connection(BaseConnection):
498
554
  if conv is None:
499
555
  conv = converters.conversions
500
556
 
557
+ conv = conv.copy()
558
+
501
559
  self.parse_json = parse_json
502
560
  self.invalid_values = (invalid_values or {}).copy()
503
561
 
562
+ # Disable JSON parsing for Arrow
563
+ if self.results_type in ['arrow']:
564
+ conv[245] = None
565
+ self.parse_json = False
566
+
567
+ # Disable date/time parsing for polars; let polars do the parsing
568
+ elif self.results_type in ['polars']:
569
+ conv[7] = None
570
+ conv[10] = None
571
+ conv[12] = None
572
+
504
573
  # Need for MySQLdb compatibility.
505
574
  self.encoders = {k: v for (k, v) in conv.items() if type(k) is not int}
506
575
  self.decoders = {k: v for (k, v) in conv.items() if type(k) is int}