diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..8786236 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +{ + "image": "mcr.microsoft.com/devcontainers/universal:2", + "containerEnv": { + }, + "hostRequirements": { + "cpus": 2 + }, + "waitFor": "onCreateCommand", + "updateContentCommand": "pip install -e ", + "postCreateCommand": "", + "postStartCommand": "git reset --hard && git clean -fd", + "customizations": { + "codespaces": { + "openFiles": [ + "notebooks/demo.ipynb" + ] + }, + "vscode": { + "extensions": [ + "ms-toolsai.jupyter", + "ms-python.python" + ] + } + } +} \ No newline at end of file diff --git a/notebooks/demo.ipynb b/notebooks/demo.ipynb new file mode 100644 index 0000000..c980af3 --- /dev/null +++ b/notebooks/demo.ipynb @@ -0,0 +1,150 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PyStackQL Development Demo\n", + "\n", + "This notebook demonstrates how to use the development version of PyStackQL directly from the source code. Any changes you make to the PyStackQL code will be immediately reflected here." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# First, let's check what version of PyStackQL we're using\n", + "import pystackql\n", + "print(f\"PyStackQL Version: {pystackql.__version__}\")\n", + "\n", + "# Check the location of the package to confirm we're using the development version\n", + "print(f\"Package Location: {pystackql.__file__}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Load the magic extension\n", + "%load_ext pystackql.magic" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic Query Test\n", + "\n", + "Let's run a simple query to test that everything is working:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%stackql SELECT 42 as answer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## CSV Download Test\n", + "\n", + "Let's test the CSV download functionality:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%stackql --csv-download\n", + "SELECT \n", + " 'Python' as language,\n", + " 'Development' as mode,\n", + " 'PyStackQL' as package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cloud Provider Functionality\n", + "\n", + "If you have credentials configured, you can test actual cloud provider queries:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Uncomment and run the appropriate provider query based on your available credentials\n", + "\n", + "# AWS Example\n", + "# %stackql DESCRIBE aws.ec2.instances\n", + "\n", + "# GitHub Example\n", + "# %stackql registry pull github\n", + "# %stackql SELECT login FROM github.users.followers WHERE username = 'stackql'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Development Tips\n", + "\n", + "1. After modifying PyStackQL code, you don't need to reinstall the package - changes are reflected immediately\n", + "2. You can run tests from the terminal with `pytest tests/`\n", + "3. If you modify deep core functionality, you may need to restart the kernel\n", + "4. To debug issues, you can use Python's built-in debugging tools:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Example debugging a PyStackQL function\n", + "from pystackql.core import StackQL\n", + "\n", + "# Get instance properties\n", + "stackql = StackQL()\n", + "props = stackql.properties()\n", + "print(props)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python (PyStackQL Dev)", + "language": "python", + "name": "pystackql-dev" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/pystackql/magic_ext/base.py b/pystackql/magic_ext/base.py index 7a647f9..0febcc3 100644 --- a/pystackql/magic_ext/base.py +++ b/pystackql/magic_ext/base.py @@ -50,4 +50,46 @@ def run_query(self, query): if query.strip().lower().startswith("registry pull"): return self.stackql_instance.executeStmt(query) - return self.stackql_instance.execute(query) \ No newline at end of file + return self.stackql_instance.execute(query) + + def _display_with_csv_download(self, df): + """Display DataFrame with CSV download link. + + :param df: The DataFrame to display and make downloadable. + """ + import IPython.display + + try: + # Generate CSV data + import io + import base64 + csv_buffer = io.StringIO() + df.to_csv(csv_buffer, index=False) + csv_data = csv_buffer.getvalue() + + # Encode to base64 for data URI + csv_base64 = base64.b64encode(csv_data.encode()).decode() + + # Create download link + download_link = f'data:text/csv;base64,{csv_base64}' + + # Display the DataFrame first + IPython.display.display(df) + + # Create and display the download button + download_html = f''' +
+ ''' + IPython.display.display(IPython.display.HTML(download_html)) + + except Exception as e: + # If CSV generation fails, just display the DataFrame normally + IPython.display.display(df) + print(f"Error generating CSV download: {e}") \ No newline at end of file diff --git a/pystackql/magic_ext/local.py b/pystackql/magic_ext/local.py index ba98d99..e88479b 100644 --- a/pystackql/magic_ext/local.py +++ b/pystackql/magic_ext/local.py @@ -8,11 +8,8 @@ """ from IPython.core.magic import (magics_class, line_cell_magic) -from IPython.display import display, HTML from .base import BaseStackqlMagic import argparse -import base64 -import io @magics_class class StackqlMagic(BaseStackqlMagic): @@ -62,48 +59,6 @@ def stackql(self, line, cell=None): elif not is_cell_magic: return results - def _display_with_csv_download(self, df): - """Display DataFrame with CSV download link. - - :param df: The DataFrame to display and make downloadable. - """ - import IPython.display - - try: - # Generate CSV data - import io - import base64 - csv_buffer = io.StringIO() - df.to_csv(csv_buffer, index=False) - csv_data = csv_buffer.getvalue() - - # Encode to base64 for data URI - csv_base64 = base64.b64encode(csv_data.encode()).decode() - - # Create download link - download_link = f'data:text/csv;base64,{csv_base64}' - - # Display the DataFrame first - IPython.display.display(df) - - # Create and display the download button - download_html = f''' - - ''' - IPython.display.display(IPython.display.HTML(download_html)) - - except Exception as e: - # If CSV generation fails, just display the DataFrame normally - IPython.display.display(df) - print(f"Error generating CSV download: {e}") - def load_ipython_extension(ipython): """Load the non-server magic in IPython. @@ -114,4 +69,4 @@ def load_ipython_extension(ipython): """ # Create an instance of the magic class and register it magic_instance = StackqlMagic(ipython) - ipython.register_magics(magic_instance) + ipython.register_magics(magic_instance) \ No newline at end of file diff --git a/pystackql/magic_ext/server.py b/pystackql/magic_ext/server.py index 074603f..70d561c 100644 --- a/pystackql/magic_ext/server.py +++ b/pystackql/magic_ext/server.py @@ -8,11 +8,8 @@ """ from IPython.core.magic import (magics_class, line_cell_magic) -from IPython.display import display, HTML from .base import BaseStackqlMagic import argparse -import base64 -import io @magics_class class StackqlServerMagic(BaseStackqlMagic): @@ -64,50 +61,8 @@ def stackql(self, line, cell=None): else: return results - def _display_with_csv_download(self, df): - """Display DataFrame with CSV download link. - - :param df: The DataFrame to display and make downloadable. - """ - import IPython.display - - try: - # Generate CSV data - import io - import base64 - csv_buffer = io.StringIO() - df.to_csv(csv_buffer, index=False) - csv_data = csv_buffer.getvalue() - - # Encode to base64 for data URI - csv_base64 = base64.b64encode(csv_data.encode()).decode() - - # Create download link - download_link = f'data:text/csv;base64,{csv_base64}' - - # Display the DataFrame first - IPython.display.display(df) - - # Create and display the download button - download_html = f''' - - ''' - IPython.display.display(IPython.display.HTML(download_html)) - - except Exception as e: - # If CSV generation fails, just display the DataFrame normally - IPython.display.display(df) - print(f"Error generating CSV download: {e}") - def load_ipython_extension(ipython): """Load the server magic in IPython.""" # Create an instance of the magic class and register it magic_instance = StackqlServerMagic(ipython) - ipython.register_magics(magic_instance) + ipython.register_magics(magic_instance) \ No newline at end of file