singlestoredb 1.0.3__cp38-abi3-win_amd64.whl → 1.1.0__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.

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
@@ -45,6 +45,8 @@ BUILTINS = {
45
45
  '<limit>': r'''
46
46
  limit = LIMIT <integer>
47
47
  ''',
48
+ '<integer>': '',
49
+ '<number>': '',
48
50
  }
49
51
 
50
52
  BUILTIN_DEFAULTS = { # type: ignore
@@ -170,8 +172,8 @@ def build_cmd(grammar: str) -> str:
170
172
  return f'{space}{cmd} ={begin}\n{end}'
171
173
 
172
174
 
173
- def build_help(grammar: str) -> str:
174
- """Construct full help syntax."""
175
+ def build_syntax(grammar: str) -> str:
176
+ """Construct full syntax."""
175
177
  if ';' not in grammar:
176
178
  raise ValueError('a semi-colon exist at the end of the primary rule')
177
179
 
@@ -199,8 +201,96 @@ def build_help(grammar: str) -> str:
199
201
  return cmd
200
202
 
201
203
 
204
+ def _format_examples(ex: str) -> str:
205
+ """Convert examples into sections."""
206
+ return re.sub(r'(^Example\s+\d+.*$)', r'### \1', ex, flags=re.M)
207
+
208
+
209
+ def _format_arguments(arg: str) -> str:
210
+ """Format arguments as subsections."""
211
+ out = []
212
+ for line in arg.split('\n'):
213
+ if line.startswith('<'):
214
+ out.append(f'### {line.replace("<", "&lt;").replace(">", "&gt;")}')
215
+ out.append('')
216
+ else:
217
+ out.append(line.strip())
218
+ return '\n'.join(out)
219
+
220
+
221
+ def _to_markdown(txt: str) -> str:
222
+ """Convert formatting to markdown."""
223
+ txt = txt.replace('``', '`')
224
+
225
+ # Format code blocks
226
+ lines = re.split(r'\n', txt)
227
+ out = []
228
+ while lines:
229
+ line = lines.pop(0)
230
+ if line.endswith('::'):
231
+ out.append(line[:-2])
232
+ code = []
233
+ while lines and (not lines[0].strip() or lines[0].startswith(' ')):
234
+ code.append(lines.pop(0).rstrip())
235
+ out.extend(['```sql', '\n'.join(code).rstrip(), '```\n'])
236
+ else:
237
+ out.append(line)
238
+
239
+ return '\n'.join(out)
240
+
241
+
242
+ def build_help(syntax: str, grammar: str) -> str:
243
+ """Build full help text."""
244
+ syntax = re.sub(r'\s*\n+\s*', r' ', syntax.strip())
245
+
246
+ cmd = re.match(r'([A-Z0-9_ ]+)', syntax)
247
+ if not cmd:
248
+ raise ValueError(f'no command found: {syntax}')
249
+
250
+ out = [f'# {cmd.group(1)}\n\n']
251
+
252
+ sections: Dict[str, str] = {}
253
+ grammar = textwrap.dedent(grammar.rstrip())
254
+ desc_re = re.compile(r'^([A-Z][\S ]+)\s*^\-\-\-\-+\s*$', flags=re.M)
255
+ if desc_re.search(grammar):
256
+ _, *txt = desc_re.split(grammar)
257
+ txt = [x.strip() for x in txt]
258
+ sections = {}
259
+ while txt:
260
+ key = txt.pop(0)
261
+ value = txt.pop(0)
262
+ sections[key.lower()] = _to_markdown(value).strip()
263
+
264
+ if 'description' in sections:
265
+ out.extend([sections['description'], '\n\n'])
266
+
267
+ out.extend(['## Syntax\n```sql\n', syntax, '\n```\n\n'])
268
+
269
+ if 'arguments' in sections:
270
+ out.extend([
271
+ '## Arguments\n\n',
272
+ _format_arguments(sections['arguments']),
273
+ '\n\n',
274
+ ])
275
+
276
+ if 'remarks' in sections:
277
+ out.extend(['## Remarks\n', sections['remarks'], '\n\n'])
278
+
279
+ if 'examples' in sections:
280
+ out.extend(['## Examples\n\n', _format_examples(sections['examples']), '\n\n'])
281
+ elif 'example' in sections:
282
+ out.extend(['## Example\n\n', _format_examples(sections['example']), '\n\n'])
283
+
284
+ if 'see also' in sections:
285
+ out.extend(['## See Also\n', sections['see also'], '\n\n'])
286
+
287
+ return ''.join(out).rstrip() + '\n'
288
+
289
+
202
290
  def strip_comments(grammar: str) -> str:
203
291
  """Strip comments from grammar."""
292
+ desc_re = re.compile(r'(^\s*Description\s*^\s*-----------\s*$)', flags=re.M)
293
+ grammar = desc_re.split(grammar, maxsplit=1)[0]
204
294
  return re.sub(r'^\s*#.*$', r'', grammar, flags=re.M)
205
295
 
206
296
 
@@ -226,7 +316,9 @@ def inject_builtins(grammar: str) -> str:
226
316
  return grammar
227
317
 
228
318
 
229
- def process_grammar(grammar: str) -> Tuple[Grammar, Tuple[str, ...], Dict[str, Any], str]:
319
+ def process_grammar(
320
+ grammar: str,
321
+ ) -> Tuple[Grammar, Tuple[str, ...], Dict[str, Any], str, str]:
230
322
  """
231
323
  Convert SQL grammar to a Parsimonious grammar.
232
324
 
@@ -247,10 +339,12 @@ def process_grammar(grammar: str) -> Tuple[Grammar, Tuple[str, ...], Dict[str, A
247
339
  rules = {}
248
340
  rule_info = {}
249
341
 
342
+ full_grammar = grammar
250
343
  grammar = strip_comments(grammar)
251
344
  grammar = inject_builtins(grammar)
252
345
  command_key = get_keywords(grammar)
253
- help_txt = build_help(grammar)
346
+ syntax_txt = build_syntax(grammar)
347
+ help_txt = build_help(syntax_txt, full_grammar)
254
348
  grammar = build_cmd(grammar)
255
349
 
256
350
  # Make sure grouping characters all have whitespace around them
@@ -336,7 +430,10 @@ def process_grammar(grammar: str) -> Tuple[Grammar, Tuple[str, ...], Dict[str, A
336
430
  cmds = ' / '.join(x for x in rules if x.endswith('_cmd'))
337
431
  cmds = f'init = ws* ( {cmds} ) ws* ";"? ws*\n'
338
432
 
339
- return Grammar(cmds + CORE_GRAMMAR + '\n'.join(out)), command_key, rule_info, help_txt
433
+ return (
434
+ Grammar(cmds + CORE_GRAMMAR + '\n'.join(out)), command_key,
435
+ rule_info, syntax_txt, help_txt,
436
+ )
340
437
 
341
438
 
342
439
  def flatten(items: Iterable[Any]) -> List[Any]:
@@ -378,7 +475,10 @@ class SQLHandler(NodeVisitor):
378
475
  #: Metadata about the parse rules
379
476
  rule_info: Dict[str, Any] = {}
380
477
 
381
- #: Help string for use in error messages
478
+ #: Syntax string for use in error messages
479
+ syntax: str = ''
480
+
481
+ #: Full help for the command
382
482
  help: str = ''
383
483
 
384
484
  #: Rule validation functions
@@ -396,7 +496,7 @@ class SQLHandler(NodeVisitor):
396
496
  Compile the grammar held in the docstring.
397
497
 
398
498
  This method modifies attributes on the class: ``grammar``,
399
- ``command_key``, ``rule_info``, and ``help``.
499
+ ``command_key``, ``rule_info``, ``syntax``, and ``help``.
400
500
 
401
501
  Parameters
402
502
  ----------
@@ -407,7 +507,7 @@ class SQLHandler(NodeVisitor):
407
507
  if cls._is_compiled:
408
508
  return
409
509
 
410
- cls.grammar, cls.command_key, cls.rule_info, cls.help = \
510
+ cls.grammar, cls.command_key, cls.rule_info, cls.syntax, cls.help = \
411
511
  process_grammar(grammar or cls.__doc__ or '')
412
512
 
413
513
  cls._grammar = grammar or cls.__doc__ or ''
@@ -476,7 +576,7 @@ class SQLHandler(NodeVisitor):
476
576
  msg = ' ' + m.group(1) + m.group(2)
477
577
  raise ValueError(
478
578
  f'Could not parse statement.{msg} '
479
- 'Expecting:\n' + textwrap.indent(type(self).help, ' '),
579
+ 'Expecting:\n' + textwrap.indent(type(self).syntax, ' '),
480
580
  )
481
581
 
482
582
  @abc.abstractmethod
@@ -33,6 +33,41 @@ class ShowStageFilesHandler(SQLHandler):
33
33
  # Should extended attributes be shown?
34
34
  extended = EXTENDED
35
35
 
36
+ Description
37
+ -----------
38
+ Show the files in a workspace group's stage.
39
+
40
+ Remarks
41
+ -------
42
+ * ``IN GROUP`` specifies the workspace group or workspace group ID.
43
+ When using an ID, ``IN GROUP ID`` must be used.
44
+ * ``AT PATH`` specifies the path to list. If no ``AT PATH`` is specified,
45
+ the root directory is used.
46
+ * ``LIKE`` allows you to specify a filename pattern using ``%`` as a wildcard.
47
+ * ``ORDER BY`` allows you to specify the field to sort by.
48
+ * ``LIMIT`` allows you to set a limit on the number of entries displayed.
49
+ * ``RECURSIVE`` indicates that the stage should be listed recursively.
50
+ * ``EXTENDED`` indicates that more detailed information should be displayed.
51
+
52
+ Examples
53
+ --------
54
+ Example 1: Show files at path
55
+
56
+ This example shows how to list files starting at a specific path::
57
+
58
+ SHOW STAGE FILES IN GROUP "My Group" AT PATH "/data/";
59
+
60
+ Example 2: Show files recursively
61
+
62
+ This example show dow to display files recursively and with extra information::
63
+
64
+ SHOW STAGE FILES IN GROUP "My Group" RECURSIVE EXTENDED;
65
+
66
+ See Also
67
+ --------
68
+ * UPLOAD FILE TO STAGE
69
+ * DOWNLOAD STAGE FILE
70
+
36
71
  """
37
72
 
38
73
  def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
@@ -100,6 +135,30 @@ class UploadStageFileHandler(SQLHandler):
100
135
  # Should an existing file be overwritten?
101
136
  overwrite = OVERWRITE
102
137
 
138
+ Description
139
+ -----------
140
+ Upload a file to the workspace group's stage.
141
+
142
+ Remarks
143
+ -------
144
+ * ``<stage-path>`` is the path in stage to upload the file to.
145
+ * ``IN GROUP`` specifies the workspace group or workspace group ID. When
146
+ using an ID ``IN GROUP ID`` should be used.
147
+ * ``<local-path>`` is the path on the local machine of the file to upload.
148
+ * ``OVERWRITE`` indicates that an existing stage file at that path
149
+ should be overwritten if it exists.
150
+
151
+ Examples
152
+ --------
153
+ Example 1: Upload with overwrite::
154
+
155
+ UPLOAD FILE TO STAGE '/data/stats.csv' IN GROUP 'My Group'
156
+ FROM '/u/user/stats.csv' OVERWRITE;
157
+
158
+ See Also
159
+ --------
160
+ * DOWNLOAD STAGE FILE
161
+
103
162
  """
104
163
 
105
164
  def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
@@ -140,6 +199,38 @@ class DownloadStageFileHandler(SQLHandler):
140
199
  # File encoding
141
200
  encoding = ENCODING '<encoding>'
142
201
 
202
+ Description
203
+ -----------
204
+ Download a stage file.
205
+
206
+ Remarks
207
+ -------
208
+ * ``<stage-path>`` is the path in stage to download.
209
+ * ``IN GROUP`` specifies the workspace group or workspace group ID. When
210
+ using an ID ``IN GROUP ID`` should be used.
211
+ * ``<local-path>`` is the destination path for the file. If not specified,
212
+ the file is returned in a result set.
213
+ * ``OVERWRITE`` indicates that an existing local file should be overwritten.
214
+ * ``ENCODING`` specifies the encoding of the file to apply to the downloaded
215
+ file. By default, files are downloaded as binary. This only option
216
+ typically only matters if ``<local-path>`` is not specified and the file
217
+ is to be printed to the screen.
218
+
219
+ Examples
220
+ --------
221
+ Example 1: Print a file to the screen::
222
+
223
+ DOWNLOAD STAGE FILE '/data/stats.csv' IN GROUP 'My Group';
224
+
225
+ Example 2: Download a file to a local path with overwrite set::
226
+
227
+ DONLOAD STAGE FILE '/data/stats.csv' IN GROUP 'My Group'
228
+ TO '/u/me/data.csv' OVERWRITE;
229
+
230
+ See Also
231
+ --------
232
+ * UPLOAD FILE TO STAGE
233
+
143
234
  """
144
235
 
145
236
  def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
@@ -183,6 +274,26 @@ class DropStageFileHandler(SQLHandler):
183
274
  # Name of group
184
275
  group_name = '<group-name>'
185
276
 
277
+ Description
278
+ -----------
279
+ Drop a stage file.
280
+
281
+ Remarks
282
+ -------
283
+ * ``<stage-path>`` is the path in stage to drop.
284
+ * ``IN GROUP`` specifies the workspace group or workspace group ID. When
285
+ using an ID ``IN GROUP ID`` should be used.
286
+
287
+ Example
288
+ --------
289
+ Drop a specific file from stage::
290
+
291
+ DROP STAGE FILE '/data/stats.csv' IN GROUP 'My Group';
292
+
293
+ See Also
294
+ --------
295
+ * DROP STAGE FOLDER
296
+
186
297
  """
187
298
 
188
299
  def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
@@ -213,6 +324,27 @@ class DropStageFolderHandler(SQLHandler):
213
324
  # Should folers be deleted recursively?
214
325
  recursive = RECURSIVE
215
326
 
327
+ Description
328
+ -----------
329
+ Drop a folder from stage.
330
+
331
+ Remarks
332
+ -------
333
+ * ``<stage-path>`` is the path in stage to drop.
334
+ * ``IN GROUP`` specifies the workspace group or workspace group ID. When
335
+ using an ID ``IN GROUP ID`` should be used.
336
+ * ``RECURSIVE`` indicates that folders should be removed recursively.
337
+
338
+ Example
339
+ -------
340
+ Drop a folder recursively::
341
+
342
+ DROP STAGE FOLDER '/data/' IN GROUP 'My Group' RECURSIVE;
343
+
344
+ See Also
345
+ --------
346
+ * DROP STAGE FILE
347
+
216
348
  """
217
349
 
218
350
  def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]:
@@ -246,6 +378,24 @@ class CreateStageFolderHandler(SQLHandler):
246
378
  # Should an existing folder be overwritten?
247
379
  overwrite = OVERWRITE
248
380
 
381
+ Description
382
+ -----------
383
+ Create a folder in stage.
384
+
385
+ Remarks
386
+ -------
387
+ * ``<stage-path>`` is the path to create in stage.
388
+ * ``IN GROUP`` specifies the workspace group or workspace group ID. When
389
+ using an ID ``IN GROUP ID`` should be used.
390
+ * ``OVERWRITE`` indicates that an existing folder should be overwritten
391
+ with a new folder.
392
+
393
+ Example
394
+ -------
395
+ Create a folder::
396
+
397
+ CREATE STAGE FOLDER `/data/csv/` IN GROUP 'My Group';
398
+
249
399
  """
250
400
 
251
401
  def run(self, params: Dict[str, Any]) -> Optional[FusionSQLResult]: