Skip to content

Commit

Permalink
Merge pull request #224 from DanielSchiavini/fix/jupyter-error
Browse files Browse the repository at this point in the history
feat: error when jupyter plugin is not installed
  • Loading branch information
charles-cooper authored May 14, 2024
2 parents 1bf16f9 + 8dfd1b9 commit 83688de
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 124 deletions.
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,46 @@ 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.
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
Expand Down
18 changes: 15 additions & 3 deletions boa/integrations/jupyter/jupyter.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = `<h3 style="color: red">${error}</h3><pre>${command}</pre>`;
} else {
prompt(error, command);
}
return;
}
}

const body = stringify(await parsePromise(func(...args)));
Expand Down
3 changes: 2 additions & 1 deletion docs/source/testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
130 changes: 11 additions & 119 deletions examples/jupyter_browser_signer.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -6,130 +6,22 @@
"id": "94744db8",
"metadata": {},
"outputs": [],
"source": [
"import boa; from boa.network import NetworkEnv"
]
"source": "%load_ext boa.ipython"
},
{
"cell_type": "code",
"execution_count": 2,
"id": "ff9dfb06",
"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": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from boa.integrations.jupyter import BrowserSigner"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "814ff4f3",
"metadata": {},
"outputs": [],
"source": [
"boa.set_env(NetworkEnv(\"<rpc server address, e.g. an alchemy endpoint>\"))"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "a24872c9",
"metadata": {},
"outputs": [],
"execution_count": 2,
"source": [
"boa.env.add_account(BrowserSigner())"
]
"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": [
Expand All @@ -139,7 +31,7 @@
"<boa.vyper.contract.VyperDeployer at 0x7f5150614a90>"
]
},
"execution_count": 6,
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -158,7 +50,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 4,
"id": "c5b60ed3",
"metadata": {},
"outputs": [
Expand All @@ -178,7 +70,7 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 5,
"id": "bdbfc09c",
"metadata": {},
"outputs": [
Expand All @@ -189,7 +81,7 @@
"<storage: totalSupply=1000, balances={'0x...<truncated>': 1000}>"
]
},
"execution_count": 8,
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
Expand Down

0 comments on commit 83688de

Please sign in to comment.