singlestoredb 1.16.1__py3-none-any.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.
- singlestoredb/__init__.py +75 -0
- singlestoredb/ai/__init__.py +2 -0
- singlestoredb/ai/chat.py +139 -0
- singlestoredb/ai/embeddings.py +128 -0
- singlestoredb/alchemy/__init__.py +90 -0
- singlestoredb/apps/__init__.py +3 -0
- singlestoredb/apps/_cloud_functions.py +90 -0
- singlestoredb/apps/_config.py +72 -0
- singlestoredb/apps/_connection_info.py +18 -0
- singlestoredb/apps/_dashboards.py +47 -0
- singlestoredb/apps/_process.py +32 -0
- singlestoredb/apps/_python_udfs.py +100 -0
- singlestoredb/apps/_stdout_supress.py +30 -0
- singlestoredb/apps/_uvicorn_util.py +36 -0
- singlestoredb/auth.py +245 -0
- singlestoredb/config.py +484 -0
- singlestoredb/connection.py +1487 -0
- singlestoredb/converters.py +950 -0
- singlestoredb/docstring/__init__.py +33 -0
- singlestoredb/docstring/attrdoc.py +126 -0
- singlestoredb/docstring/common.py +230 -0
- singlestoredb/docstring/epydoc.py +267 -0
- singlestoredb/docstring/google.py +412 -0
- singlestoredb/docstring/numpydoc.py +562 -0
- singlestoredb/docstring/parser.py +100 -0
- singlestoredb/docstring/py.typed +1 -0
- singlestoredb/docstring/rest.py +256 -0
- singlestoredb/docstring/tests/__init__.py +1 -0
- singlestoredb/docstring/tests/_pydoctor.py +21 -0
- singlestoredb/docstring/tests/test_epydoc.py +729 -0
- singlestoredb/docstring/tests/test_google.py +1007 -0
- singlestoredb/docstring/tests/test_numpydoc.py +1100 -0
- singlestoredb/docstring/tests/test_parse_from_object.py +109 -0
- singlestoredb/docstring/tests/test_parser.py +248 -0
- singlestoredb/docstring/tests/test_rest.py +547 -0
- singlestoredb/docstring/tests/test_util.py +70 -0
- singlestoredb/docstring/util.py +141 -0
- singlestoredb/exceptions.py +120 -0
- singlestoredb/functions/__init__.py +16 -0
- singlestoredb/functions/decorator.py +201 -0
- singlestoredb/functions/dtypes.py +1793 -0
- singlestoredb/functions/ext/__init__.py +1 -0
- singlestoredb/functions/ext/arrow.py +375 -0
- singlestoredb/functions/ext/asgi.py +2133 -0
- singlestoredb/functions/ext/json.py +420 -0
- singlestoredb/functions/ext/mmap.py +413 -0
- singlestoredb/functions/ext/rowdat_1.py +724 -0
- singlestoredb/functions/ext/timer.py +89 -0
- singlestoredb/functions/ext/utils.py +218 -0
- singlestoredb/functions/signature.py +1578 -0
- singlestoredb/functions/typing/__init__.py +41 -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/functions/utils.py +421 -0
- singlestoredb/fusion/__init__.py +11 -0
- singlestoredb/fusion/graphql.py +213 -0
- singlestoredb/fusion/handler.py +916 -0
- singlestoredb/fusion/handlers/__init__.py +0 -0
- singlestoredb/fusion/handlers/export.py +525 -0
- singlestoredb/fusion/handlers/files.py +690 -0
- singlestoredb/fusion/handlers/job.py +660 -0
- singlestoredb/fusion/handlers/models.py +250 -0
- singlestoredb/fusion/handlers/stage.py +502 -0
- singlestoredb/fusion/handlers/utils.py +324 -0
- singlestoredb/fusion/handlers/workspace.py +956 -0
- singlestoredb/fusion/registry.py +249 -0
- singlestoredb/fusion/result.py +399 -0
- singlestoredb/http/__init__.py +27 -0
- singlestoredb/http/connection.py +1267 -0
- singlestoredb/magics/__init__.py +34 -0
- singlestoredb/magics/run_personal.py +137 -0
- singlestoredb/magics/run_shared.py +134 -0
- singlestoredb/management/__init__.py +9 -0
- singlestoredb/management/billing_usage.py +148 -0
- singlestoredb/management/cluster.py +462 -0
- singlestoredb/management/export.py +295 -0
- singlestoredb/management/files.py +1102 -0
- singlestoredb/management/inference_api.py +105 -0
- singlestoredb/management/job.py +887 -0
- singlestoredb/management/manager.py +373 -0
- singlestoredb/management/organization.py +226 -0
- singlestoredb/management/region.py +169 -0
- singlestoredb/management/utils.py +423 -0
- singlestoredb/management/workspace.py +1927 -0
- singlestoredb/mysql/__init__.py +177 -0
- singlestoredb/mysql/_auth.py +298 -0
- singlestoredb/mysql/charset.py +214 -0
- singlestoredb/mysql/connection.py +2032 -0
- singlestoredb/mysql/constants/CLIENT.py +38 -0
- singlestoredb/mysql/constants/COMMAND.py +32 -0
- singlestoredb/mysql/constants/CR.py +78 -0
- singlestoredb/mysql/constants/ER.py +474 -0
- singlestoredb/mysql/constants/EXTENDED_TYPE.py +3 -0
- singlestoredb/mysql/constants/FIELD_TYPE.py +48 -0
- singlestoredb/mysql/constants/FLAG.py +15 -0
- singlestoredb/mysql/constants/SERVER_STATUS.py +10 -0
- singlestoredb/mysql/constants/VECTOR_TYPE.py +6 -0
- singlestoredb/mysql/constants/__init__.py +0 -0
- singlestoredb/mysql/converters.py +271 -0
- singlestoredb/mysql/cursors.py +896 -0
- singlestoredb/mysql/err.py +92 -0
- singlestoredb/mysql/optionfile.py +20 -0
- singlestoredb/mysql/protocol.py +450 -0
- singlestoredb/mysql/tests/__init__.py +19 -0
- singlestoredb/mysql/tests/base.py +126 -0
- singlestoredb/mysql/tests/conftest.py +37 -0
- singlestoredb/mysql/tests/test_DictCursor.py +132 -0
- singlestoredb/mysql/tests/test_SSCursor.py +141 -0
- singlestoredb/mysql/tests/test_basic.py +452 -0
- singlestoredb/mysql/tests/test_connection.py +851 -0
- singlestoredb/mysql/tests/test_converters.py +58 -0
- singlestoredb/mysql/tests/test_cursor.py +141 -0
- singlestoredb/mysql/tests/test_err.py +16 -0
- singlestoredb/mysql/tests/test_issues.py +514 -0
- singlestoredb/mysql/tests/test_load_local.py +75 -0
- singlestoredb/mysql/tests/test_nextset.py +88 -0
- singlestoredb/mysql/tests/test_optionfile.py +27 -0
- singlestoredb/mysql/tests/thirdparty/__init__.py +6 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/__init__.py +9 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/capabilities.py +323 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/dbapi20.py +865 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_capabilities.py +110 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +224 -0
- singlestoredb/mysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_nonstandard.py +101 -0
- singlestoredb/mysql/times.py +23 -0
- singlestoredb/notebook/__init__.py +16 -0
- singlestoredb/notebook/_objects.py +213 -0
- singlestoredb/notebook/_portal.py +352 -0
- singlestoredb/py.typed +0 -0
- singlestoredb/pytest.py +352 -0
- singlestoredb/server/__init__.py +0 -0
- singlestoredb/server/docker.py +452 -0
- singlestoredb/server/free_tier.py +267 -0
- singlestoredb/tests/__init__.py +0 -0
- singlestoredb/tests/alltypes.sql +307 -0
- singlestoredb/tests/alltypes_no_nulls.sql +208 -0
- singlestoredb/tests/empty.sql +0 -0
- singlestoredb/tests/ext_funcs/__init__.py +702 -0
- singlestoredb/tests/local_infile.csv +3 -0
- singlestoredb/tests/test.ipynb +18 -0
- singlestoredb/tests/test.sql +680 -0
- singlestoredb/tests/test2.ipynb +18 -0
- singlestoredb/tests/test2.sql +1 -0
- singlestoredb/tests/test_basics.py +1332 -0
- singlestoredb/tests/test_config.py +318 -0
- singlestoredb/tests/test_connection.py +3103 -0
- singlestoredb/tests/test_dbapi.py +27 -0
- singlestoredb/tests/test_exceptions.py +45 -0
- singlestoredb/tests/test_ext_func.py +1472 -0
- singlestoredb/tests/test_ext_func_data.py +1101 -0
- singlestoredb/tests/test_fusion.py +1527 -0
- singlestoredb/tests/test_http.py +288 -0
- singlestoredb/tests/test_management.py +1599 -0
- singlestoredb/tests/test_plugin.py +33 -0
- singlestoredb/tests/test_results.py +171 -0
- singlestoredb/tests/test_types.py +132 -0
- singlestoredb/tests/test_udf.py +737 -0
- singlestoredb/tests/test_udf_returns.py +459 -0
- singlestoredb/tests/test_vectorstore.py +51 -0
- singlestoredb/tests/test_xdict.py +333 -0
- singlestoredb/tests/utils.py +141 -0
- singlestoredb/types.py +373 -0
- singlestoredb/utils/__init__.py +0 -0
- singlestoredb/utils/config.py +950 -0
- singlestoredb/utils/convert_rows.py +69 -0
- singlestoredb/utils/debug.py +13 -0
- singlestoredb/utils/dtypes.py +205 -0
- singlestoredb/utils/events.py +65 -0
- singlestoredb/utils/mogrify.py +151 -0
- singlestoredb/utils/results.py +585 -0
- singlestoredb/utils/xdict.py +425 -0
- singlestoredb/vectorstore.py +192 -0
- singlestoredb/warnings.py +5 -0
- singlestoredb-1.16.1.dist-info/METADATA +165 -0
- singlestoredb-1.16.1.dist-info/RECORD +183 -0
- singlestoredb-1.16.1.dist-info/WHEEL +5 -0
- singlestoredb-1.16.1.dist-info/entry_points.txt +2 -0
- singlestoredb-1.16.1.dist-info/licenses/LICENSE +201 -0
- singlestoredb-1.16.1.dist-info/top_level.txt +3 -0
- sqlx/__init__.py +4 -0
- sqlx/magic.py +113 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from IPython.core.interactiveshell import InteractiveShell
|
|
2
|
+
|
|
3
|
+
from .run_personal import RunPersonalMagic
|
|
4
|
+
from .run_shared import RunSharedMagic
|
|
5
|
+
|
|
6
|
+
# In order to actually use these magics, we must register them with a
|
|
7
|
+
# running IPython.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def load_ipython_extension(ip: InteractiveShell) -> None:
|
|
11
|
+
"""
|
|
12
|
+
Any module file that define a function named `load_ipython_extension`
|
|
13
|
+
can be loaded via `%load_ext module.path` or be configured to be
|
|
14
|
+
autoloaded by IPython at startup time.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
# Load jupysql extension
|
|
18
|
+
# This is necessary for jupysql to initialize internal state
|
|
19
|
+
# required to render messages
|
|
20
|
+
assert ip.extension_manager is not None
|
|
21
|
+
result = ip.extension_manager.load_extension('sql')
|
|
22
|
+
if result == 'no load function':
|
|
23
|
+
raise RuntimeError('Could not load sql extension. Is jupysql installed?')
|
|
24
|
+
|
|
25
|
+
# Check if %run magic command is defined
|
|
26
|
+
if ip.find_line_magic('run') is None:
|
|
27
|
+
raise RuntimeError(
|
|
28
|
+
'%run magic command is not defined. '
|
|
29
|
+
'Is it available in your IPython environment?',
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Register run_personal and run_shared
|
|
33
|
+
ip.register_magics(RunPersonalMagic(ip))
|
|
34
|
+
ip.register_magics(RunSharedMagic(ip))
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
from warnings import warn
|
|
6
|
+
|
|
7
|
+
from IPython.core.interactiveshell import InteractiveShell
|
|
8
|
+
from IPython.core.magic import line_magic
|
|
9
|
+
from IPython.core.magic import Magics
|
|
10
|
+
from IPython.core.magic import magics_class
|
|
11
|
+
from IPython.core.magic import needs_local_scope
|
|
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
|
|
15
|
+
from jinja2 import Template
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@magics_class
|
|
19
|
+
class RunPersonalMagic(Magics):
|
|
20
|
+
def __init__(self, shell: InteractiveShell):
|
|
21
|
+
Magics.__init__(self, shell=shell)
|
|
22
|
+
|
|
23
|
+
@no_var_expand
|
|
24
|
+
@needs_local_scope
|
|
25
|
+
@line_magic('run_personal')
|
|
26
|
+
def run_personal(self, line: str, local_ns: Any = None) -> Any:
|
|
27
|
+
"""
|
|
28
|
+
Downloads a personal file using the %sql magic and then runs it using %run.
|
|
29
|
+
|
|
30
|
+
Examples::
|
|
31
|
+
|
|
32
|
+
# Line usage
|
|
33
|
+
|
|
34
|
+
%run_personal personal_file.ipynb
|
|
35
|
+
|
|
36
|
+
%run_personal {{ sample_notebook_name }}
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
template = Template(line.strip())
|
|
41
|
+
personal_file = template.render(local_ns)
|
|
42
|
+
if not personal_file:
|
|
43
|
+
raise ValueError('No personal file specified.')
|
|
44
|
+
if (personal_file.startswith("'") and personal_file.endswith("'")) or \
|
|
45
|
+
(personal_file.startswith('"') and personal_file.endswith('"')):
|
|
46
|
+
personal_file = personal_file[1:-1]
|
|
47
|
+
if not personal_file:
|
|
48
|
+
raise ValueError('No personal file specified.')
|
|
49
|
+
|
|
50
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
51
|
+
temp_file_path = os.path.join(temp_dir, personal_file)
|
|
52
|
+
sql_command = (
|
|
53
|
+
f"DOWNLOAD PERSONAL FILE '{personal_file}' "
|
|
54
|
+
f"TO '{temp_file_path}'"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Execute the SQL command
|
|
58
|
+
self.shell.run_line_magic('sql', sql_command)
|
|
59
|
+
# Run the downloaded file
|
|
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)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
from warnings import warn
|
|
6
|
+
|
|
7
|
+
from IPython.core.interactiveshell import InteractiveShell
|
|
8
|
+
from IPython.core.magic import line_magic
|
|
9
|
+
from IPython.core.magic import Magics
|
|
10
|
+
from IPython.core.magic import magics_class
|
|
11
|
+
from IPython.core.magic import needs_local_scope
|
|
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
|
|
15
|
+
from jinja2 import Template
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@magics_class
|
|
19
|
+
class RunSharedMagic(Magics):
|
|
20
|
+
def __init__(self, shell: InteractiveShell):
|
|
21
|
+
Magics.__init__(self, shell=shell)
|
|
22
|
+
|
|
23
|
+
@no_var_expand
|
|
24
|
+
@needs_local_scope
|
|
25
|
+
@line_magic('run_shared')
|
|
26
|
+
def run_shared(self, line: str, local_ns: Any = None) -> Any:
|
|
27
|
+
"""
|
|
28
|
+
Downloads a shared file using the %sql magic and then runs it using %run.
|
|
29
|
+
|
|
30
|
+
Examples::
|
|
31
|
+
|
|
32
|
+
# Line usage
|
|
33
|
+
|
|
34
|
+
%run_shared shared_file.ipynb
|
|
35
|
+
|
|
36
|
+
%run_shared {{ sample_notebook_name }}
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
template = Template(line.strip())
|
|
41
|
+
shared_file = template.render(local_ns)
|
|
42
|
+
if not shared_file:
|
|
43
|
+
raise ValueError('No shared file specified.')
|
|
44
|
+
if (shared_file.startswith("'") and shared_file.endswith("'")) or \
|
|
45
|
+
(shared_file.startswith('"') and shared_file.endswith('"')):
|
|
46
|
+
shared_file = shared_file[1:-1]
|
|
47
|
+
if not shared_file:
|
|
48
|
+
raise ValueError('No personal file specified.')
|
|
49
|
+
|
|
50
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
51
|
+
temp_file_path = os.path.join(temp_dir, shared_file)
|
|
52
|
+
sql_command = f"DOWNLOAD SHARED FILE '{shared_file}' TO '{temp_file_path}'"
|
|
53
|
+
|
|
54
|
+
# Execute the SQL command
|
|
55
|
+
self.shell.run_line_magic('sql', sql_command)
|
|
56
|
+
# Run the downloaded file
|
|
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)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
from .cluster import manage_cluster
|
|
3
|
+
from .files import manage_files
|
|
4
|
+
from .manager import get_token
|
|
5
|
+
from .region import manage_regions
|
|
6
|
+
from .workspace import get_organization
|
|
7
|
+
from .workspace import get_secret
|
|
8
|
+
from .workspace import get_stage
|
|
9
|
+
from .workspace import manage_workspaces
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""SingleStoreDB Cloud Billing Usage."""
|
|
3
|
+
import datetime
|
|
4
|
+
from typing import Any
|
|
5
|
+
from typing import Dict
|
|
6
|
+
from typing import List
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from .manager import Manager
|
|
10
|
+
from .utils import camel_to_snake
|
|
11
|
+
from .utils import vars_to_str
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class UsageItem(object):
|
|
15
|
+
"""Usage statistics."""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
start_time: datetime.datetime,
|
|
20
|
+
end_time: datetime.datetime,
|
|
21
|
+
owner_id: str,
|
|
22
|
+
resource_id: str,
|
|
23
|
+
resource_name: str,
|
|
24
|
+
resource_type: str,
|
|
25
|
+
value: str,
|
|
26
|
+
):
|
|
27
|
+
#: Starting time for the usage duration
|
|
28
|
+
self.start_time = start_time
|
|
29
|
+
|
|
30
|
+
#: Ending time for the usage duration
|
|
31
|
+
self.end_time = end_time
|
|
32
|
+
|
|
33
|
+
#: Owner ID
|
|
34
|
+
self.owner_id = owner_id
|
|
35
|
+
|
|
36
|
+
#: Resource ID
|
|
37
|
+
self.resource_id = resource_id
|
|
38
|
+
|
|
39
|
+
#: Resource name
|
|
40
|
+
self.resource_name = resource_name
|
|
41
|
+
|
|
42
|
+
#: Resource type
|
|
43
|
+
self.resource_type = resource_type
|
|
44
|
+
|
|
45
|
+
#: Usage statistic value
|
|
46
|
+
self.value = value
|
|
47
|
+
|
|
48
|
+
self._manager: Optional[Manager] = None
|
|
49
|
+
|
|
50
|
+
def __str__(self) -> str:
|
|
51
|
+
"""Return string representation."""
|
|
52
|
+
return vars_to_str(self)
|
|
53
|
+
|
|
54
|
+
def __repr__(self) -> str:
|
|
55
|
+
"""Return string representation."""
|
|
56
|
+
return str(self)
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def from_dict(
|
|
60
|
+
cls,
|
|
61
|
+
obj: Dict[str, Any],
|
|
62
|
+
manager: Manager,
|
|
63
|
+
) -> 'UsageItem':
|
|
64
|
+
"""
|
|
65
|
+
Convert dictionary to a ``UsageItem`` object.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
obj : dict
|
|
70
|
+
Key-value pairs to retrieve billling usage information from
|
|
71
|
+
manager : WorkspaceManager, optional
|
|
72
|
+
The WorkspaceManager the UsageItem belongs to
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
:class:`UsageItem`
|
|
77
|
+
|
|
78
|
+
"""
|
|
79
|
+
out = cls(
|
|
80
|
+
end_time=datetime.datetime.fromisoformat(obj['endTime']),
|
|
81
|
+
start_time=datetime.datetime.fromisoformat(obj['startTime']),
|
|
82
|
+
owner_id=obj['ownerId'],
|
|
83
|
+
resource_id=obj['resourceId'],
|
|
84
|
+
resource_name=obj['resourceName'],
|
|
85
|
+
resource_type=obj['resource_type'],
|
|
86
|
+
value=obj['value'],
|
|
87
|
+
)
|
|
88
|
+
out._manager = manager
|
|
89
|
+
return out
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class BillingUsageItem(object):
|
|
93
|
+
"""Billing usage item."""
|
|
94
|
+
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
description: str,
|
|
98
|
+
metric: str,
|
|
99
|
+
usage: List[UsageItem],
|
|
100
|
+
):
|
|
101
|
+
"""Use :attr:`WorkspaceManager.billing.usage` instead."""
|
|
102
|
+
#: Description of the usage metric
|
|
103
|
+
self.description = description
|
|
104
|
+
|
|
105
|
+
#: Name of the usage metric
|
|
106
|
+
self.metric = metric
|
|
107
|
+
|
|
108
|
+
#: Usage statistics
|
|
109
|
+
self.usage = list(usage)
|
|
110
|
+
|
|
111
|
+
self._manager: Optional[Manager] = None
|
|
112
|
+
|
|
113
|
+
def __str__(self) -> str:
|
|
114
|
+
"""Return string representation."""
|
|
115
|
+
return vars_to_str(self)
|
|
116
|
+
|
|
117
|
+
def __repr__(self) -> str:
|
|
118
|
+
"""Return string representation."""
|
|
119
|
+
return str(self)
|
|
120
|
+
|
|
121
|
+
@ classmethod
|
|
122
|
+
def from_dict(
|
|
123
|
+
cls,
|
|
124
|
+
obj: Dict[str, Any],
|
|
125
|
+
manager: Manager,
|
|
126
|
+
) -> 'BillingUsageItem':
|
|
127
|
+
"""
|
|
128
|
+
Convert dictionary to a ``BillingUsageItem`` object.
|
|
129
|
+
|
|
130
|
+
Parameters
|
|
131
|
+
----------
|
|
132
|
+
obj : dict
|
|
133
|
+
Key-value pairs to retrieve billling usage information from
|
|
134
|
+
manager : WorkspaceManager, optional
|
|
135
|
+
The WorkspaceManager the BillingUsageItem belongs to
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
:class:`BillingUsageItem`
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
out = cls(
|
|
143
|
+
description=obj['description'],
|
|
144
|
+
metric=str(camel_to_snake(obj['metric'])),
|
|
145
|
+
usage=[UsageItem.from_dict(x, manager) for x in obj['Usage']],
|
|
146
|
+
)
|
|
147
|
+
out._manager = manager
|
|
148
|
+
return out
|