Skip to content

Commit

Permalink
Add Edit on GitHub
Browse files Browse the repository at this point in the history
  • Loading branch information
michalk8 committed Nov 16, 2021
1 parent 10479a9 commit adc51f2
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 34 deletions.
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
bezier
ipython
ipywidgets
jinja2>=3.0.3
leidenalg
memory_profiler>=0.58.0
# 0.8.7 is really slow
Expand Down
62 changes: 62 additions & 0 deletions docs/source/_ext/edit_on_github.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Based on: gist.github.com/MantasVaitkunas/7c16de233812adcb7028"""

import os
import warnings

__licence__ = "BSD (3 clause)"

from typing import Any, Dict, Tuple, Optional

from sphinx.addnodes import document
from sphinx.application import Sphinx


def get_github_repo(app: Sphinx, path: str) -> Tuple[str, str]:
if path.endswith(".ipynb"):
return app.config.github_nb_repo, "/tutorials/"
if path.endswith(".rst") and "auto_examples" in path and "index.rst" not in path:
# TODO(michalk8): ugly trick to point .rst files in `auto_examples` to `.py`
path = (
path.replace("auto_examples", "examples").replace(".rst", ".py") + "#FIXME/"
)
if not path.startswith("/"):
path = "/" + path
return app.config.github_repo, path
return app.config.github_repo, "/docs/source/"


def html_page_context(
app: Sphinx,
pagename: str,
templatename: str,
context: Dict[str, Any],
doctree: Optional[document],
) -> Optional[str]:
if doctree is None:
return
if templatename != "page.html":
return
if not app.config.github_repo:
warnings.warn("`github_repo `not specified")
return

if not app.config.github_nb_repo:
nb_repo = f"{app.config.github_repo}_notebooks"
app.config.github_nb_repo = nb_repo

path = os.path.relpath(doctree.get("source"), app.builder.srcdir)
repo, conf_py_path = get_github_repo(app, path)

# For sphinx_rtd_theme.
context["display_github"] = True
context["github_user"] = "theislab"
# TODO(michalk): master/dev
context["github_version"] = "master"
context["github_repo"] = repo
context["conf_py_path"] = conf_py_path


def setup(app: Sphinx) -> None:
app.add_config_value("github_nb_repo", "", True)
app.add_config_value("github_repo", "", True)
app.connect("html-page-context", html_page_context)
2 changes: 1 addition & 1 deletion docs/source/_templates/autosummary/base.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
:github_url: {{ fullname }}
:github_url: {{ fullname | modurl }}

{% extends "!autosummary/base.rst" %}

Expand Down
4 changes: 2 additions & 2 deletions docs/source/_templates/autosummary/class.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
:github_url: {{ fullname }}
:github_url: {{ fullname | modurl }}

{{ fullname | escape | underline}}

Expand Down Expand Up @@ -34,6 +34,6 @@

.. _sphx_glr_backref_{{fullname}}:

.. minigallery:: {{fullname}}
.. minigallery:: {{ fullname }}
:add-heading: Examples
:heading-level: -
4 changes: 2 additions & 2 deletions docs/source/_templates/autosummary/function.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
:github_url: {{ fullname }}
:github_url: {{ fullname | modurl }}

{{ fullname | escape | underline}}

.. autofunction:: {{ fullname }}

.. _sphx_glr_backref_{{fullname}}:

.. minigallery:: {{fullname}}
.. minigallery:: {{ fullname }}
:add-heading: Examples
:heading-level: -
4 changes: 0 additions & 4 deletions docs/source/_templates/breadcrumbs.html

This file was deleted.

60 changes: 35 additions & 25 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any, Dict

import os
import sys
import logging
Expand All @@ -6,14 +8,19 @@
from collections import ChainMap
from urllib.parse import urljoin
from urllib.request import urlretrieve
from jinja2.defaults import DEFAULT_FILTERS
from sphinx.application import Sphinx
from sphinx_gallery.sorting import ExplicitOrder, _SortKey

HERE = Path(__file__).parent
sys.path.insert(0, str(HERE))
sys.path.insert(0, str(HERE.parent.parent))
sys.path.insert(0, os.path.abspath("_ext"))

import cellrank

from docs.source.modurl import modurl

logger = logging.getLogger(__name__)

# Configuration file for the Sphinx documentation builder.
Expand Down Expand Up @@ -52,6 +59,7 @@
copyright = f"{datetime.now():%Y}, {author}"
release = "master"
version = f"master ({cellrank.__version__})"
github_repo = "cellrank"


# -- General configuration ---------------------------------------------------
Expand All @@ -70,31 +78,32 @@
"nbsphinx",
"sphinx_copybutton",
"typed_returns",
"edit_on_github",
"sphinxcontrib.bibtex",
# https://github.com/spatialaudio/nbsphinx/issues/24
"IPython.sphinxext.ipython_console_highlighting",
]

intersphinx_mapping = dict(
anndata=("https://anndata.readthedocs.io/en/stable/", None),
scanpy=("https://scanpy.readthedocs.io/en/stable/", None),
squidpy=("https://squidpy.readthedocs.io/en/latest/", None),
scvelo=("https://scvelo.readthedocs.io/", None),
python=("https://docs.python.org/3", None),
numpy=("https://docs.scipy.org/doc/numpy/", None),
scipy=("https://docs.scipy.org/doc/scipy/reference/", None),
networkx=("https://networkx.org/documentation/stable/", None),
pandas=("https://pandas.pydata.org/pandas-docs/stable/", None),
statsmodels=("https://www.statsmodels.org/stable/", None),
matplotlib=("https://matplotlib.org/stable/", None),
joblib=("https://joblib.readthedocs.io/en/latest/", None),
sklearn=("https://scikit-learn.org/stable/", None),
seaborn=("https://seaborn.pydata.org/", None),
pygam=("https://pygam.readthedocs.io/en/latest/", None),
jax=("https://jax.readthedocs.io/en/latest/", None),
pygpcca=("https://pygpcca.readthedocs.io/en/latest/", None),
ot=("https://pythonot.github.io/", None),
)
intersphinx_mapping = {
"anndata": ("https://anndata.readthedocs.io/en/stable/", None),
"scanpy": ("https://scanpy.readthedocs.io/en/stable/", None),
"squidpy": ("https://squidpy.readthedocs.io/en/latest/", None),
"scvelo": ("https://scvelo.readthedocs.io/", None),
"python": ("https://docs.python.org/3", None),
"numpy": ("https://docs.scipy.org/doc/numpy/", None),
"scipy": ("https://docs.scipy.org/doc/scipy/reference/", None),
"networkx": ("https://networkx.org/documentation/stable/", None),
"pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None),
"statsmodels": ("https://www.statsmodels.org/stable/", None),
"matplotlib": ("https://matplotlib.org/stable/", None),
"joblib": ("https://joblib.readthedocs.io/en/latest/", None),
"sklearn": ("https://scikit-learn.org/stable/", None),
"seaborn": ("https://seaborn.pydata.org/", None),
"pygam": ("https://pygam.readthedocs.io/en/latest/", None),
"jax": ("https://jax.readthedocs.io/en/latest/", None),
"pygpcca": ("https://pygpcca.readthedocs.io/en/latest/", None),
"ot": ("https://pythonot.github.io/", None),
}

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates", "_build"]
Expand Down Expand Up @@ -154,15 +163,15 @@
# -- sphinx gallery


def reset_scvelo(gallery_conf, fname):
def reset_scvelo(gallery_conf: Dict[str, Any], fname: str) -> None:
import scvelo as scv

scv.set_figure_params(
style="scvelo", color_map="viridis", format="png", ipython_format="png"
)


def reset_matplotlib(gallery_conf, fname):
def reset_matplotlib(gallery_conf: Dict[str, Any], fname: str) -> None:
import matplotlib as mpl

mpl.use("agg")
Expand Down Expand Up @@ -269,16 +278,17 @@ def __repr__(self) -> str:
napoleon_custom_sections = [("Params", "Parameters")]
todo_include_todos = False


# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_theme = "sphinx_rtd_theme"
html_static_path = ["_static"]
html_theme_options = {"navigation_depth": 4, "logo_only": True}
html_show_sphinx = False
html_show_sourcelink = False
html_show_sourcelink = True

DEFAULT_FILTERS.update(modurl=modurl)


def setup(app):
def setup(app: Sphinx) -> None:
app.add_css_file("css/custom.css")
52 changes: 52 additions & 0 deletions docs/source/modurl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Based on: https://github.com/theislab/scvelo/blob/fb65bab8eb469e2b7f2793d9aca0cb9062d7e58a/docs/source/conf.py"""
from typing import Any, Tuple, Optional

import sys
from inspect import getsourcelines
from pathlib import Path, PurePosixPath


def get_obj_module(qualname: str) -> Tuple[Any, Any]:
"""Get a module/class/attribute and its original module by qualname"""
modname = qualname
classname, attrname = None, None
while modname not in sys.modules:
attrname = classname
modname, classname = modname.rsplit(".", 1)

# retrieve object and find original module name
if classname:
cls = getattr(sys.modules[modname], classname)
modname = cls.__module__
obj = getattr(cls, attrname) if attrname else cls
else:
obj = None

return obj, sys.modules[modname]


def get_linenos(obj: Any) -> Tuple[Optional[int], Optional[int]]:
"""Get an object’s line numbers"""
try:
lines, start = getsourcelines(obj)
except TypeError:
return None, None
else:
return start, start + len(lines) - 1


def modurl(qualname: str) -> str:
"""Get the full GitHub URL for some object’s qualname."""
project_dir = Path(__file__).parent.parent.parent
obj, module = get_obj_module(qualname)
github_url = "https://github.com/theislab/cellrank/tree/master"

try:
path = PurePosixPath(Path(module.__file__).resolve().relative_to(project_dir))
except ValueError:
return github_url

start, end = get_linenos(obj)
fragment = f"#L{start}-L{end}" if start and end else ""

return f"{github_url}/{path}{fragment}"

0 comments on commit adc51f2

Please sign in to comment.