singlestoredb 0.9.2__cp36-abi3-win_amd64.whl → 0.9.3__cp36-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__ = '0.9.2'
16
+ __version__ = '0.9.3'
17
17
 
18
18
  from .alchemy import create_engine
19
19
  from .config import options, get_option, set_option, describe_option
@@ -21,8 +21,8 @@ from ..connection import Connection
21
21
 
22
22
  CORE_GRAMMAR = r'''
23
23
  ws = ~r"(\s*(/\*.*\*/)*\s*)*"
24
- qs = ~r"\"([^\"]*)\"|'([^\']*)'"
25
- number = ~r"-?\d+(\.\d+)?|-?\.d+"
24
+ qs = ~r"\"([^\"]*)\"|'([^\']*)'|`([^\`]*)`|(\S+)"
25
+ number = ~r"[-+]?(\d*\.)?\d+(e[-+]?\d+)?"i
26
26
  integer = ~r"-?\d+"
27
27
  comma = ws "," ws
28
28
  open_paren = ws "(" ws
@@ -32,10 +32,10 @@ CORE_GRAMMAR = r'''
32
32
 
33
33
  def get_keywords(grammar: str) -> Tuple[str, ...]:
34
34
  """Return all all-caps words from the beginning of the line."""
35
- m = re.match(r'^\s*([A-Z0-9_]+(\s+|$))+', grammar)
35
+ m = re.match(r'^\s*([A-Z0-9_]+(\s+|$|;))+', grammar)
36
36
  if not m:
37
37
  return tuple()
38
- return tuple(re.split(r'\s+', m.group(0).strip()))
38
+ return tuple(re.split(r'\s+', m.group(0).replace(';', '').strip()))
39
39
 
40
40
 
41
41
  def process_optional(m: Any) -> str:
@@ -322,6 +322,7 @@ class SQLHandler(NodeVisitor):
322
322
  #: Rule validation functions
323
323
  validators: Dict[str, Callable[..., Any]] = {}
324
324
 
325
+ _grammar: str = CORE_GRAMMAR
325
326
  _is_compiled: bool = False
326
327
 
327
328
  def __init__(self, connection: Connection):
@@ -347,6 +348,7 @@ class SQLHandler(NodeVisitor):
347
348
  cls.grammar, cls.command_key, cls.rule_info, cls.help = \
348
349
  process_grammar(grammar or cls.__doc__ or '')
349
350
 
351
+ cls._grammar = grammar or cls.__doc__ or ''
350
352
  cls._is_compiled = True
351
353
 
352
354
  def create_result(self) -> result.FusionSQLResult:
@@ -384,10 +386,15 @@ class SQLHandler(NodeVisitor):
384
386
  """
385
387
  type(self).compile()
386
388
  try:
387
- res = self.run(self.visit(type(self).grammar.parse(sql)))
389
+ params = self.visit(type(self).grammar.parse(sql))
390
+ for k, v in params.items():
391
+ params[k] = self.validate_rule(k, v)
392
+ res = self.run(params)
388
393
  if res is not None:
389
394
  return res
390
- return result.FusionSQLResult(self.connection)
395
+ res = result.FusionSQLResult(self.connection)
396
+ res.set_rows([])
397
+ return res
391
398
  except ParseError as exc:
392
399
  s = str(exc)
393
400
  msg = ''
@@ -421,7 +428,7 @@ class SQLHandler(NodeVisitor):
421
428
  """
422
429
  raise NotImplementedError
423
430
 
424
- def create_like_func(self, like: str) -> Callable[[str], bool]:
431
+ def create_like_func(self, like: Optional[str]) -> Callable[[str], bool]:
425
432
  """
426
433
  Construct a function to apply the LIKE clause.
427
434
 
@@ -457,7 +464,16 @@ class SQLHandler(NodeVisitor):
457
464
  """Quoted strings."""
458
465
  if node is None:
459
466
  return None
460
- return node.match.group(1) or node.match.group(2)
467
+ return node.match.group(1) or node.match.group(2) or \
468
+ node.match.group(3) or node.match.group(4)
469
+
470
+ def visit_number(self, node: Node, visited_children: Iterable[Any]) -> Any:
471
+ """Numeric value."""
472
+ return float(node.match.group(0))
473
+
474
+ def visit_integer(self, node: Node, visited_children: Iterable[Any]) -> Any:
475
+ """Integer value."""
476
+ return int(node.match.group(0))
461
477
 
462
478
  def visit_ws(self, node: Node, visited_children: Iterable[Any]) -> Any:
463
479
  """Whitespace and comments."""
@@ -505,13 +521,10 @@ class SQLHandler(NodeVisitor):
505
521
  # Filter out stray empty strings
506
522
  out = [x for x in flatten(visited_children)[n_keywords:] if x]
507
523
 
508
- if repeats:
509
- return {node.expr_name: self.validate_rule(node.expr_name, out)}
524
+ if repeats or len(out) > 1:
525
+ return {node.expr_name: out}
510
526
 
511
- return {
512
- node.expr_name:
513
- self.validate_rule(node.expr_name, out[0]) if out else True,
514
- }
527
+ return {node.expr_name: out[0] if out else True}
515
528
 
516
529
  if hasattr(node, 'match'):
517
530
  if not visited_children and not node.match.groups():
@@ -3,7 +3,9 @@ import os
3
3
  import re
4
4
  from typing import Any
5
5
  from typing import Dict
6
+ from typing import List
6
7
  from typing import Optional
8
+ from typing import Tuple
7
9
  from typing import Type
8
10
  from typing import Union
9
11
 
@@ -110,3 +112,56 @@ def execute(
110
112
  raise RuntimeError(f'could not find handler for query: {sql}')
111
113
 
112
114
  return handler(connection).execute(sql)
115
+
116
+
117
+ class ShowFusionCommandsHandler(SQLHandler):
118
+ """
119
+ SHOW FUSION COMMANDS [ like ];
120
+
121
+ # LIKE pattern
122
+ like = LIKE '<pattern>'
123
+
124
+ """
125
+
126
+ def run(self, params: Dict[str, Any]) -> Optional[result.FusionSQLResult]:
127
+ res = self.create_result()
128
+ res.add_field('Command', result.STRING)
129
+
130
+ is_like = self.create_like_func(params.get('like'))
131
+
132
+ data: List[Tuple[Any, ...]] = []
133
+ for _, v in sorted(_handlers.items()):
134
+ if v is type(self):
135
+ continue
136
+ if is_like(' '.join(v.command_key)):
137
+ data.append((v.help,))
138
+
139
+ res.set_rows(data)
140
+
141
+ return res
142
+
143
+
144
+ ShowFusionCommandsHandler.register()
145
+
146
+
147
+ class ShowFusionGrammarHandler(SQLHandler):
148
+ """
149
+ SHOW FUSION GRAMMAR for_query;
150
+
151
+ # Query to show grammar for
152
+ for_query = FOR '<query>'
153
+
154
+ """
155
+
156
+ def run(self, params: Dict[str, Any]) -> Optional[result.FusionSQLResult]:
157
+ res = self.create_result()
158
+ res.add_field('Grammar', result.STRING)
159
+ handler = get_handler(params['for_query'])
160
+ data: List[Tuple[Any, ...]] = []
161
+ if handler is not None:
162
+ data.append((handler._grammar,))
163
+ res.set_rows(data)
164
+ return res
165
+
166
+
167
+ ShowFusionGrammarHandler.register()
@@ -543,7 +543,7 @@ class Cursor(connection.Cursor):
543
543
  # precision, scale, null_ok, column_flags, charset)
544
544
 
545
545
  # Remove converters for things the JSON parser already converted
546
- http_converters = dict(converters)
546
+ http_converters = dict(self._connection.decoders)
547
547
  http_converters.pop(4, None)
548
548
  http_converters.pop(5, None)
549
549
  http_converters.pop(6, None)
@@ -955,6 +955,9 @@ class Connection(connection.Connection):
955
955
  version = kwargs.get('version', 'v2')
956
956
  self.driver = kwargs.get('driver', 'https')
957
957
 
958
+ self.encoders = {k: v for (k, v) in converters.items() if type(k) is not int}
959
+ self.decoders = {k: v for (k, v) in converters.items() if type(k) is int}
960
+
958
961
  self._database = kwargs.get('database', get_option('database'))
959
962
  self._url = f'{self.driver}://{host}:{port}/api/{version}/'
960
963
  self._messages: List[Tuple[int, str]] = []
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env python
2
+ # type: ignore
3
+ """SingleStoreDB Fusion testing."""
4
+ import os
5
+ import unittest
6
+
7
+ import singlestoredb as s2
8
+ from singlestoredb.tests import utils
9
+
10
+
11
+ class TestFusion(unittest.TestCase):
12
+
13
+ dbname: str = ''
14
+ dbexisted: bool = False
15
+
16
+ @classmethod
17
+ def setUpClass(cls):
18
+ sql_file = os.path.join(os.path.dirname(__file__), 'test.sql')
19
+ cls.dbname, cls.dbexisted = utils.load_sql(sql_file)
20
+
21
+ @classmethod
22
+ def tearDownClass(cls):
23
+ if not cls.dbexisted:
24
+ utils.drop_database(cls.dbname)
25
+
26
+ def setUp(self):
27
+ self.enabled = os.environ.get('SINGLESTOREDB_ENABLE_FUSION')
28
+ os.environ['SINGLESTOREDB_ENABLE_FUSION'] = '1'
29
+ self.conn = s2.connect(database=type(self).dbname, local_infile=True)
30
+ self.cur = self.conn.cursor()
31
+
32
+ def tearDown(self):
33
+ if self.enabled:
34
+ os.environ['SINGLESTOREDB_ENABLE_FUSION'] = self.enabled
35
+ else:
36
+ del os.environ['SINGLESTOREDB_ENABLE_FUSION']
37
+
38
+ try:
39
+ if self.cur is not None:
40
+ self.cur.close()
41
+ except Exception:
42
+ # traceback.print_exc()
43
+ pass
44
+
45
+ try:
46
+ if self.conn is not None:
47
+ self.conn.close()
48
+ except Exception:
49
+ # traceback.print_exc()
50
+ pass
51
+
52
+ def test_env_var(self):
53
+ os.environ['SINGLESTOREDB_ENABLE_FUSION'] = '0'
54
+
55
+ with self.assertRaises(s2.ProgrammingError):
56
+ self.cur.execute('show fusion commands')
57
+
58
+ del os.environ['SINGLESTOREDB_ENABLE_FUSION']
59
+
60
+ with self.assertRaises(s2.ProgrammingError):
61
+ self.cur.execute('show fusion commands')
62
+
63
+ os.environ['SINGLESTOREDB_ENABLE_FUSION'] = 'yes'
64
+
65
+ self.cur.execute('show fusion commands')
66
+ assert list(self.cur)
67
+
68
+ def test_show_commands(self):
69
+ self.cur.execute('show fusion commands')
70
+ cmds = [x[0] for x in self.cur.fetchall()]
71
+ assert cmds
72
+ assert [x for x in cmds if x.strip().startswith('SHOW FUSION GRAMMAR')], cmds
73
+
74
+ self.cur.execute('show fusion commands like "create%"')
75
+ cmds = [x[0] for x in self.cur.fetchall()]
76
+ assert cmds
77
+ assert [x for x in cmds if x.strip().startswith('CREATE')] == cmds, cmds
78
+
79
+ def test_show_grammar(self):
80
+ self.cur.execute('show fusion grammar for "create workspace"')
81
+ cmds = [x[0] for x in self.cur.fetchall()]
82
+ assert cmds
83
+ assert [x for x in cmds if x.strip().startswith('CREATE WORKSPACE')], cmds
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python
2
2
  # type: ignore
3
- """SingleStoreDB HTTP connection testing."""
3
+ """SingleStoreDB Management API testing."""
4
4
  import os
5
5
  import pathlib
6
6
  import random
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: singlestoredb
3
- Version: 0.9.2
3
+ Version: 0.9.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,5 +1,5 @@
1
- _singlestoredb_accel.pyd,sha256=XsmhxHVwW13ZYLgfK4S3Tm5n6qk9xVsYp9p44d8953k,37376
2
- singlestoredb/__init__.py,sha256=9rGI34yrB6tPF6m8t6cpWfnimKnzT2X_cUu5wo3IOss,909
1
+ _singlestoredb_accel.pyd,sha256=oVCTUXoHbcAJhDASVeczCSA1-hWY33z8jk1M7AlvKxI,37376
2
+ singlestoredb/__init__.py,sha256=uPSaY4xDxpO0orU6aqssT93B24ItTyVzGvhv4tgZSOc,909
3
3
  singlestoredb/auth.py,sha256=RmYiH0Wlc2RXc4pTlRMysxtBI445ggCIwojWKC_eDLE,7844
4
4
  singlestoredb/config.py,sha256=-n8HA5_KlwFxcOnfqnLobDbIA43sMlLiVr-YmvtG3a0,7397
5
5
  singlestoredb/connection.py,sha256=XeuKeM0ihbF1QIlDn2AxnJfT5d-RNCch56q0z3dn9g8,45409
@@ -16,13 +16,13 @@ singlestoredb/functions/ext/asgi.py,sha256=LFrcZL2R7sgXflWqx-wcCYRIlivywqBg1joDr
16
16
  singlestoredb/functions/ext/json.py,sha256=7dncClZrC1X42GbKzVgV5jgExdbI7GQq0BGSDB9NuTM,1107
17
17
  singlestoredb/functions/ext/rowdat_1.py,sha256=70KSVL7E2842uMWOa-pygbLFd8GyZqOviEFwFacadDs,3296
18
18
  singlestoredb/fusion/__init__.py,sha256=FHWtrg6OJFTf6Ye197V5sU6ssryr2h6FBcDIgXP7-H4,367
19
- singlestoredb/fusion/handler.py,sha256=F6X4bSdYy870XXQVucXwNeaRdnWGyOvIf53ucg-uVPE,16140
20
- singlestoredb/fusion/registry.py,sha256=uL2Myucxlw6m6jfVq4oWiNW0nuL1ZLIwMdrKgqwXzuM,3060
19
+ singlestoredb/fusion/handler.py,sha256=bJRJFX-j70J3aSfAaeX38AkfV_WlwL-wWU--T5JBYjc,16725
20
+ singlestoredb/fusion/registry.py,sha256=0suBgQ87A85sCZWGWlzBoIIZxbcL18wnrt280w01qJU,4433
21
21
  singlestoredb/fusion/result.py,sha256=K5WOm4_COuWXo-YxL0wjodfLhjO_X5Fdp34TrX9_FZI,4019
22
22
  singlestoredb/fusion/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  singlestoredb/fusion/handlers/workspace.py,sha256=PLxIM0747WN7tbQ_QMxQG_YvSSL_UqCoijMFwH2xfuA,10893
24
24
  singlestoredb/http/__init__.py,sha256=4cEDvLloGc3LSpU-PnIwacyu0n5oIIIE6xk2SPyWD_w,939
25
- singlestoredb/http/connection.py,sha256=1PWiP0rD-uj224Lzt6tKLfpWPWeq-u6YvXwRp1S9nbU,35072
25
+ singlestoredb/http/connection.py,sha256=uVbHgjcU28uHf4sMpJD8UIqzcFVPmJQAcE_ikDTr_GQ,35259
26
26
  singlestoredb/management/__init__.py,sha256=pRxBjzZxNjnuAtBlv4WwYZF-2Z3dbrKoy5XilJRXT2w,102
27
27
  singlestoredb/management/billing_usage.py,sha256=0UHFSPCrN0nyeGFFM-HXS3NP8pYmYo2BCCahDEPXvzg,3883
28
28
  singlestoredb/management/cluster.py,sha256=dqozXaM8kneKTFlUg92gjw6oIT6sPsoYWwJ8aefsVCo,14611
@@ -80,8 +80,9 @@ singlestoredb/tests/test_config.py,sha256=Ad0PDmCnJMOyy9f7WTKiRasSR_3mYRByUlSb7k
80
80
  singlestoredb/tests/test_connection.py,sha256=0GRvsvUz8G2I5ah0lHI97XUVv6UI13A1D5UNHk7RRmc,52215
81
81
  singlestoredb/tests/test_dbapi.py,sha256=cNJoTEZvYG7ckcwT7xqlkJX-2TDEYGTDDU1Igucp48k,679
82
82
  singlestoredb/tests/test_exceptions.py,sha256=vscMYmdOJr0JmkTAJrNI2w0Q96Nfugjkrt5_lYnw8i0,1176
83
+ singlestoredb/tests/test_fusion.py,sha256=g7sLQUJgHRDe48SWDfFPrx0onbh4qAVjQ_sEp8-VGBs,2624
83
84
  singlestoredb/tests/test_http.py,sha256=7hwXe61hlUes3nji0MTTZweo94tJAlJ-vA5ct9geXFQ,8868
84
- singlestoredb/tests/test_management.py,sha256=XSYmKBEyRz_mLRiJyx1ntlK-95ivuQnB9D9j0MeRrWs,26513
85
+ singlestoredb/tests/test_management.py,sha256=jvT38o-nYGmzk260NS8j9Bit2kBv24CSloG3CJmcQVs,26512
85
86
  singlestoredb/tests/test_results.py,sha256=Zg1ynZFRZqalAMfNLOU5C6BDXaox6JxrKm_XZwVNFcg,6753
86
87
  singlestoredb/tests/test_types.py,sha256=YeVE6KPqlqzJke-4hbRmc8ko1E7RLHu5S8qLg04Bl5Y,4632
87
88
  singlestoredb/tests/test_udf.py,sha256=6fGNQELY6KKvUUUmi6StTGw-jZUMGrVXTpfZf61bwFw,29562
@@ -94,8 +95,8 @@ singlestoredb/utils/debug.py,sha256=y7dnJeJGt3U_BWXz9pLt1qNQREpPtumYX_sk1DiqG6Y,
94
95
  singlestoredb/utils/mogrify.py,sha256=gCcn99-vgsGVjTUV7RHJ6hH4vCNrsGB_Xo4z8kiSPDQ,4201
95
96
  singlestoredb/utils/results.py,sha256=ely2XVAHHejObjLibS3UcrPOuCO2g5aRtA3PxAMtE-g,5432
96
97
  singlestoredb/utils/xdict.py,sha256=-wi1lSPTnY99fhVMBhPKJ8cCsQhNG4GMUfkEBDKYgCw,13321
97
- singlestoredb-0.9.2.dist-info/LICENSE,sha256=Bojenzui8aPNjlF3w4ojguDP7sTf8vFV_9Gc2UAG1sg,11542
98
- singlestoredb-0.9.2.dist-info/METADATA,sha256=1psiVY-gct4A569NxnKOvAWdPv5bHkTPHt9dR-yynXo,7793
99
- singlestoredb-0.9.2.dist-info/WHEEL,sha256=CFPxCuvaTIZS0h5c8o2xFStPFn1i6Rraxc2uR61QpoA,100
100
- singlestoredb-0.9.2.dist-info/top_level.txt,sha256=SDtemIXf-Kp-_F2f_S6x0db33cHGOILdAEsIQZe2LZc,35
101
- singlestoredb-0.9.2.dist-info/RECORD,,
98
+ singlestoredb-0.9.3.dist-info/LICENSE,sha256=Bojenzui8aPNjlF3w4ojguDP7sTf8vFV_9Gc2UAG1sg,11542
99
+ singlestoredb-0.9.3.dist-info/METADATA,sha256=3Kv3yUR-JCqYGCvlmCsSX5MJdhG4lvh8tGpnfetigXI,7793
100
+ singlestoredb-0.9.3.dist-info/WHEEL,sha256=CFPxCuvaTIZS0h5c8o2xFStPFn1i6Rraxc2uR61QpoA,100
101
+ singlestoredb-0.9.3.dist-info/top_level.txt,sha256=SDtemIXf-Kp-_F2f_S6x0db33cHGOILdAEsIQZe2LZc,35
102
+ singlestoredb-0.9.3.dist-info/RECORD,,