-
Notifications
You must be signed in to change notification settings - Fork 200
/
Copy pathlaunch.py
127 lines (102 loc) · 4.41 KB
/
launch.py
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
from pathlib import Path
from sphinx.util import logging
from shutil import copy2
SPHINX_LOGGER = logging.getLogger(__name__)
def add_hub_urls(app, pagename, templatename, context, doctree):
"""Builds a binder link and inserts it in HTML context for use in templating."""
# First decide if we'll insert any links
path = app.env.doc2path(pagename)
extension = Path(path).suffix
# If so, insert the URLs depending on the configuration
config_theme = app.config["html_theme_options"]
launch_buttons = config_theme.get("launch_buttons", {})
if not launch_buttons or not _is_notebook(app, pagename):
return
# Check if we have a markdown notebook, and if so then add a link to the context
if _is_notebook(app, pagename) and context["sourcename"].endswith(".md"):
# Figure out the folders we want
build_dir = Path(app.outdir).parent
ntbk_dir = build_dir.joinpath("jupyter_execute")
sources_dir = build_dir.joinpath("html", "_sources")
# Paths to old and new notebooks
path_ntbk = ntbk_dir.joinpath(pagename).with_suffix(".ipynb")
path_new_notebook = sources_dir.joinpath(pagename).with_suffix(".ipynb")
# Copy the notebook to `_sources` dir so it can be downloaded
path_new_notebook.parent.mkdir(exist_ok=True)
copy2(path_ntbk, path_new_notebook)
context["ipynb_source"] = pagename + ".ipynb"
repo_url = _get_repo_url(config_theme)
# Parse the repo parts from the URL
org, repo = _split_repo_url(repo_url)
if org is None and repo is None:
# Skip the rest because the repo_url isn't right
return
branch = _get_branch(config_theme)
# Construct the extra URL parts (app and relative path)
notebook_interface_prefixes = {"classic": "tree", "jupyterlab": "lab/tree"}
notebook_interface = launch_buttons.get("notebook_interface", "classic")
if notebook_interface not in notebook_interface_prefixes:
raise ValueError(
(
"Notebook UI for Binder/JupyterHub links must be one"
f"of {tuple(notebook_interface_prefixes.keys())},"
f"not {notebook_interface}"
)
)
ui_pre = notebook_interface_prefixes[notebook_interface]
# Check if we have a non-ipynb file, but an ipynb of same name exists
# If so, we'll use the ipynb extension instead of the text extension
if extension != ".ipynb" and Path(path).with_suffix(".ipynb").exists():
extension = ".ipynb"
# Construct a path to the file relative to the repository root
book_relpath = config_theme.get("path_to_docs", "").strip("/")
if book_relpath != "":
book_relpath += "/"
path_rel_repo = f"{book_relpath}{pagename}{extension}"
# Now build infrastructure-specific links
jupyterhub_url = launch_buttons.get("jupyterhub_url")
binderhub_url = launch_buttons.get("binderhub_url")
colab_url = launch_buttons.get("colab_url")
if binderhub_url:
url = (
f"{binderhub_url}/v2/gh/{org}/{repo}/{branch}?"
f"urlpath={ui_pre}/{path_rel_repo}"
)
context["binder_url"] = url
if jupyterhub_url:
url = (
f"{jupyterhub_url}/hub/user-redirect/git-pull?"
f"repo={repo_url}&urlpath={ui_pre}/{repo}/{path_rel_repo}"
)
context["jupyterhub_url"] = url
if colab_url:
url = f"{colab_url}/github/{org}/{repo}/blob/{branch}/{path_rel_repo}"
context["colab_url"] = url
# Add thebe flag in context
if launch_buttons.get("thebe", False):
context["use_thebe"] = True
def _split_repo_url(url):
"""Split a repository URL into an org / repo combination."""
if "github.com/" in url:
end = url.split("github.com/")[-1]
org, repo = end.split("/")[:2]
else:
SPHINX_LOGGER.warning(
f"Currently Binder/JupyterHub repositories must be on GitHub, got {url}"
)
org = repo = None
return org, repo
def _get_repo_url(config):
repo_url = config.get("repository_url")
if not repo_url:
raise ValueError(
"You must provide the key: `repository_url` to use launch buttons."
)
return repo_url
def _is_notebook(app, pagename):
return app.env.metadata[pagename].get("kernelspec")
def _get_branch(config_theme):
branch = config_theme.get("repository_branch")
if not branch:
branch = "master"
return branch