Python Code Playground in MkDocs
Inspired by live coding playgrounds, where users can code on the website instead of downloading the programming language or software, how cool would it be to have it in MkDocs Documentation and have your Python package available in a "plug-and-play" mode?
Documentation should minimally have a user and technical guide, together with a glossary and release notes. But documentation can truly come to life if readers can interact with the code directly on the documentation!
After scouring through the Internet, I realized coding playgrounds are easier to set up with JavaScript, while my Mkdocs documentation and the entire codebase were in Python. After much searching, I found this forum with what I wanted, but the playground was heavily hardcoded to work with another Python package. I decided to adapt that to a generic solution and will elaborate step-by-step on what is needed and what can be tweaked to work for you.
Note: These are the links to the playground and my codebase. More useful links can be found in the "Related Links" section at the end of this article.
Overview of Solution
Besides the required setup files for the Playground to work, there is a need to modify the MkDocs config and Markdown files and integrate them with Read the Docs and GitHub pages if your documentation is hosted on those platforms.
Playground Setup
There are 4 files required for the playground. Their purpose will be elaborated in the future sections, namely they are:
docs/_static/playground.css
: CSS for the playgrounddocs/_static/playground.js
: JS for the playgrounddocs/_static/playground.py
: For Mkdocs configurationdocs/_static/playground_whl.py
: For fetching Python package WHL files, this generates another JS file in runtime
MkDocs configuration changes
In mkdocs.yml
file, the playground will leverage pymdownx.superfences
Markdown extensions.
# mkdocs.yml
markdown_extensions:
- pymdownx.superfences:
custom_fences:
- name: py
class: 'highlight'
format: !!python/object/apply:docs._static.playground.color_command_formatter
kwds:
init: |
from bigtree import *
validator: !!python/name:docs._static.playground.color_command_validator
Some important things to note here,
- The name
py
indicates how the Markdown will be used or defined - I initialized
from bigtree import *
here to enable the playground to access all the functions in my Python package by default, if not this can be left blank - This references the functions
color_command_formatter
andcolor_command_validator
in thedocs/_static/playground.py
file
Another change needed in the MkDocs configuration is to reference the CSS and JS files for the playground.
extra_css:
- _static/playground.css
extra_javascript:
- _static/playground-config.js # generated in runtime by playground_whl.py
- _static/playground.js
- https://cdn.jsdelivr.net/pyodide/v0.25.1/full/pyodide.js # open source
MkDocs Markdown file changes
Of course, what good would it be to have all the setup instructions without explaining how to use them in your actual documentation? Playground can be added to the Markdown files easily with the py
extension – as simple as that!
## Playground
```py play
# Your code here
### Integrate with Read the Docs / GitHub Pages
If your documentation is integrated with Read the Docs or GitHub Pages, I added a line of code to run the `docs/_static/playground_whl.py` file that fetches the Python package WHL files and generates the `playground-config.js` file in runtime required by MkDocs.
```yaml
# .readthedocs.yaml
jobs:
pre_build:
- python docs/_static/playground_whl.py
At this point you are 80% there, what is left is just copy-pasting the remaining files over!
The remaining files work just fine on their own since they are not hardcoded (mostly). They can be tweaked to your needs if you want to change the default texts, for example. Before that, the purpose of each file will be elaborated on.
playground.css
file
Purpose: Controls the look and feel of the playground
In all honesty, I just copied and pasted the CSS file from the source since the playground layout looks good to me and I did not want to risk breaking anything.
playground.js
file
Purpose: Controls the layout of the playground, and extracts the code for processing
This was heavily edited from the source to remove the parts that were hardcoded to fit another Python package – currently, this is generic enough to be reused.
I am no JavaScript expert, but preliminary inspection of the code tells me that this script extracts the code in the playground to be processed by a Python interpreter. This file also controls the layout of the playground after it is run – if you are interested in changing any layout or text of the playground.
playground.py
file
Purpose: Interprets and executes the code, and displays the results in the playground
This file was also heavily edited from the source to remove the hardcoded parts and is now fit for reuse.
While the colour formatter and validator functions are used in the Markdown extensions of MkDocs, this script contains a lot more functions. The other functions interpret and execute the code line-by-line while ignoring all the non-code lines such as line breaks and comments. This is also why line breaks and comments in the playground are not shown on the results page after execution – something that I found buggy.
This file also controls the initial layout of the playground before it is run – if you want to change any layout, you need to modify this file and the js file.
playground_whl.py
file
Purpose: Compiles relevant WHL information and generates a JS script at runtime with this information.
This file is not fit for reuse and should be modified to fit your purpose.
The Python interpreter for the playground requires Python packages as "background information" when interpreting and executing the code. This is done by having it reference WHL files – similar to how you pip install
Python packages.
The original implementation downloads open-source WHL files to their local folder, and also builds the Python package into a WHL file in their local folder. The Python interpreter then references the WHL files that are in the local folder. This method is not preferred and did not work for me because:
- This requires installing additional Python packages to run command-line operations
- This requires installing WHL files into local folders
- Installing WHL files works for GitHub pages but not Read the Docs
Adapted from the original implementation, I decided to reference WHL files via their online URL. This meant that:
- Open-source WHL files remain as their online reference URLs
- Python package must be uploaded to PyPI, PyPI API is then queried using
requests
library to retrieve the latest URL of the WHL file
The part that is ‘hardcoded' was referencing my own bigtree
Python package to query PyPI API – modify this part to install any Python package of your choice to work with your playground!
Happy playing with your playground!
Related Links
- My Python playground on MkDocs: https://bigtree.readthedocs.io/en/stable/playground/
- My codebase: https://github.com/kayjan/bigtree
- My related merge request: https://github.com/kayjan/bigtree/pull/259
- Adapted from Coloraide: https://github.com/facelessuser/coloraide