Skip to content

Update to Pyscript 2024.5.2 #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions docs/example_md.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,30 @@ py-config:

# Example with MyST

## `py-repl` and `py-terminal`
## `py-editor` and `py-terminal`

We can create a REPL which will output to a `div` and print `stdout` to a terminal with:

````md
```{py-repl}
:output: replOutput
```{py-editor}

print("hallo world")
import matplotlib.pyplot as plt
plt.plot([1, 2, 3])
plt.gcf()
```

<div id="replOutput"></div>

```{py-terminal}
```
````

Press `shift+enter` to run the code.

```{py-repl}
:output: replOutput
```{py-editor}

print("hallo world")
import matplotlib.pyplot as plt
plt.plot([1, 2, 3])
plt.gcf()
```

<div id="replOutput"></div>

```{py-terminal}
```

## `py-script` application

Here is a simple application to replace "a" with "b", using the `py-script` directive:
Expand Down
70 changes: 54 additions & 16 deletions docs/example_rst.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,80 @@
Example with RST
================

`py-repl` and `py-terminal`
----------------------------
`py-editor` and `py-terminal`
-----------------------------

We can create a REPL which will output to a `div` and print `stdout` to a terminal with:
We can create an editor cell which will print its `stdout`:

.. code-block:: restructuredtext

.. py-repl::
:output: replOutput
.. py-editor::

print("hallo world")
import matplotlib.pyplot as plt
plt.plot([1, 2, 3])
plt.gcf()

.. raw:: html

<div id="replOutput"></div>

.. py-terminal::

Press `shift+enter` to run the code.

.. py-repl::
:output: replOutput
.. py-editor::

print("hallo world")
import matplotlib.pyplot as plt
plt.plot([1, 2, 3])
plt.gcf()

.. raw:: html
By default, each editor uses a separate copy of the Python interpreter. Code blocks with the same `env` (environment) share a copy of the Python interpreter:

.. code-block:: restructuredtext

.. py-editor::
:env: one

x = 1

.. py-editor::
:env: one

print(x)

.. py-editor::
:env: two

print(x) # Error: x is not defined

Add the `setup` option to an editor tag in a given environment to include code that will run just before the first time the visible code in a block runs in that environment. Code in a `setup` block is invisible to the user. This is useful for setting up variables, imports, etc without cluttering up the editor cells.

.. code-block:: restructuredtext

.. py-editor::
:env: one
:setup:

# This code is not visible on the page
from datetime import datetime

.. py-editor::
:env: one

print(datetime.now())

Use the `config` option to specify the url of a `PyScript Configuration File <https://docs.pyscript.net/2024.5.2/user-guide/configuration/>`_:

.. code-block:: toml

# config.toml
packages = ['numpy', 'pandas']

.. code-block:: restructuredtext

.. py-editor::
:config: config.toml

<div id="replOutput"></div>
import numpy as np
import pandas as pd

.. py-terminal::
s = pd.Series([1, 3, 5, np.nan, 6, 8])

`py-script` application
-----------------------
Expand Down
76 changes: 56 additions & 20 deletions src/sphinx_pyscript.py → sphinx_pyscript/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""A sphinx extension for adding pyscript to a page"""

__version__ = "0.1.0"
__version__ = "0.2.0"

import json
from pathlib import Path
Expand All @@ -10,23 +10,29 @@
from docutils.parsers.rst import directives
from sphinx.application import Sphinx
from sphinx.util.docutils import SphinxDirective
from sphinx.util.fileutil import copy_asset_file
from sphinx.util.logging import getLogger

DEFAULT_VERSION = "2024.5.2"


def setup(app: Sphinx):
"""Setup the extension"""
app.add_config_value(
"pyscript_js", "https://pyscript.net/releases/2022.12.1/pyscript.js", "env"
"pyscript_js", f"https://pyscript.net/releases/{DEFAULT_VERSION}/core.js", "env"
)
app.add_config_value(
"pyscript_css", "https://pyscript.net/releases/2022.12.1/pyscript.css", "env"
"pyscript_css",
f"https://pyscript.net/releases/{DEFAULT_VERSION}/core.css",
"env",
)
app.add_directive("py-config", PyConfig)
app.add_directive("py-script", PyScript)
app.add_directive("py-repl", PyRepl)
app.add_directive("py-editor", PyEditor)
app.add_directive("py-terminal", PyTerminal)
app.connect("doctree-read", doctree_read)
app.connect("html-page-context", add_html_context)
app.connect("env-updated", copy_asset_files)
return {"version": __version__, "parallel_read_safe": True}


Expand Down Expand Up @@ -72,52 +78,75 @@ def run(self):
code = "\n".join(self.content)
else:
raise self.error("Must provide either content or the 'file' option")
return [nodes.raw("", f"<py-script>\n{code}\n</py-script>\n", format="html")]
return [
nodes.raw("", f"<script type='py'>\n{code}\n</script>\n", format="html")
]


class PyRepl(SphinxDirective):
"""Add a py-repl tag"""
class PyEditor(SphinxDirective):
"""Add a py-editor tag"""

has_content = True

"""
Notes on <py-editor> options. See https://docs.pyscript.net/2024.5.2/user-guide/editor/ for details
env: The name of a particular instance of the CPython interpreter. Cells with the same 'env' share an interpreter
setup: designates a 'setup' tag
config: The URL of a PyScript configuration file (TOML or JSON), or an inline configuration
"""
option_spec = {
"auto-generate": directives.flag,
"output": directives.unchanged,
"env": directives.unchanged,
"setup": directives.flag,
"config": directives.unchanged,
}

def run(self):
"""Add the py-repl tag"""
"""Add the py-editor tag"""
attrs = ""
code = ""
if "auto-generate" in self.options:
attrs += ' auto-generate="true"'
if "output" in self.options:
attrs += f' output="{self.options["output"]}"'
if "env" in self.options:
attrs += f' env="{self.options["""env"""]}"'
if "config" in self.options:
attrs += f' config="{self.options["""config"""]}"'
if "setup" in self.options:
attrs += "setup"
if self.content:
code = "\n".join(self.content)
return [nodes.raw("", f"<py-repl{attrs}>\n{code}\n</py-repl>\n", format="html")]
return [
nodes.raw(
"",
f'<script type="py-editor" {attrs}>\n{code}\n</script>\n',
format="html",
)
]


class PyTerminal(SphinxDirective):
"""Add a py-terminal tag"""

option_spec = {
"auto": directives.flag,
"worker": directives.flag,
}

def run(self):
"""Add the py-terminal tag"""
attrs = ""
if "auto" in self.options:
attrs += " auto"
return [nodes.raw("", f"<py-terminal{attrs}></py-terminal>\n", format="html")]
if "worker" in self.options:
attrs += " worker"
return [
nodes.raw(
"", f"<script type='py' terminal {attrs}></script>\n", format="html"
)
]


def add_html_context(
app: Sphinx, pagename: str, templatename: str, context, doctree: nodes.document
):
"""Add extra variables to the HTML template context."""
if doctree and "pyscript" in doctree:
app.add_js_file(app.config.pyscript_js, loading_method="defer")
app.add_js_file(app.config.pyscript_js, type="module")
app.add_js_file("../mini-coi.js")
app.add_css_file(app.config.pyscript_css)


Expand All @@ -142,3 +171,10 @@ def doctree_read(app: Sphinx, doctree: nodes.document):
format="html",
)
)


def copy_asset_files(app, _):
if app.builder.format == "html":
custom_file = (Path(__file__).parent / "mini-coi.js").absolute()
static_dir = (Path(app.builder.outdir)).absolute()
copy_asset_file(str(custom_file), str(static_dir))
31 changes: 31 additions & 0 deletions sphinx_pyscript/mini-coi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*! This script installs a service worker to set the COOP, COEP, and CORP headers required
to use SharedArrayBuffer in the browser. This is required to use py-editor cells.
See https://docs.pyscript.net/2024.5.2/user-guide/workers/ for details */
/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
/*! mini-coi - Andrea Giammarchi and contributors, licensed under MIT */
(({ document: d, navigator: { serviceWorker: s } }) => {
if (d) {
const { currentScript: c } = d;
s.register(c.src, { scope: c.getAttribute('scope') || '.' }).then(r => {
r.addEventListener('updatefound', () => location.reload());
if (r.active && !s.controller) location.reload();
});
}
else {
addEventListener('install', () => skipWaiting());
addEventListener('activate', e => e.waitUntil(clients.claim()));
addEventListener('fetch', e => {
const { request: r } = e;
if (r.cache === 'only-if-cached' && r.mode !== 'same-origin') return;
e.respondWith(fetch(r).then(r => {
const { body, status, statusText } = r;
if (!status || status > 399) return r;
const h = new Headers(r.headers);
h.set('Cross-Origin-Opener-Policy', 'same-origin');
h.set('Cross-Origin-Embedder-Policy', 'require-corp');
h.set('Cross-Origin-Resource-Policy', 'cross-origin');
return new Response(body, { status, statusText, headers: h });
}));
});
}
})(self);
13 changes: 6 additions & 7 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ def test_basic(sphinx_doctree: CreateDoctree):
splashscreen:
autoclose: true

.. py-repl::
:output: replOutput
.. py-editor::

.. py-terminal::

Expand All @@ -33,15 +32,15 @@ def test_basic(sphinx_doctree: CreateDoctree):
<title>
Test
<raw format="html" xml:space="preserve">
<py-repl output="replOutput">
<script type="py-editor" >

</py-repl>
</script>
<raw format="html" xml:space="preserve">
<py-terminal></py-terminal>
<script type='py' terminal ></script>
<raw format="html" xml:space="preserve">
<py-script>
<script type='py'>
print("Hello World")
</py-script>
</script>
<raw format="html" xml:space="preserve">
<py-config type="json">
{
Expand Down