From 7bf657e8260cbbdee136ca6bcff1d5a63e8af128 Mon Sep 17 00:00:00 2001 From: Daniel Schiavini Date: Tue, 14 May 2024 09:41:31 +0200 Subject: [PATCH 1/3] Add error when we cannot reach the backend Fixes #197 --- boa/integrations/jupyter/jupyter.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/boa/integrations/jupyter/jupyter.js b/boa/integrations/jupyter/jupyter.js index 310989a4..047ded94 100644 --- a/boa/integrations/jupyter/jupyter.js +++ b/boa/integrations/jupyter/jupyter.js @@ -87,10 +87,22 @@ /** Call the backend when the given function is called, handling errors */ const handleCallback = func => async (token, ...args) => { if (!colab) { - // Check if the cell was already executed. In Colab, eval_js() doesn't replay. + // Check backend and whether cell was executed. In Colab, eval_js() doesn't replay. const response = await fetch(`${base}/titanoboa_jupyterlab/callback/${token}`); - // !response.ok indicates the cell has already been executed - if (!response.ok) return; + if (response.status === 404 && response.headers.get('Content-Type') === 'application/json') { + return; // the cell has already been executed + } + if (!response.ok) { + const error = 'Could not connect to the titanoboa backend. Please make sure the Jupyter extension is installed by running the following command:'; + const command = 'jupyter lab extension enable boa'; + if (element) { + element.style.display = "block"; // show the output element in JupyterLab + element.innerHTML = `

${error}

${command}
`; + } else { + prompt(error, command); + } + return; + } } const body = stringify(await parsePromise(func(...args))); From 32f93b0ad08b80b928c4b8aeba0e9db872a2dd15 Mon Sep 17 00:00:00 2001 From: Daniel Schiavini Date: Tue, 14 May 2024 09:50:31 +0200 Subject: [PATCH 2/3] Update documentation --- README.md | 3 +- docs/source/testing.rst | 3 +- examples/jupyter_browser_signer.ipynb | 132 ++++---------------------- 3 files changed, 25 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index fb311d6e..a5e9b97b 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,8 @@ Cast current deployed addresses to vyper contract ### Jupyter Integration -You can use Jupyter to execute titanoboa code in network mode from your browser using any wallet, using `boa.integrations.jupyter.BrowserSigner` as a drop-in replacement for `eth_account.Account`. For a full example, please see [this example Jupyter notebook](examples/jupyter_browser_signer.ipynb) +You can use Jupyter to execute titanoboa code in network mode from your browser using any wallet, using `BrowserSigner` as a drop-in replacement for `eth_account.Account`. +For a full example, please see [this example Jupyter notebook](examples/jupyter_browser_signer.ipynb) ### Basic tests diff --git a/docs/source/testing.rst b/docs/source/testing.rst index 71075f27..cbfc90e1 100644 --- a/docs/source/testing.rst +++ b/docs/source/testing.rst @@ -151,7 +151,8 @@ ipython Vyper Cells Titanoboa supports ipython Vyper cells. This means that you can write Vyper code in a ipython/Jupyter Notebook environment and execute it as if it was a Python cell (the contract will be compiled instead, and a ``ContractFactory`` will be returned). -To enable this feature, execute ``%load_ext boa.ipython`` in a cell. +You can use Jupyter to execute titanoboa code in network mode from your browser using any wallet, using your wallet to sign transactions and call the RPC. +For a full example, please see `this example Jupyter notebook <../../examples/jupyter_browser_signer.ipynb>`_. .. code-block:: python diff --git a/examples/jupyter_browser_signer.ipynb b/examples/jupyter_browser_signer.ipynb index 886eb00b..e50fcfd9 100644 --- a/examples/jupyter_browser_signer.ipynb +++ b/examples/jupyter_browser_signer.ipynb @@ -1,111 +1,33 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "id": "94744db8", "metadata": {}, - "outputs": [], + "cell_type": "markdown", "source": [ - "import boa; from boa.network import NetworkEnv" - ] + "Before being able to use the plugin, you need to install it. You can do this by running the following command:\n", + "```bash\n", + "jupyter lab extension enable boa\n", + "```\n", + "\n", + "We provide a multi-user setup with JupyterLab in [try.vyperlang.org](https://try.vyperlang.org/).\n", + "The source code for this website is available in [GitHub](https://github.com/vyperlang/try.vyperlang.org).\n", + "\n", + "It is also possible to run our plugin in [Google Colab](https://colab.research.google.com/).\n", + "To do this, you need to install the plugin by running the following commands:\n", + "```jupyter\n", + "!pip install git+https://github.com/vyperlang/titanoboa\n", + "%load_ext boa.ipython\n", + "```" + ], + "id": "1eb33cb4f02a9a6c" }, { "cell_type": "code", - "execution_count": 2, - "id": "ff9dfb06", + "execution_count": 1, + "id": "94744db8", "metadata": {}, "outputs": [], - "source": [ - "%load_ext boa.ipython" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "9f241bf5", - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": [ - "\n", - "require.config({\n", - " paths: {\n", - " //ethers: \"https://cdnjs.cloudflare.com/ajax/libs/ethers/5.7.2/ethers.umd.min\"\n", - " ethers: \"https://cdnjs.cloudflare.com/ajax/libs/ethers/6.4.2/ethers.umd.min\"\n", - " }\n", - "});\n", - "\n", - "require(['ethers'], function(ethers) {\n", - " // Initialize ethers\n", - " let provider = new ethers.BrowserProvider(window.ethereum);\n", - "\n", - " // check that we have a signer for this account\n", - " Jupyter.notebook.kernel.comm_manager.register_target('get_signer', function(c, msg) {\n", - " // console.log(\"get_signer created\", c)\n", - " c.on_msg(function(msg) {\n", - " // console.log(\"get_signer called\", c)\n", - " let account = msg.content.data.account\n", - " provider.getSigner(account).then(signer => {\n", - " // console.log(\"success\", signer)\n", - " c.send({\"success\": signer});\n", - " }).catch(function(error) {\n", - " console.error(\"got error, percolating up:\", error);\n", - " c.send({\"error\": error});\n", - " });\n", - " });\n", - " });\n", - "\n", - " Jupyter.notebook.kernel.comm_manager.register_target(\"send_transaction\", function(c, msg) {\n", - " c.on_msg(function(msg) {\n", - " let tx_data = msg.content.data.transaction_data;\n", - " let account = msg.content.data.account\n", - " provider.getSigner(account).then(signer => {\n", - " signer.sendTransaction(tx_data).then(response => {\n", - " console.log(response);\n", - " c.send({\"success\": response});\n", - " }).catch(function(error) {\n", - " console.error(\"got error, percolating up:\", error);\n", - " c.send({\"error\": error});\n", - " });\n", - " }).catch(function(error) {\n", - " console.error(\"got error, percolating up:\", error);\n", - " c.send({\"error\": error});\n", - " });\n", - " });\n", - " });\n", - "});\n", - "\n", - "Jupyter.notebook.kernel.comm_manager.register_target(\"test_comm\", function(comm, msg) {\n", - " console.log(\"ENTER\", comm);\n", - " /*comm.on_close(function(msg) {\n", - " console.log(\"CLOSING\", msg);\n", - " });\n", - " */\n", - "\n", - " comm.on_msg(function(msg) {\n", - " console.log(\"ENTER 2\", comm);\n", - " console.log(\"ENTER 3\", msg.content.data);\n", - " setTimeout(() => {\n", - " comm.send({\"success\": \"hello\", \"echo\": msg.content.data});\n", - " comm.close();\n", - " console.log(comm);\n", - " }, 350);\n", - " });\n", - "});\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from boa.integrations.jupyter import BrowserSigner" - ] + "source": "import boa" }, { "cell_type": "code", @@ -113,19 +35,7 @@ "id": "814ff4f3", "metadata": {}, "outputs": [], - "source": [ - "boa.set_env(NetworkEnv(\"\"))" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "a24872c9", - "metadata": {}, - "outputs": [], - "source": [ - "boa.env.add_account(BrowserSigner())" - ] + "source": "boa.set_browser_env() # this will use the browser signer and the browser RPC" }, { "cell_type": "code", From 8dfd1b967c0618c6dc08123a312abf9eb127db39 Mon Sep 17 00:00:00 2001 From: Daniel Schiavini Date: Tue, 14 May 2024 14:35:49 +0200 Subject: [PATCH 3/3] Move Jupyter installation to README --- README.md | 40 +++++++++++++++++++++++- examples/jupyter_browser_signer.ipynb | 44 ++++++++------------------- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index a5e9b97b..b7e39576 100644 --- a/README.md +++ b/README.md @@ -209,9 +209,47 @@ Cast current deployed addresses to vyper contract ### Jupyter Integration -You can use Jupyter to execute titanoboa code in network mode from your browser using any wallet, using `BrowserSigner` as a drop-in replacement for `eth_account.Account`. +You can use Jupyter to execute titanoboa code in network mode from your browser using any wallet. +We provide a `BrowserSigner` as a drop-in replacement for `eth_account.Account`. +The `BrowserRPC` may be used to interact with the RPC server from the browser. + For a full example, please see [this example Jupyter notebook](examples/jupyter_browser_signer.ipynb) +#### JupyterLab + +Before being able to use the plugin, you need to install it. +You can do this by running the following command in the terminal: + +```bash +pip install titanoboa +jupyter lab extension enable boa +``` +To activate our IPython extension, you need to run the following command in the notebook: +```jupyter +%load_ext boa.ipython +``` + +For ease of use, add the following to `ipython_config.py`: +```python +c.InteractiveShellApp.extensions = ["boa.ipython"] +c.InteractiveShellApp.exec_lines = ['import boa'] +``` + +We provide a multi-user setup with JupyterLab in [try.vyperlang.org](https://try.vyperlang.org/), where the extension is installed and activated. +The source code for this website is available in the [GitHub repository](https://github.com/vyperlang/try.vyperlang.org). + +#### Colab +It is also possible to run our plugin in [Google Colab](https://colab.research.google.com/). +To do this, you need to install the plugin by running the following commands: +```jupyter +!pip install titanoboa +%load_ext boa.ipython +``` + +#### IPython extensions + +This activates the `%%vyper`, `%%contract` and `%%eval` magics. + ### Basic tests diff --git a/examples/jupyter_browser_signer.ipynb b/examples/jupyter_browser_signer.ipynb index e50fcfd9..5da5f571 100644 --- a/examples/jupyter_browser_signer.ipynb +++ b/examples/jupyter_browser_signer.ipynb @@ -1,45 +1,27 @@ { "cells": [ - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "Before being able to use the plugin, you need to install it. You can do this by running the following command:\n", - "```bash\n", - "jupyter lab extension enable boa\n", - "```\n", - "\n", - "We provide a multi-user setup with JupyterLab in [try.vyperlang.org](https://try.vyperlang.org/).\n", - "The source code for this website is available in [GitHub](https://github.com/vyperlang/try.vyperlang.org).\n", - "\n", - "It is also possible to run our plugin in [Google Colab](https://colab.research.google.com/).\n", - "To do this, you need to install the plugin by running the following commands:\n", - "```jupyter\n", - "!pip install git+https://github.com/vyperlang/titanoboa\n", - "%load_ext boa.ipython\n", - "```" - ], - "id": "1eb33cb4f02a9a6c" - }, { "cell_type": "code", "execution_count": 1, "id": "94744db8", "metadata": {}, "outputs": [], - "source": "import boa" + "source": "%load_ext boa.ipython" }, { - "cell_type": "code", - "execution_count": 4, - "id": "814ff4f3", "metadata": {}, + "cell_type": "code", "outputs": [], - "source": "boa.set_browser_env() # this will use the browser signer and the browser RPC" + "execution_count": 2, + "source": [ + "import boa\n", + "boa.set_browser_env() # this will use the browser signer and the browser RPC" + ], + "id": "b724995f3df612f0" }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 3, "id": "1e98969d", "metadata": {}, "outputs": [ @@ -49,7 +31,7 @@ "" ] }, - "execution_count": 6, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -68,7 +50,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 4, "id": "c5b60ed3", "metadata": {}, "outputs": [ @@ -88,7 +70,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 5, "id": "bdbfc09c", "metadata": {}, "outputs": [ @@ -99,7 +81,7 @@ "': 1000}>" ] }, - "execution_count": 8, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" }