1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
# Pyodide
This special `pyodide` fence uses [Pyodide](https://pyodide.org), [Ace](https://ace.c9.io/)
and [Highlight.js](https://highlightjs.org/) to render an interactive Python editor.
Everything runs on the client side. The first time Pyodide is loaded by the browser
can be a bit long, but then it will be cached and the next time you load the page
it will be much faster.
Click the **:material-play: Run** button in the top-right corner, or hit ++ctrl+enter++ to run the code.
You can install packages with Micropip:
````md exec="1" source="tabbed-right" tabs="Markdown|Rendered"
```pyodide
import micropip
print("Installing cowsay...")
await micropip.install("cowsay")
print("done!")
```
````
Then you can import and use the packages you installed:
````md exec="1" source="tabbed-right" tabs="Markdown|Rendered"
```pyodide
import cowsay
cowsay.cow("Hello World")
```
````
Packages installed with Micropip are cached by the browser as well,
making future installations much faster.
## Pyodide version
You can select a specific Pyodide version with the `version` option:
````md
```pyodide version="0.26.4"
print("Hello.")
```
````
NOTE: **All Pyodide blocks on the same page should use the same version!**
## Editor height
The height of the editor can be configured with the `height` option. It accepts the following values:
- `0` or `auto`: A fixed number of lines, based on initial code.
- a positive number, like `10`: A fixed number of lines.
- a positive range, like `5-30`: The minimum and maximum number of lines. The editor will shring/grow as you type.
The default is `auto`.
A few examples:
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered" title="Fixed height (10 lines)"
```pyodide height="10"
from typing import Iterator
# This is an example
class Math:
@staticmethod
def fib(n: int) -> Iterator[int]:
"""Fibonacci series up to n."""
a, b = 0, 1
while a < n:
yield a
a, b = b, a + b
result = sum(Math.fib(42))
print(f"The answer is {result}")
```
````
````md exec="1" source="tabbed-left" tabs="Markdown|Rendered" title="Between 1 and 40 lines"
```pyodide height="1-40"
from typing import Iterator
# This is an example
class Math:
@staticmethod
def fib(n: int) -> Iterator[int]:
"""Fibonacci series up to n."""
a, b = 0, 1
while a < n:
yield a
a, b = b, a + b
result = sum(Math.fib(42))
print(f"The answer is {result}")
```
````
## Sessions
Editors with the same session share the same `globals()` dictionary,
so you can reuse variables, classes, imports, etc., from another editor
within the same session. This is why you can import `cowsay` in this editor,
given you actually installed it in the first. Sessions are ephemeral:
everything is reset when reloading the page. This means you cannot persist
sessions across multiple pages. Try refreshing your page
and running the code of the second editor: you should get a ModuleNotFoundError.
To use other sessions, simply pass the `session="name"` option to the code block:
````md exec="1" source="tabbed-right" tabs="Markdown|Rendered"
```pyodide session="something"
something = "hello"
```
````
Now lets print it in another editor with the same session:
````md exec="1" source="tabbed-right" tabs="Markdown|Rendered"
```pyodide session="something"
print(something)
```
````
And in another editor with the default session:
````md exec="1" source="tabbed-right" tabs="Markdown|Rendered"
```pyodide
print(something)
```
````
## Pre-installing packages
In your own documentation pages, you might not want to add
`import micropip; await micropip.install("your-package")`
to every editor to show how to use your package. In this case,
you can use the `install` option to pre-install packages.
The option takes a list of comma-separated package distribution names:
````md exec="1" source="tabbed-right" tabs="Markdown|Rendered"
```pyodide install="griffe,dependenpy"
import griffe
import dependenpy
print("OK!")
```
````
## Excluding assets
When you add a Pyodide fence to a page,
Markdown Exec will inject `<script>` and `<link>` tags
to load Javascript and CSS assets.
If you add multiple Pyodide fences to the same page,
the same assets will be included many times.
The browser is clever enough not to re-download them everytime
(they are cached), but we can still avoid re-injecting assets
to make the HTML page smaller and faster.
````md
```pyodide assets="no"
print("hello")
```
````
**Make sure that at least one Pyodide fence per page injects the assets.**
## Editor themes
The editor provided by [Ace](https://ace.c9.io/) supports different color themes.
The complete list can be found here: https://github.com/ajaxorg/ace/tree/master/src/theme.
To use a specific theme for both light and dark schemes, use the `theme` option on the Pyodide code block:
````md
```pyodide theme="ambiance"
print("hello")
```
````
To specify different themes for the light and dark schemes, separate them with a comma:
````md
```pyodide theme="ambiance,chaos"
print("hello")
```
````
See all previews below.
```python exec="1"
import subprocess
from textwrap import dedent
theme_files = subprocess.check_output(["gh", "api", "/repos/ajaxorg/ace/contents/src/theme", "--jq", ".[].name"], text=True)
themes = [theme_file[:-3] for theme_file in theme_files.splitlines() if not theme_file.endswith("-css.js")]
for theme in themes:
print(f"### `{theme}`")
print(
dedent(
f'''
```pyodide theme="{theme}" assets="no"
from typing import Iterator
# This is an example
class Math:
@staticmethod
def fib(n: int) -> Iterator[int]:
"""Fibonacci series up to n."""
a, b = 0, 1
while a < n:
yield a
a, b = b, a + b
result = sum(Math.fib(42))
print(f"The answer is {{result}}")
```
'''
)
)
```
|