singlestoredb 1.14.1__cp38-abi3-win32.whl → 1.15.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.
- _singlestoredb_accel.pyd +0 -0
- singlestoredb/__init__.py +14 -10
- singlestoredb/apps/_python_udfs.py +3 -3
- singlestoredb/config.py +5 -0
- singlestoredb/functions/decorator.py +32 -13
- singlestoredb/functions/ext/asgi.py +287 -27
- singlestoredb/functions/ext/timer.py +98 -0
- singlestoredb/functions/typing/numpy.py +20 -0
- singlestoredb/functions/typing/pandas.py +2 -0
- singlestoredb/functions/typing/polars.py +2 -0
- singlestoredb/functions/typing/pyarrow.py +2 -0
- singlestoredb/fusion/handler.py +17 -4
- singlestoredb/magics/run_personal.py +82 -1
- singlestoredb/magics/run_shared.py +82 -1
- singlestoredb/management/__init__.py +1 -0
- singlestoredb/management/export.py +1 -1
- singlestoredb/management/region.py +92 -0
- singlestoredb/management/workspace.py +180 -1
- singlestoredb/tests/ext_funcs/__init__.py +94 -55
- singlestoredb/tests/test.sql +22 -0
- singlestoredb/tests/test_ext_func.py +90 -0
- singlestoredb/tests/test_fusion.py +4 -1
- singlestoredb/tests/test_management.py +253 -20
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/METADATA +3 -2
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/RECORD +30 -25
- /singlestoredb/functions/{typing.py → typing/__init__.py} +0 -0
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/LICENSE +0 -0
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/WHEEL +0 -0
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/entry_points.txt +0 -0
- {singlestoredb-1.14.1.dist-info → singlestoredb-1.15.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import time
|
|
3
|
+
from typing import Any
|
|
4
|
+
from typing import Dict
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from . import utils
|
|
8
|
+
|
|
9
|
+
logger = utils.get_logger('singlestoredb.functions.ext.metrics')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RoundedFloatEncoder(json.JSONEncoder):
|
|
13
|
+
|
|
14
|
+
def encode(self, obj: Any) -> str:
|
|
15
|
+
if isinstance(obj, dict):
|
|
16
|
+
return '{' + ', '.join(
|
|
17
|
+
f'"{k}": {self._format_value(v)}'
|
|
18
|
+
for k, v in obj.items()
|
|
19
|
+
) + '}'
|
|
20
|
+
return super().encode(obj)
|
|
21
|
+
|
|
22
|
+
def _format_value(self, value: Any) -> str:
|
|
23
|
+
if isinstance(value, float):
|
|
24
|
+
return f'{value:.2f}'
|
|
25
|
+
return json.dumps(value)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Timer:
|
|
29
|
+
"""
|
|
30
|
+
Timer context manager that supports nested timing using a stack.
|
|
31
|
+
|
|
32
|
+
Example
|
|
33
|
+
-------
|
|
34
|
+
timer = Timer()
|
|
35
|
+
|
|
36
|
+
with timer('total'):
|
|
37
|
+
with timer('receive_data'):
|
|
38
|
+
time.sleep(0.1)
|
|
39
|
+
with timer('parse_input'):
|
|
40
|
+
time.sleep(0.2)
|
|
41
|
+
with timer('call_function'):
|
|
42
|
+
with timer('inner_operation'):
|
|
43
|
+
time.sleep(0.05)
|
|
44
|
+
time.sleep(0.3)
|
|
45
|
+
|
|
46
|
+
print(timer.metrics)
|
|
47
|
+
# {'receive_data': 0.1, 'parse_input': 0.2, 'inner_operation': 0.05,
|
|
48
|
+
# 'call_function': 0.35, 'total': 0.65}
|
|
49
|
+
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
53
|
+
self.metadata: Dict[str, Any] = kwargs
|
|
54
|
+
self.metrics: Dict[str, float] = dict()
|
|
55
|
+
self.entries: Dict[str, float] = dict()
|
|
56
|
+
self._current_key: Optional[str] = None
|
|
57
|
+
self.start_time = time.perf_counter()
|
|
58
|
+
|
|
59
|
+
def __call__(self, key: str) -> 'Timer':
|
|
60
|
+
self._current_key = key
|
|
61
|
+
return self
|
|
62
|
+
|
|
63
|
+
def __enter__(self) -> 'Timer':
|
|
64
|
+
if self._current_key is None:
|
|
65
|
+
raise ValueError(
|
|
66
|
+
"No key specified. Use timer('key_name') as context manager.",
|
|
67
|
+
)
|
|
68
|
+
self.entries[self._current_key] = time.perf_counter()
|
|
69
|
+
return self
|
|
70
|
+
|
|
71
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
72
|
+
key = self._current_key
|
|
73
|
+
if key and key in self.entries:
|
|
74
|
+
start = self.entries.pop(key)
|
|
75
|
+
elapsed = time.perf_counter() - start
|
|
76
|
+
self.metrics[key] = elapsed
|
|
77
|
+
self._current_key = None
|
|
78
|
+
|
|
79
|
+
async def __aenter__(self) -> 'Timer':
|
|
80
|
+
return self.__enter__()
|
|
81
|
+
|
|
82
|
+
async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
83
|
+
self.__exit__(exc_type, exc_val, exc_tb)
|
|
84
|
+
|
|
85
|
+
def reset(self) -> None:
|
|
86
|
+
self.metrics.clear()
|
|
87
|
+
self.entries.clear()
|
|
88
|
+
self._current_key = None
|
|
89
|
+
|
|
90
|
+
def finish(self) -> None:
|
|
91
|
+
"""Finish the current timing context and store the elapsed time."""
|
|
92
|
+
self.metrics['total'] = time.perf_counter() - self.start_time
|
|
93
|
+
self.log_metrics()
|
|
94
|
+
|
|
95
|
+
def log_metrics(self) -> None:
|
|
96
|
+
if self.metadata.get('function'):
|
|
97
|
+
result = dict(type='function_metrics', **self.metadata, **self.metrics)
|
|
98
|
+
logger.info(json.dumps(result, cls=RoundedFloatEncoder))
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
NDArray = npt.NDArray
|
|
5
|
+
|
|
6
|
+
StringArray = StrArray = npt.NDArray[np.str_]
|
|
7
|
+
BytesArray = npt.NDArray[np.bytes_]
|
|
8
|
+
Float32Array = FloatArray = npt.NDArray[np.float32]
|
|
9
|
+
Float64Array = DoubleArray = npt.NDArray[np.float64]
|
|
10
|
+
IntArray = npt.NDArray[np.int_]
|
|
11
|
+
Int8Array = npt.NDArray[np.int8]
|
|
12
|
+
Int16Array = npt.NDArray[np.int16]
|
|
13
|
+
Int32Array = npt.NDArray[np.int32]
|
|
14
|
+
Int64Array = npt.NDArray[np.int64]
|
|
15
|
+
UInt8Array = npt.NDArray[np.uint8]
|
|
16
|
+
UInt16Array = npt.NDArray[np.uint16]
|
|
17
|
+
UInt32Array = npt.NDArray[np.uint32]
|
|
18
|
+
UInt64Array = npt.NDArray[np.uint64]
|
|
19
|
+
DateTimeArray = npt.NDArray[np.datetime64]
|
|
20
|
+
TimeDeltaArray = npt.NDArray[np.timedelta64]
|
singlestoredb/fusion/handler.py
CHANGED
|
@@ -33,7 +33,7 @@ CORE_GRAMMAR = r'''
|
|
|
33
33
|
close_paren = ws* ")" ws*
|
|
34
34
|
open_repeats = ws* ~r"[\(\[\{]" ws*
|
|
35
35
|
close_repeats = ws* ~r"[\)\]\}]" ws*
|
|
36
|
-
|
|
36
|
+
statement = ~r"[\s\S]*" ws*
|
|
37
37
|
table = ~r"(?:([A-Za-z0-9_\-]+)|`([^\`]+)`)(?:\.(?:([A-Za-z0-9_\-]+)|`([^\`]+)`))?" ws*
|
|
38
38
|
column = ~r"(?:([A-Za-z0-9_\-]+)|`([^\`]+)`)(?:\.(?:([A-Za-z0-9_\-]+)|`([^\`]+)`))?" ws*
|
|
39
39
|
link_name = ~r"(?:([A-Za-z0-9_\-]+)|`([^\`]+)`)(?:\.(?:([A-Za-z0-9_\-]+)|`([^\`]+)`))?" ws*
|
|
@@ -77,6 +77,7 @@ BUILTINS = {
|
|
|
77
77
|
'<file-type>': r'''
|
|
78
78
|
file_type = { FILE | FOLDER }
|
|
79
79
|
''',
|
|
80
|
+
'<statement>': '',
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
BUILTIN_DEFAULTS = { # type: ignore
|
|
@@ -627,6 +628,18 @@ class SQLHandler(NodeVisitor):
|
|
|
627
628
|
cls.compile()
|
|
628
629
|
registry.register_handler(cls, overwrite=overwrite)
|
|
629
630
|
|
|
631
|
+
def create_result(self) -> result.FusionSQLResult:
|
|
632
|
+
"""
|
|
633
|
+
Create a new result object.
|
|
634
|
+
|
|
635
|
+
Returns
|
|
636
|
+
-------
|
|
637
|
+
FusionSQLResult
|
|
638
|
+
A new result object for this handler
|
|
639
|
+
|
|
640
|
+
"""
|
|
641
|
+
return result.FusionSQLResult()
|
|
642
|
+
|
|
630
643
|
def execute(self, sql: str) -> result.FusionSQLResult:
|
|
631
644
|
"""
|
|
632
645
|
Parse the SQL and invoke the handler method.
|
|
@@ -746,9 +759,9 @@ class SQLHandler(NodeVisitor):
|
|
|
746
759
|
_, out, *_ = visited_children
|
|
747
760
|
return out
|
|
748
761
|
|
|
749
|
-
def
|
|
750
|
-
out = ' '.join(flatten(visited_children))
|
|
751
|
-
return {'
|
|
762
|
+
def visit_statement(self, node: Node, visited_children: Iterable[Any]) -> Any:
|
|
763
|
+
out = ' '.join(flatten(visited_children)).strip()
|
|
764
|
+
return {'statement': out}
|
|
752
765
|
|
|
753
766
|
def visit_order_by(self, node: Node, visited_children: Iterable[Any]) -> Any:
|
|
754
767
|
"""Handle ORDER BY."""
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import tempfile
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from typing import Any
|
|
5
|
+
from warnings import warn
|
|
4
6
|
|
|
5
7
|
from IPython.core.interactiveshell import InteractiveShell
|
|
6
8
|
from IPython.core.magic import line_magic
|
|
@@ -8,6 +10,8 @@ from IPython.core.magic import Magics
|
|
|
8
10
|
from IPython.core.magic import magics_class
|
|
9
11
|
from IPython.core.magic import needs_local_scope
|
|
10
12
|
from IPython.core.magic import no_var_expand
|
|
13
|
+
from IPython.utils.contexts import preserve_keys
|
|
14
|
+
from IPython.utils.syspathcontext import prepended_to_syspath
|
|
11
15
|
from jinja2 import Template
|
|
12
16
|
|
|
13
17
|
|
|
@@ -53,4 +57,81 @@ class RunPersonalMagic(Magics):
|
|
|
53
57
|
# Execute the SQL command
|
|
54
58
|
self.shell.run_line_magic('sql', sql_command)
|
|
55
59
|
# Run the downloaded file
|
|
56
|
-
self.shell.
|
|
60
|
+
with preserve_keys(self.shell.user_ns, '__file__'):
|
|
61
|
+
self.shell.user_ns['__file__'] = temp_file_path
|
|
62
|
+
self.safe_execfile_ipy(temp_file_path, raise_exceptions=True)
|
|
63
|
+
|
|
64
|
+
def safe_execfile_ipy(
|
|
65
|
+
self,
|
|
66
|
+
fname: str,
|
|
67
|
+
shell_futures: bool = False,
|
|
68
|
+
raise_exceptions: bool = False,
|
|
69
|
+
) -> None:
|
|
70
|
+
"""Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
fname : str
|
|
75
|
+
The name of the file to execute. The filename must have a
|
|
76
|
+
.ipy or .ipynb extension.
|
|
77
|
+
shell_futures : bool (False)
|
|
78
|
+
If True, the code will share future statements with the interactive
|
|
79
|
+
shell. It will both be affected by previous __future__ imports, and
|
|
80
|
+
any __future__ imports in the code will affect the shell. If False,
|
|
81
|
+
__future__ imports are not shared in either direction.
|
|
82
|
+
raise_exceptions : bool (False)
|
|
83
|
+
If True raise exceptions everywhere. Meant for testing.
|
|
84
|
+
"""
|
|
85
|
+
fpath = Path(fname).expanduser().resolve()
|
|
86
|
+
|
|
87
|
+
# Make sure we can open the file
|
|
88
|
+
try:
|
|
89
|
+
with fpath.open('rb'):
|
|
90
|
+
pass
|
|
91
|
+
except Exception:
|
|
92
|
+
warn('Could not open file <%s> for safe execution.' % fpath)
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
# Find things also in current directory. This is needed to mimic the
|
|
96
|
+
# behavior of running a script from the system command line, where
|
|
97
|
+
# Python inserts the script's directory into sys.path
|
|
98
|
+
dname = str(fpath.parent)
|
|
99
|
+
|
|
100
|
+
def get_cells() -> Any:
|
|
101
|
+
"""generator for sequence of code blocks to run"""
|
|
102
|
+
if fpath.suffix == '.ipynb':
|
|
103
|
+
from nbformat import read
|
|
104
|
+
nb = read(fpath, as_version=4)
|
|
105
|
+
if not nb.cells:
|
|
106
|
+
return
|
|
107
|
+
for cell in nb.cells:
|
|
108
|
+
if cell.cell_type == 'code':
|
|
109
|
+
if not cell.source.strip():
|
|
110
|
+
continue
|
|
111
|
+
if getattr(cell, 'metadata', {}).get('language', '') == 'sql':
|
|
112
|
+
output_redirect = getattr(
|
|
113
|
+
cell, 'metadata', {},
|
|
114
|
+
).get('output_variable', '') or ''
|
|
115
|
+
if output_redirect:
|
|
116
|
+
output_redirect = f' {output_redirect} <<'
|
|
117
|
+
yield f'%%sql{output_redirect}\n{cell.source}'
|
|
118
|
+
else:
|
|
119
|
+
yield cell.source
|
|
120
|
+
else:
|
|
121
|
+
yield fpath.read_text(encoding='utf-8')
|
|
122
|
+
|
|
123
|
+
with prepended_to_syspath(dname):
|
|
124
|
+
try:
|
|
125
|
+
for cell in get_cells():
|
|
126
|
+
result = self.shell.run_cell(
|
|
127
|
+
cell, silent=True, shell_futures=shell_futures,
|
|
128
|
+
)
|
|
129
|
+
if raise_exceptions:
|
|
130
|
+
result.raise_error()
|
|
131
|
+
elif not result.success:
|
|
132
|
+
break
|
|
133
|
+
except Exception:
|
|
134
|
+
if raise_exceptions:
|
|
135
|
+
raise
|
|
136
|
+
self.shell.showtraceback()
|
|
137
|
+
warn('Unknown failure executing file: <%s>' % fpath)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import tempfile
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from typing import Any
|
|
5
|
+
from warnings import warn
|
|
4
6
|
|
|
5
7
|
from IPython.core.interactiveshell import InteractiveShell
|
|
6
8
|
from IPython.core.magic import line_magic
|
|
@@ -8,6 +10,8 @@ from IPython.core.magic import Magics
|
|
|
8
10
|
from IPython.core.magic import magics_class
|
|
9
11
|
from IPython.core.magic import needs_local_scope
|
|
10
12
|
from IPython.core.magic import no_var_expand
|
|
13
|
+
from IPython.utils.contexts import preserve_keys
|
|
14
|
+
from IPython.utils.syspathcontext import prepended_to_syspath
|
|
11
15
|
from jinja2 import Template
|
|
12
16
|
|
|
13
17
|
|
|
@@ -50,4 +54,81 @@ class RunSharedMagic(Magics):
|
|
|
50
54
|
# Execute the SQL command
|
|
51
55
|
self.shell.run_line_magic('sql', sql_command)
|
|
52
56
|
# Run the downloaded file
|
|
53
|
-
self.shell.
|
|
57
|
+
with preserve_keys(self.shell.user_ns, '__file__'):
|
|
58
|
+
self.shell.user_ns['__file__'] = temp_file_path
|
|
59
|
+
self.safe_execfile_ipy(temp_file_path, raise_exceptions=True)
|
|
60
|
+
|
|
61
|
+
def safe_execfile_ipy(
|
|
62
|
+
self,
|
|
63
|
+
fname: str,
|
|
64
|
+
shell_futures: bool = False,
|
|
65
|
+
raise_exceptions: bool = False,
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
fname : str
|
|
72
|
+
The name of the file to execute. The filename must have a
|
|
73
|
+
.ipy or .ipynb extension.
|
|
74
|
+
shell_futures : bool (False)
|
|
75
|
+
If True, the code will share future statements with the interactive
|
|
76
|
+
shell. It will both be affected by previous __future__ imports, and
|
|
77
|
+
any __future__ imports in the code will affect the shell. If False,
|
|
78
|
+
__future__ imports are not shared in either direction.
|
|
79
|
+
raise_exceptions : bool (False)
|
|
80
|
+
If True raise exceptions everywhere. Meant for testing.
|
|
81
|
+
"""
|
|
82
|
+
fpath = Path(fname).expanduser().resolve()
|
|
83
|
+
|
|
84
|
+
# Make sure we can open the file
|
|
85
|
+
try:
|
|
86
|
+
with fpath.open('rb'):
|
|
87
|
+
pass
|
|
88
|
+
except Exception:
|
|
89
|
+
warn('Could not open file <%s> for safe execution.' % fpath)
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
# Find things also in current directory. This is needed to mimic the
|
|
93
|
+
# behavior of running a script from the system command line, where
|
|
94
|
+
# Python inserts the script's directory into sys.path
|
|
95
|
+
dname = str(fpath.parent)
|
|
96
|
+
|
|
97
|
+
def get_cells() -> Any:
|
|
98
|
+
"""generator for sequence of code blocks to run"""
|
|
99
|
+
if fpath.suffix == '.ipynb':
|
|
100
|
+
from nbformat import read
|
|
101
|
+
nb = read(fpath, as_version=4)
|
|
102
|
+
if not nb.cells:
|
|
103
|
+
return
|
|
104
|
+
for cell in nb.cells:
|
|
105
|
+
if cell.cell_type == 'code':
|
|
106
|
+
if not cell.source.strip():
|
|
107
|
+
continue
|
|
108
|
+
if getattr(cell, 'metadata', {}).get('language', '') == 'sql':
|
|
109
|
+
output_redirect = getattr(
|
|
110
|
+
cell, 'metadata', {},
|
|
111
|
+
).get('output_variable', '') or ''
|
|
112
|
+
if output_redirect:
|
|
113
|
+
output_redirect = f' {output_redirect} <<'
|
|
114
|
+
yield f'%%sql{output_redirect}\n{cell.source}'
|
|
115
|
+
else:
|
|
116
|
+
yield cell.source
|
|
117
|
+
else:
|
|
118
|
+
yield fpath.read_text(encoding='utf-8')
|
|
119
|
+
|
|
120
|
+
with prepended_to_syspath(dname):
|
|
121
|
+
try:
|
|
122
|
+
for cell in get_cells():
|
|
123
|
+
result = self.shell.run_cell(
|
|
124
|
+
cell, silent=True, shell_futures=shell_futures,
|
|
125
|
+
)
|
|
126
|
+
if raise_exceptions:
|
|
127
|
+
result.raise_error()
|
|
128
|
+
elif not result.success:
|
|
129
|
+
break
|
|
130
|
+
except Exception:
|
|
131
|
+
if raise_exceptions:
|
|
132
|
+
raise
|
|
133
|
+
self.shell.showtraceback()
|
|
134
|
+
warn('Unknown failure executing file: <%s>' % fpath)
|
|
@@ -215,7 +215,7 @@ class ExportService(object):
|
|
|
215
215
|
msg='Export ID is not set. You must start the export first.',
|
|
216
216
|
)
|
|
217
217
|
|
|
218
|
-
self._manager.
|
|
218
|
+
self._manager._delete(
|
|
219
219
|
f'workspaceGroups/{self.workspace_group.id}/egress/dropTableEgress',
|
|
220
220
|
json=dict(egressID=self.export_id),
|
|
221
221
|
)
|
|
@@ -4,6 +4,7 @@ from typing import Dict
|
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
6
|
from .manager import Manager
|
|
7
|
+
from .utils import NamedList
|
|
7
8
|
from .utils import vars_to_str
|
|
8
9
|
|
|
9
10
|
|
|
@@ -65,3 +66,94 @@ class Region(object):
|
|
|
65
66
|
)
|
|
66
67
|
out._manager = manager
|
|
67
68
|
return out
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class RegionManager(Manager):
|
|
72
|
+
"""
|
|
73
|
+
SingleStoreDB region manager.
|
|
74
|
+
|
|
75
|
+
This class should be instantiated using :func:`singlestoredb.manage_regions`.
|
|
76
|
+
|
|
77
|
+
Parameters
|
|
78
|
+
----------
|
|
79
|
+
access_token : str, optional
|
|
80
|
+
The API key or other access token for the workspace management API
|
|
81
|
+
version : str, optional
|
|
82
|
+
Version of the API to use
|
|
83
|
+
base_url : str, optional
|
|
84
|
+
Base URL of the workspace management API
|
|
85
|
+
|
|
86
|
+
See Also
|
|
87
|
+
--------
|
|
88
|
+
:func:`singlestoredb.manage_regions`
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
#: Object type
|
|
92
|
+
obj_type = 'region'
|
|
93
|
+
|
|
94
|
+
def list_regions(self) -> NamedList[Region]:
|
|
95
|
+
"""
|
|
96
|
+
List all available regions.
|
|
97
|
+
|
|
98
|
+
Returns
|
|
99
|
+
-------
|
|
100
|
+
NamedList[Region]
|
|
101
|
+
List of available regions
|
|
102
|
+
|
|
103
|
+
Raises
|
|
104
|
+
------
|
|
105
|
+
ManagementError
|
|
106
|
+
If there is an error getting the regions
|
|
107
|
+
"""
|
|
108
|
+
res = self._get('regions')
|
|
109
|
+
return NamedList(
|
|
110
|
+
[Region.from_dict(item, self) for item in res.json()],
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
def list_shared_tier_regions(self) -> NamedList[Region]:
|
|
114
|
+
"""
|
|
115
|
+
List regions that support shared tier workspaces.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
NamedList[Region]
|
|
120
|
+
List of regions that support shared tier workspaces
|
|
121
|
+
|
|
122
|
+
Raises
|
|
123
|
+
------
|
|
124
|
+
ManagementError
|
|
125
|
+
If there is an error getting the regions
|
|
126
|
+
"""
|
|
127
|
+
res = self._get('regions/sharedtier')
|
|
128
|
+
return NamedList(
|
|
129
|
+
[Region.from_dict(item, self) for item in res.json()],
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def manage_regions(
|
|
134
|
+
access_token: Optional[str] = None,
|
|
135
|
+
version: Optional[str] = None,
|
|
136
|
+
base_url: Optional[str] = None,
|
|
137
|
+
) -> RegionManager:
|
|
138
|
+
"""
|
|
139
|
+
Retrieve a SingleStoreDB region manager.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
access_token : str, optional
|
|
144
|
+
The API key or other access token for the workspace management API
|
|
145
|
+
version : str, optional
|
|
146
|
+
Version of the API to use
|
|
147
|
+
base_url : str, optional
|
|
148
|
+
Base URL of the workspace management API
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
:class:`RegionManager`
|
|
153
|
+
|
|
154
|
+
"""
|
|
155
|
+
return RegionManager(
|
|
156
|
+
access_token=access_token,
|
|
157
|
+
version=version,
|
|
158
|
+
base_url=base_url,
|
|
159
|
+
)
|