From 07fb7d4f1437080b80250b1a936de8db5b9fe066 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Sun, 18 Jun 2023 02:04:57 +0200 Subject: [PATCH 1/4] Allow to build with sphinx 7 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d9d3b3d..dcf3f0f 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Python Modules", ], - install_requires=["sphinx>=4,<7"], + install_requires=["sphinx>=4"], extras_require={ "sphinx": [ "matplotlib", From 6b18799a457e2734e7ca2ecd52c73f3e695aa6c2 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Sun, 18 Jun 2023 02:15:17 +0200 Subject: [PATCH 2/4] Update requirements format and remove matplotlib --- setup.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index dcf3f0f..eaa5288 100644 --- a/setup.py +++ b/setup.py @@ -50,12 +50,17 @@ install_requires=["sphinx>=4"], extras_require={ "sphinx": [ - "matplotlib", "myst-nb", "sphinx-book-theme>=0.4.0rc1", "sphinx-copybutton", "sphinx-design", ], - "testing": ["matplotlib", "pytest", "pytest-regressions", "beautifulsoup4"], + "testing": [ + "sphinx-thebe[sphinx]", + "matplotlib", + "pytest", + "pytest-regressions", + "beautifulsoup4", + ], }, ) From 62ba86fd0182712865eb77e1f378b094fee07344 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Sun, 18 Jun 2023 02:16:17 +0200 Subject: [PATCH 3/4] Expand the github action testing --- .github/workflows/tests.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5c0374c..c0c4b1d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,7 +2,7 @@ name: continuous-integration on: push: - branches: [master] + branches: [main] tags: - 'v*' pull_request: @@ -12,19 +12,21 @@ jobs: docs: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - python-version: [3.7, 3.8, 3.9] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + sphinx: [ "~=4.0", "~=5.0", "~=6.0", "~=7.0" ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies + - name: Install sphinx-thebe with sphinx ${{ matrix.sphinx }} run: | - python -m pip install --upgrade pip - pip install -e .[sphinx,testing] + pip install --upgrade pip + pip install --upgrade "Sphinx${{ matrix.sphinx }}" -e .[testing] - name: Run tests run: | pytest From c6230f78d928af6dfd6ee82244768ecc74b6d37b Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Fri, 30 Jun 2023 14:07:29 +0200 Subject: [PATCH 4/4] Try to minimize dependencies --- setup.py | 4 +- tests/test_build.py | 9 +- tests/test_build/src/conf.py | 25 +++ tests/test_build/src/configure.md | 192 +++++++++++++++++++++ tests/test_build/src/examples/notebooks.md | 59 +++++++ tests/test_build/src/index.md | 53 ++++++ 6 files changed, 334 insertions(+), 8 deletions(-) create mode 100644 tests/test_build/src/conf.py create mode 100644 tests/test_build/src/configure.md create mode 100644 tests/test_build/src/examples/notebooks.md create mode 100644 tests/test_build/src/index.md diff --git a/setup.py b/setup.py index eaa5288..cc82f64 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,9 @@ "sphinx-design", ], "testing": [ - "sphinx-thebe[sphinx]", + # TODO: Minimize the testing dependencies + "myst-parser", + "myst-nb", "matplotlib", "pytest", "pytest-regressions", diff --git a/tests/test_build.py b/tests/test_build.py index 471f707..6959a53 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -6,7 +6,7 @@ path_tests = Path(__file__).parent.resolve() -path_docs = path_tests.joinpath("..", "docs") +path_docs = path_tests.joinpath("test_build", "src") @pytest.fixture(scope="session") @@ -21,15 +21,10 @@ class SphinxBuild: path_pg_ntbk = path_html.joinpath("examples/notebooks.html") cmd_base = ["sphinx-build", ".", "_build/html", "-a", "-W"] - def copy(self, path=None): + def copy(self, path: Path = path_docs): """Copy the specified book to our tests folder for building.""" - if path is None: - path = path_docs - path_changelog = path / "../CHANGELOG.md" if not self.path_tmp_docs.exists(): copytree(path, self.path_tmp_docs) - # Copy since it's loaded with an `include` directive - copy(path_changelog, self.path_tmp) def build(self, cmd=None): """Build the test book""" diff --git a/tests/test_build/src/conf.py b/tests/test_build/src/conf.py new file mode 100644 index 0000000..0d4aa10 --- /dev/null +++ b/tests/test_build/src/conf.py @@ -0,0 +1,25 @@ +project = "Sphinx Thebe" +copyright = "2020, Executable Book Project" +author = "Executable Book Project" +version = "" +release = "" + +extensions = [ + "myst_parser", + "sphinx_thebe", + "myst_nb", +] + +thebe_config = { + "repository_url": "https://github.com/binder-examples/jupyter-stacks-datascience", + "path_to_docs": "docs", +} + +myst_enable_extensions = ["colon_fence"] +source_suffix = [".rst", ".md"] + +exclude_patterns = [ + "_build", + "Thumbs.db", + ".DS_Store", +] diff --git a/tests/test_build/src/configure.md b/tests/test_build/src/configure.md new file mode 100644 index 0000000..a26788c --- /dev/null +++ b/tests/test_build/src/configure.md @@ -0,0 +1,192 @@ +--- +thebe-kernel: ir +--- + +# Configuration + +(configure:selector)= +## Change the HTML selector to mark interactive cells + +By default, `sphinx-thebe` will be run on any cells with the `thebe` class. +However, you can customize the HTML selector to use other classes, elements, etc. + +For example, if you wanted to convert **all code cells**, you could use the following +selector: + +```python +thebe_config = { + "selector": "div.highlight" +} +``` + +```{note} +`sphinx-thebe` will subsequently look for any `pre` blocks inside of elements it +finds with the `selector` configuration value. These are the blocks that will be +converted to interactive with `thebe`. +``` + +## Including outputs with your code + +If you'd like to include outputs in the *static* version of your page, and only +overwrite them once the user has run that Thebe cell, you can configure `sphinx-thebe` +to detect and keep the outputs associated with some code. To do so, use +the `selector_output` configuration. This is a selector that is searched for *within* any +items discovered by `selector`. If an output is found, it will be placed just after the +code and Thebe will detect it. + +For example, the following code: + +Defines a *parent container* in which we'll put both code and the output of the +code. We'll use a `code-block` for the code, and another `container` node with our +`output` class for the output. `sphinx-gallery` will detect the parent container because +it has a `thebe` class. It will detect the `pre` block inside the container as the +code, and it will detect the `
` block with the `output` class as the output. + +The result is that initializing Thebe *retains* the output until the cell is +executed, like so: + +```{thebe-button} +``` + +````{container} thebe +```{code-block} r +print("hi") +``` + +```{container} output +"hi" +``` +```` + +## Setting the Kernel + +You can set the kernel that Thebe uses on a page by adding metadata to your +page. To do so, add the following metadata to the top of your page: + +``` +thebe-kernel: +``` + +For example, this page had the following metadata in it: + +``` +thebe-kernel: ir +``` + +In addition, this website is configured to use the [Binder R example repository](https://github.com/binder-examples/r) +for its environment. As a result, we can now run R code interactively with Thebe: + + +```{thebe-button} Launch thebe in R +``` + +```{code-block} +:class: thebe, thebe-init +# Load ggplot - this will be automatically-run +library(ggplot2) +``` + +```{code-block} +:class: thebe, thebe-init +# create factors with value labels +mtcars$gear <- factor(mtcars$gear,levels=c(3,4,5), + labels=c("3gears","4gears","5gears")) +mtcars$am <- factor(mtcars$am,levels=c(0,1), + labels=c("Automatic","Manual")) +mtcars$cyl <- factor(mtcars$cyl,levels=c(4,6,8), + labels=c("4cyl","6cyl","8cyl")) +``` + +```{code-block} +:class: thebe, thebe-init +# Kernel density plots for mpg +# grouped by number of gears (indicated by color) +qplot(mpg, data=mtcars, geom="density", fill=gear, alpha=I(.5), + main="Distribution of Gas Milage", xlab="Miles Per Gallon", + ylab="Density") +``` + +```{code-block} +:class: thebe + +# Scatterplot of mpg vs. hp for each combination of gears and cylinders +# in each facet, transmittion type is represented by shape and color +qplot(hp, mpg, data=mtcars, shape=am, color=am, + facets=gear~cyl, size=I(3), + xlab="Horsepower", ylab="Miles per Gallon") +``` + +## Automatically running some code + +You can tag code blocks to run as soon as the kernel is ready (i.e., without any user input) +by adding the `thebe-init` class to the code blocks. For example: + +These code blocks will be run automatically once the kernel is ready, and their outputs +will be displayed below. + + +(add-custom-button)= +## Adding your own button to start Thebe + +By default, Thebe encourages users to use the `thebe-button` directive to +insert a thebe button into their documentation. However, you can add your own +buttons wherever you wish. Simply ensure that an HTML element has this attribute: + +```js +onclick="initThebe()" +``` + +and it will be able to initialize Thebe on that page on its own. + +For example, here is the HTML for the Thebe button generated by the `thebe-button` +directive: + +```html + +``` + +## Choose a codemirror theme + +You can customize `sphinx-thebe` to use the codemirror theme of your choice. +To do so, use the following configuration: + +```python +thebe_config = { + "codemirror-theme": "" +} +``` + +See [the CodeMirror theme demo](https://codemirror.net/demo/theme.html) for a list +of themes that you can use, and what they look like. + +## Load `thebe` automatically on all pages + +By default, `sphinx-thebe` will lazily load the JS/CSS from `thebe` when the `sphinx-thebe` initialization button is pressed. +This means that no Javascript is loaded until a person explicitly tries to start thebe, which reduces page load times. + +If you want `thebe` to be loaded on every page, in an "eager" fashion, you may do so with the following configuration: + +```python +thebe_config = { + "always_load": True +} +``` + +## Configuration reference + +Here's a reference of all of the configuration values avialable to `sphinx-thebe`. +Many of these eventually make their was into the `thebe` configuration. You can +find a [reference for `thebe` configuration here](https://thebe.readthedocs.io/en/latest/config_reference.html). + +```python +thebe_config = { + "always_load": bool (default True) + "repository_url": "", + "repository_branch": "", + "selector": "", + "selector_input": "", + "selector_output": "", +} +``` diff --git a/tests/test_build/src/examples/notebooks.md b/tests/test_build/src/examples/notebooks.md new file mode 100644 index 0000000..9d50ff1 --- /dev/null +++ b/tests/test_build/src/examples/notebooks.md @@ -0,0 +1,59 @@ +--- +jupytext: + formats: md:myst + text_representation: + extension: .md + format_name: myst +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + +# Jupyter Notebooks + +This page was written for [MyST-NB](https://myst-nb.readthedocs.io/). +It demonstrates `sphinx-thebe`'s usage with Jupyter Notebooks. + +Activate Thebe by clicking the launch button below. +You should then be able to run and edit the code cell in the notebook. + +```{thebe-button} Launch thebe +``` + +The outputs should be displayed below, but they will be collected by `sphinx-thebe` when it is activated so that they are cleared when you first run the cell. + +```{code-cell} +import numpy as np +import matplotlib.pyplot as plt + +# Create some fake data +data = np.random.randn(3, 1000) + +# Create a figure +fig, ax = plt.subplots() + +# Plot data +ax.scatter(data[0], data[1], c=np.abs(data[2]), s=np.abs(data[2])*100) +``` + +## Code style + +Thebe uses CodeMirror in the background, which uses different styles than pygments, which is used for static code syntax highlighting. + +The below code block is **static** and will not be converted with `thebe`. +We include it in order to compare the active Thebe cell's syntax highlighting with an inactive cell. + +``` +import numpy as np +import matplotlib.pyplot as plt + +# Create some fake data +data = np.random.randn(3, 1000) + +# Create a figure +fig, ax = plt.subplots() + +# Plot data +ax.scatter(data[0], data[1], c=np.abs(data[2]), s=np.abs(data[2])*100) +``` diff --git a/tests/test_build/src/index.md b/tests/test_build/src/index.md new file mode 100644 index 0000000..996c252 --- /dev/null +++ b/tests/test_build/src/index.md @@ -0,0 +1,53 @@ +# sphinx-thebe + + +```{image} https://readthedocs.org/projects/sphinx-thebe/badge/?version=latest +:target: https://sphinx-thebe.readthedocs.io/en/latest/?badge=latest +:alt: Documentation +``` + +```{image} https://img.shields.io/pypi/v/sphinx-thebe.svg +:target: https://pypi.org/project/sphinx_thebe +:alt: PyPi page +``` + +Make your code cells interactive with a kernel provided by [Thebe](http://thebe.readthedocs.org/) and [Binder](https://mybinder.org). + +It uses the excellent [thebe project](http://thebe.readthedocs.org/), and pre-configures `thebe` to be compatible with common Jupyter-related patterns in the Sphinx ecosystem, such as [MyST-NB](https://myst-nb.readthedocs.io/). + +For example, click the button below. Notice that the code block beneath becomes +editable and runnable! + +```{thebe-button} Launch thebe +``` + +```{code-block} python +:class: thebe + +print("hi") +``` + +## Install + +To install `sphinx-thebe` first clone and install it: + +``` +pip install sphinx-thebe +``` + +Then, add it to your Sphinx site's `conf.py` file: + +``` +extensions = [ + ... + "sphinx_thebe" + ... +] +``` + +```{toctree} +:hidden: +configure +contribute +changelog +```