singlestoredb 1.12.2__cp38-abi3-win32.whl → 1.12.3__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.

_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.3'
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)
@@ -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,68 @@ 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
+ with s2.connect(database=type(self).dbname) as conn:
1312
+ with conn.cursor() as cur:
1313
+ cur.execute('''
1314
+ select json_extract_string('{"foo":"😀"}', "bar");
1315
+ ''')
1316
+
1317
+ if 'http' in self.conn.driver:
1318
+ self.skipTest('Charset is not use in HTTP interface')
1319
+
1320
+ with self.assertRaises(s2.OperationalError):
1321
+ with s2.connect(database=type(self).dbname, charset='utf8') as conn:
1322
+ with conn.cursor() as cur:
1323
+ cur.execute('''
1324
+ select json_extract_string('{"foo":"😀"}', "bar");
1325
+ ''')
1326
+
1258
1327
 
1259
1328
  if __name__ == '__main__':
1260
1329
  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.3
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=zBjpJVx1B1-TIKJDzJbgC0SWvwJPXqVKsHk0pj1oDYc,61440
2
- singlestoredb/__init__.py,sha256=dlGP3oKt-x7HySro64o0v_fGXAnosKaQsSoDYQc42mo,1712
1
+ _singlestoredb_accel.pyd,sha256=OpnFhIc45QCOH-rhsmVoomDaPUZitjBn_cd39ae1bGE,60928
2
+ singlestoredb/__init__.py,sha256=Mt5lSYU33x17JRX_uk7ftkZ8RmWnyWINacQdbCFPSxY,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
@@ -64,7 +64,7 @@ singlestoredb/mysql/_auth.py,sha256=YaqqyvAHmeraBv3BM207rNveUVPM-mPnW20ts_ynVWg,
64
64
  singlestoredb/mysql/charset.py,sha256=mnCdMpvdub1S2mm2PSk2j5JddgsWRjsVLtGx-y9TskE,10724
65
65
  singlestoredb/mysql/connection.py,sha256=Dlam7wNSfn4jVBNrqdvxLzwxJqCQUzuu_rlcKU45MB0,75113
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=7JZdyudRaW3ZJkQ-m21ZstFlHz1Fyw2eSfN7y_zEhpU,49703
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=c4k7z5HB0t-y0nBCv6KyJ6KCjn8SEGPddD0lhaPtU3E,96
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.3.dist-info/LICENSE,sha256=Bojenzui8aPNjlF3w4ojguDP7sTf8vFV_9Gc2UAG1sg,11542
145
+ singlestoredb-1.12.3.dist-info/METADATA,sha256=f8Qx8NA3HZiI2rGrFk1g8d41iXhAHaiEVww6DMtDixM,5778
146
+ singlestoredb-1.12.3.dist-info/WHEEL,sha256=c4k7z5HB0t-y0nBCv6KyJ6KCjn8SEGPddD0lhaPtU3E,96
147
+ singlestoredb-1.12.3.dist-info/entry_points.txt,sha256=bSLaTWB5zGjpVYPAaI46MkkDup0su-eb3uAhCNYuRV0,48
148
+ singlestoredb-1.12.3.dist-info/top_level.txt,sha256=lA65Vf4qAMfg_s1oG3LEO90h4t1Z-SPDbRqkevI3bSY,40
149
+ singlestoredb-1.12.3.dist-info/RECORD,,