Skip to content

Commit f81a90c

Browse files
committed
dry
1 parent 4ddb831 commit f81a90c

File tree

3 files changed

+332
-93
lines changed

3 files changed

+332
-93
lines changed

pystackql/magic_ext/base.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,57 @@
1+
# # pystackql/magic_ext/base.py
2+
3+
# """
4+
# Base Jupyter magic extension for PyStackQL.
5+
6+
# This module provides the base class for PyStackQL Jupyter magic extensions.
7+
# """
8+
9+
# from __future__ import print_function
10+
# from IPython.core.magic import Magics
11+
# from string import Template
12+
13+
# class BaseStackqlMagic(Magics):
14+
# """Base Jupyter magic extension enabling running StackQL queries.
15+
16+
# This extension allows users to conveniently run StackQL queries against cloud
17+
# or SaaS resources directly from Jupyter notebooks, and visualize the results in a tabular
18+
# format using Pandas DataFrames.
19+
# """
20+
# def __init__(self, shell, server_mode):
21+
# """Initialize the BaseStackqlMagic class.
22+
23+
# :param shell: The IPython shell instance.
24+
# :param server_mode: Whether to use server mode.
25+
# """
26+
# from ..core import StackQL
27+
# super(BaseStackqlMagic, self).__init__(shell)
28+
# self.stackql_instance = StackQL(server_mode=server_mode, output='pandas')
29+
30+
# def get_rendered_query(self, data):
31+
# """Substitute placeholders in a query template with variables from the current namespace.
32+
33+
# :param data: SQL query template containing placeholders.
34+
# :type data: str
35+
# :return: A SQL query with placeholders substituted.
36+
# :rtype: str
37+
# """
38+
# t = Template(data)
39+
# return t.substitute(self.shell.user_ns)
40+
41+
# def run_query(self, query):
42+
# """Execute a StackQL query
43+
44+
# :param query: StackQL query to be executed.
45+
# :type query: str
46+
# :return: Query results, returned as a Pandas DataFrame.
47+
# :rtype: pandas.DataFrame
48+
# """
49+
# # Check if the query starts with "registry pull" (case insensitive)
50+
# if query.strip().lower().startswith("registry pull"):
51+
# return self.stackql_instance.executeStmt(query)
52+
53+
# return self.stackql_instance.execute(query)
54+
155
# pystackql/magic_ext/base.py
256

357
"""
@@ -50,4 +104,46 @@ def run_query(self, query):
50104
if query.strip().lower().startswith("registry pull"):
51105
return self.stackql_instance.executeStmt(query)
52106

53-
return self.stackql_instance.execute(query)
107+
return self.stackql_instance.execute(query)
108+
109+
def _display_with_csv_download(self, df):
110+
"""Display DataFrame with CSV download link.
111+
112+
:param df: The DataFrame to display and make downloadable.
113+
"""
114+
import IPython.display
115+
116+
try:
117+
# Generate CSV data
118+
import io
119+
import base64
120+
csv_buffer = io.StringIO()
121+
df.to_csv(csv_buffer, index=False)
122+
csv_data = csv_buffer.getvalue()
123+
124+
# Encode to base64 for data URI
125+
csv_base64 = base64.b64encode(csv_data.encode()).decode()
126+
127+
# Create download link
128+
download_link = f'data:text/csv;base64,{csv_base64}'
129+
130+
# Display the DataFrame first
131+
IPython.display.display(df)
132+
133+
# Create and display the download button
134+
download_html = f'''
135+
<div style="margin-top: 10px;">
136+
<a href="{download_link}" download="stackql_results.csv"
137+
style="display: inline-block; padding: 8px 16px; background-color: #007cba;
138+
color: white; text-decoration: none; border-radius: 4px;
139+
font-family: Arial, sans-serif; font-size: 14px; border: none; cursor: pointer;">
140+
📥 Download CSV
141+
</a>
142+
</div>
143+
'''
144+
IPython.display.display(IPython.display.HTML(download_html))
145+
146+
except Exception as e:
147+
# If CSV generation fails, just display the DataFrame normally
148+
IPython.display.display(df)
149+
print(f"Error generating CSV download: {e}")

pystackql/magic_ext/local.py

Lines changed: 120 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,122 @@
1+
# # pystackql/magic_ext/local.py
2+
3+
# """
4+
# Local Jupyter magic extension for PyStackQL.
5+
6+
# This module provides a Jupyter magic command for running StackQL queries
7+
# using a local StackQL binary.
8+
# """
9+
10+
# from IPython.core.magic import (magics_class, line_cell_magic)
11+
# from IPython.display import display, HTML
12+
# from .base import BaseStackqlMagic
13+
# import argparse
14+
# import base64
15+
# import io
16+
17+
# @magics_class
18+
# class StackqlMagic(BaseStackqlMagic):
19+
# """Jupyter magic command for running StackQL queries in local mode."""
20+
21+
# def __init__(self, shell):
22+
# """Initialize the StackqlMagic class.
23+
24+
# :param shell: The IPython shell instance.
25+
# """
26+
# super().__init__(shell, server_mode=False)
27+
28+
# @line_cell_magic
29+
# def stackql(self, line, cell=None):
30+
# """A Jupyter magic command to run StackQL queries.
31+
32+
# Can be used as both line and cell magic:
33+
# - As a line magic: `%stackql QUERY`
34+
# - As a cell magic: `%%stackql [OPTIONS]` followed by the QUERY in the next line.
35+
36+
# :param line: The arguments and/or StackQL query when used as line magic.
37+
# :param cell: The StackQL query when used as cell magic.
38+
# :return: StackQL query results as a named Pandas DataFrame (`stackql_df`).
39+
# """
40+
# is_cell_magic = cell is not None
41+
42+
# if is_cell_magic:
43+
# parser = argparse.ArgumentParser()
44+
# parser.add_argument("--no-display", action="store_true", help="Suppress result display.")
45+
# parser.add_argument("--csv-download", action="store_true", help="Add CSV download link to output.")
46+
# args = parser.parse_args(line.split())
47+
# query_to_run = self.get_rendered_query(cell)
48+
# else:
49+
# args = None
50+
# query_to_run = self.get_rendered_query(line)
51+
52+
# results = self.run_query(query_to_run)
53+
# self.shell.user_ns['stackql_df'] = results
54+
55+
# if is_cell_magic and args and args.no_display:
56+
# return None
57+
# elif is_cell_magic and args and args.csv_download and not args.no_display:
58+
# self._display_with_csv_download(results)
59+
# return results
60+
# elif is_cell_magic and args and not args.no_display:
61+
# return results
62+
# elif not is_cell_magic:
63+
# return results
64+
65+
# def _display_with_csv_download(self, df):
66+
# """Display DataFrame with CSV download link.
67+
68+
# :param df: The DataFrame to display and make downloadable.
69+
# """
70+
# import IPython.display
71+
72+
# try:
73+
# # Generate CSV data
74+
# import io
75+
# import base64
76+
# csv_buffer = io.StringIO()
77+
# df.to_csv(csv_buffer, index=False)
78+
# csv_data = csv_buffer.getvalue()
79+
80+
# # Encode to base64 for data URI
81+
# csv_base64 = base64.b64encode(csv_data.encode()).decode()
82+
83+
# # Create download link
84+
# download_link = f'data:text/csv;base64,{csv_base64}'
85+
86+
# # Display the DataFrame first
87+
# IPython.display.display(df)
88+
89+
# # Create and display the download button
90+
# download_html = f'''
91+
# <div style="margin-top: 10px;">
92+
# <a href="{download_link}" download="stackql_results.csv"
93+
# style="display: inline-block; padding: 8px 16px; background-color: #007cba;
94+
# color: white; text-decoration: none; border-radius: 4px;
95+
# font-family: Arial, sans-serif; font-size: 14px; border: none; cursor: pointer;">
96+
# 📥 Download CSV
97+
# </a>
98+
# </div>
99+
# '''
100+
# IPython.display.display(IPython.display.HTML(download_html))
101+
102+
# except Exception as e:
103+
# # If CSV generation fails, just display the DataFrame normally
104+
# IPython.display.display(df)
105+
# print(f"Error generating CSV download: {e}")
106+
107+
# def load_ipython_extension(ipython):
108+
# """Load the non-server magic in IPython.
109+
110+
# This is called when running %load_ext pystackql.magic in a notebook.
111+
# It registers the %stackql and %%stackql magic commands.
112+
113+
# :param ipython: The IPython shell instance
114+
# """
115+
# # Create an instance of the magic class and register it
116+
# magic_instance = StackqlMagic(ipython)
117+
# ipython.register_magics(magic_instance)
118+
119+
1120
# pystackql/magic_ext/local.py
2121

3122
"""
@@ -8,11 +127,8 @@
8127
"""
9128

10129
from IPython.core.magic import (magics_class, line_cell_magic)
11-
from IPython.display import display, HTML
12130
from .base import BaseStackqlMagic
13131
import argparse
14-
import base64
15-
import io
16132

17133
@magics_class
18134
class StackqlMagic(BaseStackqlMagic):
@@ -62,48 +178,6 @@ def stackql(self, line, cell=None):
62178
elif not is_cell_magic:
63179
return results
64180

65-
def _display_with_csv_download(self, df):
66-
"""Display DataFrame with CSV download link.
67-
68-
:param df: The DataFrame to display and make downloadable.
69-
"""
70-
import IPython.display
71-
72-
try:
73-
# Generate CSV data
74-
import io
75-
import base64
76-
csv_buffer = io.StringIO()
77-
df.to_csv(csv_buffer, index=False)
78-
csv_data = csv_buffer.getvalue()
79-
80-
# Encode to base64 for data URI
81-
csv_base64 = base64.b64encode(csv_data.encode()).decode()
82-
83-
# Create download link
84-
download_link = f'data:text/csv;base64,{csv_base64}'
85-
86-
# Display the DataFrame first
87-
IPython.display.display(df)
88-
89-
# Create and display the download button
90-
download_html = f'''
91-
<div style="margin-top: 10px;">
92-
<a href="{download_link}" download="stackql_results.csv"
93-
style="display: inline-block; padding: 8px 16px; background-color: #007cba;
94-
color: white; text-decoration: none; border-radius: 4px;
95-
font-family: Arial, sans-serif; font-size: 14px; border: none; cursor: pointer;">
96-
📥 Download CSV
97-
</a>
98-
</div>
99-
'''
100-
IPython.display.display(IPython.display.HTML(download_html))
101-
102-
except Exception as e:
103-
# If CSV generation fails, just display the DataFrame normally
104-
IPython.display.display(df)
105-
print(f"Error generating CSV download: {e}")
106-
107181
def load_ipython_extension(ipython):
108182
"""Load the non-server magic in IPython.
109183
@@ -114,4 +188,4 @@ def load_ipython_extension(ipython):
114188
"""
115189
# Create an instance of the magic class and register it
116190
magic_instance = StackqlMagic(ipython)
117-
ipython.register_magics(magic_instance)
191+
ipython.register_magics(magic_instance)

0 commit comments

Comments
 (0)