From a493a520e7ebed5a9b7a4b9d23fe91bef5a1dd3c Mon Sep 17 00:00:00 2001 From: Zander Hill Date: Tue, 16 Apr 2024 00:35:59 -0500 Subject: [PATCH] Add mechanism for prefixing all cells with a prompt mechanism --- runbook/__init__.py | 1 + runbook/add_prompt_preprocessor.py | 55 ++++++++++++++++++++++++++++++ runbook/cli/commands/convert.py | 31 +++++++++++++---- 3 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 runbook/add_prompt_preprocessor.py diff --git a/runbook/__init__.py b/runbook/__init__.py index e19434e..b15124f 100644 --- a/runbook/__init__.py +++ b/runbook/__init__.py @@ -1 +1,2 @@ __version__ = "0.3.3" +from .add_prompt_preprocessor import AddPromptPreprocessor diff --git a/runbook/add_prompt_preprocessor.py b/runbook/add_prompt_preprocessor.py new file mode 100644 index 0000000..7628054 --- /dev/null +++ b/runbook/add_prompt_preprocessor.py @@ -0,0 +1,55 @@ +import base64 + +from nbconvert.preprocessors import Preprocessor + + +class AddPromptPreprocessor(Preprocessor): + """Add Prompt Preprocessor for Typescript""" + + has_import_added = False + # TODO don't re-import a bazillion times + import_statement = """ +import { decodeBase64 } from "https://deno.land/std@0.222.1/encoding/base64.ts"; +import { setTheme, printHighlight } from 'npm:@speed-highlight/core/terminal' + +await setTheme('default') +const syntaxPrint = async (code: string) => { + return await printHighlight(code, 'ts') +} + + """ + + def prompt_str(self, base64Code): + return ( + f""" +var _promptToRun = `{base64Code}`; +await syntaxPrint(new TextDecoder().decode(decodeBase64(_promptToRun))) +console.log("") +console.log("") +console.log("%cReady to run the above code?", "color: red;") +var _promptResult = prompt("Choose (y/n):"); +""" + + """ +if(!_promptResult.match(/y/i)) { + throw Error("You rejected progress") +} +console.log("") +""" + ) + + def preprocess_cell(self, cell, resources, index): + if "source" in cell and cell.cell_type == "code": + if type(cell.source) is str: + s = [cell.source] + else: + s = cell.source + + base64code = base64.b64encode("".join(s).encode("utf-8")).decode("utf-8") + s.insert(0, self.prompt_str(base64code)) + + if not self.has_import_added: + s.insert(0, self.import_statement) + self.has_import_added = True + + cell.source = s + return cell, resources diff --git a/runbook/cli/commands/convert.py b/runbook/cli/commands/convert.py index ee53e46..d529da8 100644 --- a/runbook/cli/commands/convert.py +++ b/runbook/cli/commands/convert.py @@ -1,6 +1,9 @@ +import tempfile from os import path import click +import nbformat +from runbook.add_prompt_preprocessor import AddPromptPreprocessor from runbook.cli.completions import EditableNotebook from runbook.cli.validators import validate_runbook_file_path @@ -15,15 +18,29 @@ "output", type=click.Path(exists=False, file_okay=True, writable=True), ) +@click.option( + "-i", + "--insert-prompts", + default=False, + help="Insert prompt statements at start of each cell", +) @click.pass_context -def convert(ctx, filename, output): +def convert(ctx, filename, output, insert_prompts): """Convert an existing runbook to different format""" # Must override argv because it's used in launch instance and there isn't a way # to pass via argument in ExtensionApp.lauch_instance - # TODO: - argv = [path.abspath(filename), "--output", output] - # Lazily loaded for performance - from jupytext.cli import jupytext as jupytext_main - jupytext_main(args=argv) - # TODO: insert post run hooks here + with tempfile.NamedTemporaryFile(suffix=".ipynb") as fp: + content = nbformat.reads(open(filename).read(), as_version=4) + if content.metadata.get("kernelspec").get("name") == "deno": + (nb, _resources) = AddPromptPreprocessor().preprocess(content, {}) + else: + nb = content + with tempfile.NamedTemporaryFile(suffix=".ipynb") as fp: + nbformat.write(nb, fp.name) + argv = [path.abspath(fp.name), "--output", output] + # Lazily loaded for performance + from jupytext.cli import jupytext as jupytext_main + + print(f"Running jupytext {argv}") + jupytext_main(args=argv)