Skip to content

Commit

Permalink
Create jupyterbook (NeuromatchAcademy#583)
Browse files Browse the repository at this point in the history
Added support for jupyterbook binding of all the tutorials w/ automatic publish to the gh-pages branch on every merge into master
  • Loading branch information
ebatty authored Jun 19, 2021
1 parent 0a70151 commit 46fb9be
Show file tree
Hide file tree
Showing 208 changed files with 14,539 additions and 23,893 deletions.
48 changes: 48 additions & 0 deletions .github/workflows/publish-book.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: publish-book

on:
push:
branches: master

# This job installs dependencies, build the book, and pushes it to `gh-pages`
jobs:
build-and-deploy-book:
runs-on: ubuntu-latest
steps:

- name: Checkout
uses: actions/checkout@v2
with:
persist-credentials: false
fetch-depth: 0
ref: ${{ github.head_ref }}

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.7

- name: Install dependencies
run: |
pip install -r requirements.txt
pip install jupyter-book==0.10.2 ghp-import
- name: Build the book
run: |
python ci/generate_book.py
ln -s ../tutorials book/tutorials
jupyter-book build book
- name: Commit book
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
ghp-import -n -m "Update course book" book/_build/html
git checkout gh-pages
- name: Publish to gh-pages
uses: ad-m/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages
force: true
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
.ipynb_checkpoints
.vscode
.idea
_build
_toc.yml
36 changes: 36 additions & 0 deletions book/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Jupyterbook Support

We use [jupyterbook](https://jupyterbook.org/intro.html) to create a condensed,
single interface to all our course materials. This book will be autogenerated
and published to [https://neuromatchacademy.github.io/course-content] every time
a PR is merged into the master branch.

The Github workflow is defined in .github/workflows/publish-book.yml.

In order to build the book locally, you will need to do the following:

1. Install dependencies

`pip install jupyter-book==0.10.2`

Do not install jupyter-book 0.11 or later at this point, as there are breaking
changes in how it handles the table of contents file we generate.

2. Create a symlink in the book dir to the tutorials dir. From the repo root
directory:

`ln -s ../tutorials book/tutorials`

3. Prepare repo for book building

`python ci/generate_book.py`

This will use the tutorials/materials.yml to create the _toc.yml file in the
book directory. It will also be responsible for creating any additional markdown
files or modifying any tutorial notebooks specifically for book generation.

**No changes created by this script should be committed to the repo.**

4. Build the book

`jupyer-book build book`
45 changes: 45 additions & 0 deletions book/_config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#######################################################################################
# A default configuration that will be loaded for all jupyter books
# See the documentation for help and more options:
# https://jupyterbook.org/customize/config.html

#######################################################################################
# Book settings
title : Neuromatch Computational Neuroscience # The title of the book. Will be placed in the left navbar.
author : Neuromatch # The author of the book
copyright : "2021" # Copyright year to be placed in the footer
logo : nma-logo-square-4xp.jpg # A path to the book logo
only_build_toc_files : true


#######################################################################################
# Execution settings
execute:
execute_notebooks : off # Whether to execute notebooks at build time. Must be one of ("auto", "force", "cache", "off")
cache : "" # A path to the jupyter cache that will be used to store execution artifacts. Defaults to `_build/.jupyter_cache/`
exclude_patterns : [] # A list of patterns to *skip* in execution (e.g. a notebook that takes a really long time)
timeout : 30 # The maximum time (in seconds) each notebook cell is allowed to run.
run_in_temp : false # If `True`, then a temporary directory will be created and used as the command working directory (cwd),
# otherwise the notebook's parent directory will be the cwd.
allow_errors : false # If `False`, when a code cell raises an error the execution is stopped, otherwise all cells are always run.
stderr_output : show # One of 'show', 'remove', 'remove-warn', 'warn', 'error', 'severe'

# Parse and render settings
parse:
myst_enable_extensions: # default extensions to enable in the myst parser. See https://myst-parser.readthedocs.io/en/latest/using/syntax-optional.html
- amsmath
- dollarmath

#######################################################################################
# Launch button settings
launch_buttons:
notebook_interface : classic # The interface interactive links will activate ["classic", "jupyterlab"]
binderhub_url : "" # The URL of the BinderHub (e.g., https://mybinder.org)
jupyterhub_url : "" # The URL of the JupyterHub (e.g., https://datahub.berkeley.edu)
thebe : false # Add a thebe button to pages (requires the repository to run on Binder)
colab_url : https://colab.research.google.com # The URL of Google Colab (https://colab.research.google.com)

repository:
url : https://github.com/NeuromatchAcademy/course_content # The URL to your book's repository
path_to_book : book # A path to your book's folder, relative to the repository root.
branch : master # Which branch of the repository should be used when creating links
3 changes: 3 additions & 0 deletions book/intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Introduction

Welcome to the Neuromatch computational neuroscience course!
Binary file added book/nma-logo-square-4xp.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions ci/generate_book.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import os

import yaml
from jinja2 import Template


def main():
with open('tutorials/materials.yml') as fh:
materials = yaml.load(fh, Loader=yaml.FullLoader)

toc = {'Pre-reqs Refresher': {'part': 'Pre-reqs Refresher', 'chapters': []},
'Intro to Modeling': {'part': 'Intro to Modeling', 'chapters': []},
'Machine Learning': {'part': 'Machine Learning', 'chapters': []},
'Dynamical Systems': {'part': 'Dynamical Systems', 'chapters': []},
'Stochastic Processes': {'part': 'Stochastic Processes', 'chapters': []}}

for m in materials:
directory = f"{m['day']}_{''.join(m['name'].split())}"
chapter = {'file': f"tutorials/{directory}/intro_text.md",
'title': f"{m['name']} ({m['day']})",
'sections': []}
print(m['day'])
part = m['category']

# Generate intro video page
chapter = generate_page(m, directory, chapter, "Intro")

# Add tutorials
for i in range(m['tutorials']):
directory = f"tutorials/{m['day']}_{''.join(m['name'].split())}"
notebook = f"{m['day']}_Tutorial{i + 1}.ipynb"
chapter['sections'].append({'file': f"{directory}/student/{notebook}"})

# Generate outro video page
chapter = generate_page(m, f"{m['day']}_{''.join(m['name'].split())}", chapter, "Outro")

toc[part]['chapters'].append(chapter)

# Turn toc into list
toc_list = [{'file': 'intro.md'}]
for key in toc.keys():
toc_list.append(toc[key])

with open('book/_toc.yml', 'w') as fh:
yaml.dump(toc_list, fh)


def convert_youtube_url_to_embed_url(url):
# TODO: Support Chinese equivalent URLs
url_key = url.split("=")[1]
return "https://www.youtube.com/embed/" + url_key


def generate_page(info, directory, chapter, file_type):
if file_type.lower() in info:
chapter['sections'].append({'file': f'tutorials/{directory}/{file_type.lower()}_vid.md'})
with open(os.path.join("ci", "resources", "intro_outro_template.txt"), encoding="utf-8") as f:
template_string = f.read()
template = Template(template_string)
for slides in info['slides']:
if slides['title'] == file_type:
prepared_template_string = template.render(type=file_type,
video_source_url=convert_youtube_url_to_embed_url(
info[file_type.lower()]),
slide_source_url=slides['link'])
with open(os.path.join("tutorials", directory, file_type.lower() + "_vid.md"),
"w+") as intro_vid_file:
intro_vid_file.write(prepared_template_string)
return chapter


if __name__ == '__main__':
main()
7 changes: 7 additions & 0 deletions ci/resources/intro_outro_template.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# {{type}} Video
## Video

<iframe width="420" height="315" src="{{video_source_url}}"></iframe>

## Slides
<iframe src="{{slide_source_url}}", frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
Loading

0 comments on commit 46fb9be

Please sign in to comment.