Skip to content

Commit 809f513

Browse files
feat(magic): add run_personal and run_shared magic commands (#50)
* feat(magic): add run_personal and run_shared magic commands * feat(magic): add support for jinja2 templates * refactor(magic): create singlestoredb.magics module * feat(magic): use tempfile.TemporaryDirectory for downloaded file
1 parent 1b6131a commit 809f513

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed

singlestoredb/magics/__init__.py

+34
Original file line numberDiff line numberDiff line change
@@ -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))

singlestoredb/magics/run_personal.py

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import os
2+
import tempfile
3+
from typing import Any
4+
5+
from IPython.core.interactiveshell import InteractiveShell
6+
from IPython.core.magic import line_magic
7+
from IPython.core.magic import Magics
8+
from IPython.core.magic import magics_class
9+
from IPython.core.magic import needs_local_scope
10+
from IPython.core.magic import no_var_expand
11+
from jinja2 import Template
12+
13+
14+
@magics_class
15+
class RunPersonalMagic(Magics):
16+
def __init__(self, shell: InteractiveShell):
17+
Magics.__init__(self, shell=shell)
18+
19+
@no_var_expand
20+
@needs_local_scope
21+
@line_magic('run_personal')
22+
def run_personal(self, line: str, local_ns: Any = None) -> Any:
23+
"""
24+
Downloads a personal file using the %sql magic and then runs it using %run.
25+
26+
Examples::
27+
28+
# Line usage
29+
30+
%run_personal personal_file.ipynb
31+
32+
%run_personal {{ sample_notebook_name }}
33+
34+
"""
35+
36+
template = Template(line.strip())
37+
personal_file = template.render(local_ns)
38+
if not personal_file:
39+
raise ValueError('No personal file specified.')
40+
if (personal_file.startswith("'") and personal_file.endswith("'")) or \
41+
(personal_file.startswith('"') and personal_file.endswith('"')):
42+
personal_file = personal_file[1:-1]
43+
if not personal_file:
44+
raise ValueError('No personal file specified.')
45+
46+
with tempfile.TemporaryDirectory() as temp_dir:
47+
temp_file_path = os.path.join(temp_dir, personal_file)
48+
sql_command = (
49+
f"DOWNLOAD PERSONAL FILE '{personal_file}' "
50+
f"TO '{temp_file_path}'"
51+
)
52+
53+
# Execute the SQL command
54+
self.shell.run_line_magic('sql', sql_command)
55+
# Run the downloaded file
56+
self.shell.run_line_magic('run', f'"{temp_file_path}"')

singlestoredb/magics/run_shared.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import os
2+
import tempfile
3+
from typing import Any
4+
5+
from IPython.core.interactiveshell import InteractiveShell
6+
from IPython.core.magic import line_magic
7+
from IPython.core.magic import Magics
8+
from IPython.core.magic import magics_class
9+
from IPython.core.magic import needs_local_scope
10+
from IPython.core.magic import no_var_expand
11+
from jinja2 import Template
12+
13+
14+
@magics_class
15+
class RunSharedMagic(Magics):
16+
def __init__(self, shell: InteractiveShell):
17+
Magics.__init__(self, shell=shell)
18+
19+
@no_var_expand
20+
@needs_local_scope
21+
@line_magic('run_shared')
22+
def run_shared(self, line: str, local_ns: Any = None) -> Any:
23+
"""
24+
Downloads a shared file using the %sql magic and then runs it using %run.
25+
26+
Examples::
27+
28+
# Line usage
29+
30+
%run_shared shared_file.ipynb
31+
32+
%run_shared {{ sample_notebook_name }}
33+
34+
"""
35+
36+
template = Template(line.strip())
37+
shared_file = template.render(local_ns)
38+
if not shared_file:
39+
raise ValueError('No shared file specified.')
40+
if (shared_file.startswith("'") and shared_file.endswith("'")) or \
41+
(shared_file.startswith('"') and shared_file.endswith('"')):
42+
shared_file = shared_file[1:-1]
43+
if not shared_file:
44+
raise ValueError('No personal file specified.')
45+
46+
with tempfile.TemporaryDirectory() as temp_dir:
47+
temp_file_path = os.path.join(temp_dir, shared_file)
48+
sql_command = f"DOWNLOAD SHARED FILE '{shared_file}' TO '{temp_file_path}'"
49+
50+
# Execute the SQL command
51+
self.shell.run_line_magic('sql', sql_command)
52+
# Run the downloaded file
53+
self.shell.run_line_magic('run', f'"{temp_file_path}"')

0 commit comments

Comments
 (0)