singlestoredb 1.12.2__cp38-abi3-win_amd64.whl → 1.12.4__cp38-abi3-win_amd64.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_accel.pyd CHANGED
Binary file
singlestoredb/__init__.py CHANGED
@@ -13,7 +13,7 @@ Examples
13
13
 
14
14
  """
15
15
 
16
- __version__ = '1.12.2'
16
+ __version__ = '1.12.4'
17
17
 
18
18
  from typing import Any
19
19
 
singlestoredb/config.py CHANGED
@@ -80,7 +80,7 @@ register_option(
80
80
  )
81
81
 
82
82
  register_option(
83
- 'charset', 'string', check_str, 'utf8',
83
+ 'charset', 'string', check_str, 'utf8mb4',
84
84
  'Specifies the character set for the session.',
85
85
  environ='SINGLESTOREDB_CHARSET',
86
86
  )
@@ -69,6 +69,12 @@ try:
69
69
  except ImportError:
70
70
  has_cloudpickle = False
71
71
 
72
+ try:
73
+ from pydantic import BaseModel
74
+ has_pydantic = True
75
+ except ImportError:
76
+ has_pydantic = False
77
+
72
78
 
73
79
  logger = utils.get_logger('singlestoredb.functions.ext.asgi')
74
80
 
@@ -138,13 +144,24 @@ def get_func_names(funcs: str) -> List[Tuple[str, str]]:
138
144
 
139
145
 
140
146
  def as_tuple(x: Any) -> Any:
141
- if hasattr(x, 'model_fields'):
142
- return tuple(x.model_fields.values())
147
+ """Convert object to tuple."""
148
+ if has_pydantic and isinstance(x, BaseModel):
149
+ return tuple(x.model_dump().values())
143
150
  if dataclasses.is_dataclass(x):
144
151
  return dataclasses.astuple(x)
145
152
  return x
146
153
 
147
154
 
155
+ def as_list_of_tuples(x: Any) -> Any:
156
+ """Convert object to a list of tuples."""
157
+ if isinstance(x, (list, tuple)) and len(x) > 0:
158
+ if has_pydantic and isinstance(x[0], BaseModel):
159
+ return [tuple(y.model_dump().values()) for y in x]
160
+ if dataclasses.is_dataclass(x[0]):
161
+ return [dataclasses.astuple(y) for y in x]
162
+ return x
163
+
164
+
148
165
  def make_func(
149
166
  name: str,
150
167
  func: Callable[..., Any],
@@ -183,7 +200,7 @@ def make_func(
183
200
  out_ids: List[int] = []
184
201
  out = []
185
202
  for i, res in zip(row_ids, func_map(func, rows)):
186
- out.extend(as_tuple(res))
203
+ out.extend(as_list_of_tuples(res))
187
204
  out_ids.extend([row_ids[i]] * (len(out)-len(out_ids)))
188
205
  return out_ids, out
189
206
 
@@ -6,6 +6,8 @@ import numbers
6
6
  import os
7
7
  import re
8
8
  import string
9
+ import sys
10
+ import types
9
11
  import typing
10
12
  from typing import Any
11
13
  from typing import Callable
@@ -32,6 +34,11 @@ except ImportError:
32
34
  from . import dtypes as dt
33
35
  from ..mysql.converters import escape_item # type: ignore
34
36
 
37
+ if sys.version_info >= (3, 10):
38
+ _UNION_TYPES = {typing.Union, types.UnionType}
39
+ else:
40
+ _UNION_TYPES = {typing.Union}
41
+
35
42
 
36
43
  array_types: Tuple[Any, ...]
37
44
 
@@ -211,7 +218,7 @@ def simplify_dtype(dtype: Any) -> List[Any]:
211
218
  args = []
212
219
 
213
220
  # Flatten Unions
214
- if origin is Union:
221
+ if origin in _UNION_TYPES:
215
222
  for x in typing.get_args(dtype):
216
223
  args.extend(simplify_dtype(x))
217
224
 
@@ -43,6 +43,12 @@ try:
43
43
  except ImportError:
44
44
  has_shapely = False
45
45
 
46
+ try:
47
+ import pydantic
48
+ has_pydantic = True
49
+ except ImportError:
50
+ has_pydantic = False
51
+
46
52
  from .. import connection
47
53
  from .. import fusion
48
54
  from .. import types
@@ -533,6 +539,9 @@ class Cursor(connection.Cursor):
533
539
  self._expect_results = True
534
540
  sql_type = 'query'
535
541
 
542
+ if has_pydantic and isinstance(params, pydantic.BaseModel):
543
+ params = params.model_dump()
544
+
536
545
  self._validate_param_subs(oper, params)
537
546
 
538
547
  handler = fusion.get_handler(oper)
@@ -989,18 +989,11 @@ class Connection(BaseConnection):
989
989
 
990
990
  def set_character_set(self, charset, collation=None):
991
991
  """
992
- Set session charaset (and collation) on the server.
992
+ Set charaset (and collation) on the server.
993
993
 
994
- Send "SET [COLLATION|CHARACTER_SET]_SERVER = [collation|charset]" query.
994
+ Send "SET NAMES charset [COLLATE collation]" query.
995
995
  Update Connection.encoding based on charset.
996
996
 
997
- If charset/collation are being set to utf8mb4, the corresponding global
998
- variables (COLLATION_SERVER and CHARACTER_SET_SERVER) must be also set
999
- to utf8mb4. This is true by default for SingleStore 8.7+. For previuous
1000
- versions or non-default setting user must manully run the query
1001
- `SET global collation_connection = utf8mb4_general_ci`
1002
- replacing utf8mb4_general_ci with {collation}.
1003
-
1004
997
  Parameters
1005
998
  ----------
1006
999
  charset : str
@@ -1013,9 +1006,9 @@ class Connection(BaseConnection):
1013
1006
  encoding = charset_by_name(charset).encoding
1014
1007
 
1015
1008
  if collation:
1016
- query = f'SET COLLATION_SERVER={collation}'
1009
+ query = f'SET NAMES {charset} COLLATE {collation}'
1017
1010
  else:
1018
- query = f'SET CHARACTER_SET_SERVER={charset}'
1011
+ query = f'SET NAMES {charset}'
1019
1012
  self._execute_command(COMMAND.COM_QUERY, query)
1020
1013
  self._read_packet()
1021
1014
  self.charset = charset
@@ -1119,6 +1112,19 @@ class Connection(BaseConnection):
1119
1112
  self._get_server_information()
1120
1113
  self._request_authentication()
1121
1114
 
1115
+ # Send "SET NAMES" query on init for:
1116
+ # - Ensure charaset (and collation) is set to the server.
1117
+ # - collation_id in handshake packet may be ignored.
1118
+ # - If collation is not specified, we don't know what is server's
1119
+ # default collation for the charset. For example, default collation
1120
+ # of utf8mb4 is:
1121
+ # - MySQL 5.7, MariaDB 10.x: utf8mb4_general_ci
1122
+ # - MySQL 8.0: utf8mb4_0900_ai_ci
1123
+ #
1124
+ # Reference:
1125
+ # - https://github.com/PyMySQL/PyMySQL/issues/1092
1126
+ # - https://github.com/wagtail/wagtail/issues/9477
1127
+ # - https://zenn.dev/methane/articles/2023-mysql-collation (Japanese)
1122
1128
  self.set_character_set(self.charset, self.collation)
1123
1129
 
1124
1130
  if self.sql_mode is not None:
@@ -8,6 +8,12 @@ from ..utils import results
8
8
  from ..utils.debug import log_query
9
9
  from ..utils.results import get_schema
10
10
 
11
+ try:
12
+ from pydantic import BaseModel
13
+ has_pydantic = True
14
+ except ImportError:
15
+ has_pydantic = False
16
+
11
17
 
12
18
  #: Regular expression for :meth:`Cursor.executemany`.
13
19
  #: executemany only supports simple bulk insert.
@@ -149,6 +155,8 @@ class Cursor(BaseCursor):
149
155
  return tuple(literal(arg) for arg in args)
150
156
  elif dtype is dict or isinstance(args, dict):
151
157
  return {key: literal(val) for (key, val) in args.items()}
158
+ elif has_pydantic and isinstance(args, BaseModel):
159
+ return {key: literal(val) for (key, val) in args.model_dump().items()}
152
160
  # If it's not a dictionary let's try escaping it anyways.
153
161
  # Worst case it will throw a Value error
154
162
  return conn.escape(args)
@@ -6,6 +6,7 @@ import decimal
6
6
  import math
7
7
  import os
8
8
  import unittest
9
+ from typing import Optional
9
10
 
10
11
  from requests.exceptions import InvalidJSONError
11
12
 
@@ -28,6 +29,12 @@ try:
28
29
  except ImportError:
29
30
  has_pygeos = False
30
31
 
32
+ try:
33
+ import pydantic
34
+ has_pydantic = True
35
+ except ImportError:
36
+ has_pydantic = False
37
+
31
38
  import singlestoredb as s2
32
39
  from . import utils
33
40
  # import traceback
@@ -1255,6 +1262,70 @@ class TestBasics(unittest.TestCase):
1255
1262
  except Exception:
1256
1263
  pass
1257
1264
 
1265
+ def test_pydantic(self):
1266
+ if not has_pydantic:
1267
+ self.skipTest('Test requires pydantic')
1268
+
1269
+ tblname = 'foo_' + str(id(self))
1270
+
1271
+ class FooData(pydantic.BaseModel):
1272
+ x: Optional[int]
1273
+ y: Optional[float]
1274
+ z: Optional[str] = None
1275
+
1276
+ self.cur.execute(f'''
1277
+ CREATE TABLE {tblname}(
1278
+ x INT,
1279
+ y DOUBLE,
1280
+ z TEXT
1281
+ )
1282
+ ''')
1283
+
1284
+ self.cur.execute(
1285
+ f'INSERT INTO {tblname}(x, y) VALUES (%(x)s, %(y)s)',
1286
+ FooData(x=2, y=3.23),
1287
+ )
1288
+
1289
+ self.cur.execute('SELECT * FROM ' + tblname)
1290
+
1291
+ assert list(sorted(self.cur.fetchall())) == \
1292
+ list(sorted([(2, 3.23, None)]))
1293
+
1294
+ self.cur.executemany(
1295
+ f'INSERT INTO {tblname}(x) VALUES (%(x)s)',
1296
+ [FooData(x=3, y=3.12), FooData(x=10, y=100.11)],
1297
+ )
1298
+
1299
+ self.cur.execute('SELECT * FROM ' + tblname)
1300
+
1301
+ assert list(sorted(self.cur.fetchall())) == \
1302
+ list(
1303
+ sorted([
1304
+ (2, 3.23, None),
1305
+ (3, None, None),
1306
+ (10, None, None),
1307
+ ]),
1308
+ )
1309
+
1310
+ def test_charset(self):
1311
+ self.skipTest('Skip until charset commands are re-implemented')
1312
+
1313
+ with s2.connect(database=type(self).dbname) as conn:
1314
+ with conn.cursor() as cur:
1315
+ cur.execute('''
1316
+ select json_extract_string('{"foo":"😀"}', "bar");
1317
+ ''')
1318
+
1319
+ if 'http' in self.conn.driver:
1320
+ self.skipTest('Charset is not use in HTTP interface')
1321
+
1322
+ with self.assertRaises(s2.OperationalError):
1323
+ with s2.connect(database=type(self).dbname, charset='utf8') as conn:
1324
+ with conn.cursor() as cur:
1325
+ cur.execute('''
1326
+ select json_extract_string('{"foo":"😀"}', "bar");
1327
+ ''')
1328
+
1258
1329
 
1259
1330
  if __name__ == '__main__':
1260
1331
  import nose2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: singlestoredb
3
- Version: 1.12.2
3
+ Version: 1.12.4
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,7 +1,7 @@
1
- _singlestoredb_accel.pyd,sha256=eIcqHNvo41uHe02n94fJEzSJyXdegzvb1VHa86AULsM,59392
2
- singlestoredb/__init__.py,sha256=dlGP3oKt-x7HySro64o0v_fGXAnosKaQsSoDYQc42mo,1712
1
+ _singlestoredb_accel.pyd,sha256=BjwcTKJQb9p7VofVO-Lrg_BXA6nM4nvVUNyKF9WkU7c,59392
2
+ singlestoredb/__init__.py,sha256=Y3oYr5E9O4QiB6TxEq0HF58H-agjoOb93fc2WyLXPBg,1712
3
3
  singlestoredb/auth.py,sha256=RmYiH0Wlc2RXc4pTlRMysxtBI445ggCIwojWKC_eDLE,7844
4
- singlestoredb/config.py,sha256=5OY9RDlGBrBWAHsGrg0X4v0y_QwNb7G6FSQooMgT8rY,13032
4
+ singlestoredb/config.py,sha256=7-M2c7IAv3B1AmAKizgeNn880TDBbM4gbElLfStejIU,13035
5
5
  singlestoredb/connection.py,sha256=Ty_idVYH50Qx-j8WXy7NeB-DYLAcpdjGYTrTHkKzG9U,47309
6
6
  singlestoredb/converters.py,sha256=6gN3_RzSbw0Aimd5cGgBNPNq1yiHb1a_NK8qC9DmOQ0,21636
7
7
  singlestoredb/exceptions.py,sha256=WCCJrNSsU-hD-621Jpd6bwmvGftQ7byXkk-XKXlaxpg,3354
@@ -22,10 +22,10 @@ singlestoredb/apps/_uvicorn_util.py,sha256=Petkmq5keBPfXZsHBrnZfY3O2rUHvb3Cw6o-B
22
22
  singlestoredb/functions/__init__.py,sha256=Ehyp1pa40cvizzSYNGZ4UP4tiEcyfaxf_LI-oyt-Lro,84
23
23
  singlestoredb/functions/decorator.py,sha256=6c0uIknQNZrN5LAj-mWUw25Bcnl-_dRel6RMDzn2vK8,11816
24
24
  singlestoredb/functions/dtypes.py,sha256=5IwMSaSzxtSowxXrm5hZXW1lpNm6QILxiU4mAUEkBO0,32854
25
- singlestoredb/functions/signature.py,sha256=np4DHtfLM-S38srVu9KzsJZnI7tiwrl0UtMnA8F6rZ0,23162
25
+ singlestoredb/functions/signature.py,sha256=0d1mqH1J0cV7W1NBAqM2C98DWIZomF5qYSS5-T6OW_g,23324
26
26
  singlestoredb/functions/ext/__init__.py,sha256=5ppI8IZN_zOwoJFdu_Oq9ipxtyHw9n6OMVAa_s9T_yY,24
27
27
  singlestoredb/functions/ext/arrow.py,sha256=mQhwaMpvCH_dP92WIhP_j-stu272n4UAHsFUOBTgnq0,9436
28
- singlestoredb/functions/ext/asgi.py,sha256=ENwGjjLxFYjv6HFB5WdX4YT5GSs5sn3mirOLgAM0wTY,44807
28
+ singlestoredb/functions/ext/asgi.py,sha256=TNQlzosguNaM1-Rs1XXO78phav25XdKsbLTFpIvXgRA,45362
29
29
  singlestoredb/functions/ext/json.py,sha256=CROdj37cuJhAZ-CM93EI-SoLb4kxFcMGudsJ5QGyCoI,10831
30
30
  singlestoredb/functions/ext/mmap.py,sha256=zo6eweOFCZp0KIzAeL1vvuSjqvQhE8ybVhHbU0ZICt4,14124
31
31
  singlestoredb/functions/ext/rowdat_1.py,sha256=KYj_y5JWm3_B2-QC47HK-CNOrzujBqGUwLJfE49jwRg,23050
@@ -44,7 +44,7 @@ singlestoredb/fusion/handlers/stage.py,sha256=PP-SSP204lwpmnycSXXSmFPzoN535JVuwg
44
44
  singlestoredb/fusion/handlers/utils.py,sha256=nV2lSzKhv7CzM7I_uIh5kmDV0Ec6VeeKoHczx5pVNcw,11009
45
45
  singlestoredb/fusion/handlers/workspace.py,sha256=NxoEY5xd5lCQmXiim4nhAYCL0agHo1H_rGPpqa31hiw,28397
46
46
  singlestoredb/http/__init__.py,sha256=4cEDvLloGc3LSpU-PnIwacyu0n5oIIIE6xk2SPyWD_w,939
47
- singlestoredb/http/connection.py,sha256=dqXX5SSn6EOV7q0Ehh0E525eLT__B_jJLG-7jgVjbXg,40861
47
+ singlestoredb/http/connection.py,sha256=kLA-LA4zinbNOSemRbGqbTHd3bNn-ucOwmQZa8HIKPI,41075
48
48
  singlestoredb/magics/__init__.py,sha256=fqCBQ0s8o1CYE4Xo_XiSbkLDzLgMNDgpSkOx66-uDZw,1244
49
49
  singlestoredb/magics/run_personal.py,sha256=M11xHi9lWquh_pLSpFI89LGE7PhOPQOGqlSPDl48itE,1900
50
50
  singlestoredb/magics/run_shared.py,sha256=rnKpW4d8CJvD6ehK8jG8FlxuqZvjZl4KocPTsk-23O8,1805
@@ -62,9 +62,9 @@ singlestoredb/management/workspace.py,sha256=D9DzpeWU7xFjpj8bBYiXyasjVYVANeYjTzg
62
62
  singlestoredb/mysql/__init__.py,sha256=CbpwzNUJPAmKPpIobC0-ugBta_RgHCMq7X7N75QLReY,4669
63
63
  singlestoredb/mysql/_auth.py,sha256=YaqqyvAHmeraBv3BM207rNveUVPM-mPnW20ts_ynVWg,8341
64
64
  singlestoredb/mysql/charset.py,sha256=mnCdMpvdub1S2mm2PSk2j5JddgsWRjsVLtGx-y9TskE,10724
65
- singlestoredb/mysql/connection.py,sha256=Dlam7wNSfn4jVBNrqdvxLzwxJqCQUzuu_rlcKU45MB0,75113
65
+ singlestoredb/mysql/connection.py,sha256=sqcwlPopdxPt1wVUTq_1uJ5_CSRxbd_ILSgOCB1z7zQ,75387
66
66
  singlestoredb/mysql/converters.py,sha256=vebFFm6IrC0WgY-5Eh-esaPizY5cq3vDOUlEKGaYM-U,7771
67
- singlestoredb/mysql/cursors.py,sha256=pkrP-1t8IhBJRnYpdM7Rdm-332nOq1RYTDJ_yg_q5HI,27682
67
+ singlestoredb/mysql/cursors.py,sha256=YoZU5_weniqXcoeA0GVSxmetkPYooiDkXMbVBYUNlrU,27942
68
68
  singlestoredb/mysql/err.py,sha256=aDbmfq08gWVmfgIea735wSeiFdvYbB5wusgd3qTVq1s,2480
69
69
  singlestoredb/mysql/optionfile.py,sha256=bz0cZp8tQZvab1iU7OT0yldHyaMVbvAcUJ3TSNwcmyI,675
70
70
  singlestoredb/mysql/protocol.py,sha256=UzHcrv0Pgb1FNofuBTnSxpC9VDkgNbPEbBrRETstxAg,14888
@@ -113,7 +113,7 @@ singlestoredb/tests/test.ipynb,sha256=IEgXbByXyWDplZvod1J2SqNHZiPOGdD4oNVMd0ArP7
113
113
  singlestoredb/tests/test.sql,sha256=winJzhZ2W52PcQ1j8X_NNIDRBmEa-xMAYrS_hoUtAP8,18337
114
114
  singlestoredb/tests/test2.ipynb,sha256=_kBQVvEoinQ1zInNcWFKpbdw-djkLsEO8l3g2MEU_Zs,236
115
115
  singlestoredb/tests/test2.sql,sha256=CEM8_lX189iQU65G3Pod7lig6osfrveQyoDz6HC35YQ,38
116
- singlestoredb/tests/test_basics.py,sha256=tLiR46qUy8-OHHRSHsQTBp5q9NAwNPR9HvfutI6YgnM,47629
116
+ singlestoredb/tests/test_basics.py,sha256=tKzeSN8koMRFq5yjb98Wz5VWAOsnUKAETZEJyLhMD_o,49778
117
117
  singlestoredb/tests/test_config.py,sha256=Ad0PDmCnJMOyy9f7WTKiRasSR_3mYRByUlSb7k5ZySg,11502
118
118
  singlestoredb/tests/test_connection.py,sha256=UmoNo8erkcifEMbHZl83yAaRsyh6HANRdEtY3aViOK8,122792
119
119
  singlestoredb/tests/test_dbapi.py,sha256=cNJoTEZvYG7ckcwT7xqlkJX-2TDEYGTDDU1Igucp48k,679
@@ -141,9 +141,9 @@ singlestoredb/utils/results.py,sha256=wR70LhCqlobniZf52r67zYLBOKjWHQm68NAskdRQND
141
141
  singlestoredb/utils/xdict.py,sha256=-wi1lSPTnY99fhVMBhPKJ8cCsQhNG4GMUfkEBDKYgCw,13321
142
142
  sqlx/__init__.py,sha256=4Sdn8HN-Hf8v0_wCt60DCckCg8BvgM3-9r4YVfZycRE,89
143
143
  sqlx/magic.py,sha256=6VBlotgjautjev599tHaTYOfcfOA9m6gV_-P1_Qc4lI,3622
144
- singlestoredb-1.12.2.dist-info/LICENSE,sha256=Bojenzui8aPNjlF3w4ojguDP7sTf8vFV_9Gc2UAG1sg,11542
145
- singlestoredb-1.12.2.dist-info/METADATA,sha256=cWTppHIaZQ4oy5fvfS_FWlVtfVPcyA2Bk9F1kb9kfgM,5778
146
- singlestoredb-1.12.2.dist-info/WHEEL,sha256=UyMHzmWA0xVqVPKfTiLs2eN3OWWZUl-kQemNbpIqlKo,100
147
- singlestoredb-1.12.2.dist-info/entry_points.txt,sha256=bSLaTWB5zGjpVYPAaI46MkkDup0su-eb3uAhCNYuRV0,48
148
- singlestoredb-1.12.2.dist-info/top_level.txt,sha256=lA65Vf4qAMfg_s1oG3LEO90h4t1Z-SPDbRqkevI3bSY,40
149
- singlestoredb-1.12.2.dist-info/RECORD,,
144
+ singlestoredb-1.12.4.dist-info/LICENSE,sha256=Bojenzui8aPNjlF3w4ojguDP7sTf8vFV_9Gc2UAG1sg,11542
145
+ singlestoredb-1.12.4.dist-info/METADATA,sha256=K1tOPCbyAof-bQelQHIkS3dyPZ5xx-2ckWoKxUamUSs,5778
146
+ singlestoredb-1.12.4.dist-info/WHEEL,sha256=UyMHzmWA0xVqVPKfTiLs2eN3OWWZUl-kQemNbpIqlKo,100
147
+ singlestoredb-1.12.4.dist-info/entry_points.txt,sha256=bSLaTWB5zGjpVYPAaI46MkkDup0su-eb3uAhCNYuRV0,48
148
+ singlestoredb-1.12.4.dist-info/top_level.txt,sha256=lA65Vf4qAMfg_s1oG3LEO90h4t1Z-SPDbRqkevI3bSY,40
149
+ singlestoredb-1.12.4.dist-info/RECORD,,