Skip to content

Commit

Permalink
Add docs build script.
Browse files Browse the repository at this point in the history
  • Loading branch information
cqc-alec committed Jul 23, 2024
1 parent 62118da commit 4b7002a
Show file tree
Hide file tree
Showing 7 changed files with 269 additions and 0 deletions.
Binary file added .github/workflows/docs/Quantinuum_logo_black.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/workflows/docs/Quantinuum_logo_white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
113 changes: 113 additions & 0 deletions .github/workflows/docs/build-docs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env python

import argparse
import datetime
from importlib import import_module
from pathlib import Path
import shutil
import subprocess
import sys

DOCS_DIR = Path(sys.argv[0]).absolute().parent
MODULES_DIR = DOCS_DIR.parent.parent.parent
TKET_EXAMPLES_LINK = "https://tket.quantinuum.com/examples/"
TKET_MANUAL_LINK = "https://tket.quantinuum.com/user-manual/"
TKET_WEBSITE_LINK = "https://tket.quantinuum.com/"
PYTKET_DOCS_LINK = "https://tket.quantinuum.com/api-docs/"
PYTKET_EX_DOCS_LINK = "https://tket.quantinuum.com/api-docs/extensions.html"
MODULE = "azure"
PYPI_LINK = f"https://pypi.org/project/pytket-{MODULE}/"
GITHUB_LINK = f"https://github.com/CQCL/pytket-{MODULE}"


def get_module_version():
m = import_module(f"pytket.extensions.{MODULE}")
return m._metadata.__extension_version__.split(".")


def remove_dir(dirpath):
if dirpath.exists() and dirpath.is_dir():
shutil.rmtree(dirpath)


def fix_links(filepath):
with open(filepath, "r", encoding="utf8") as f:
content = f.read()
content = content.replace("pytket._tket", "pytket")
with open(filepath, "w", encoding="utf8") as f:
f.write(content)


def build_module_docs():
v = get_module_version()
mod_docs = MODULES_DIR / "docs"
mod_build = mod_docs / "build"
conf_copy = mod_docs / "conf.py"
logo_copy_black = mod_docs / "Quantinuum_logo_black.png"
logo_copy_white = mod_docs / "Quantinuum_logo_white.png"
shutil.copy(DOCS_DIR / "conf.py", conf_copy)
shutil.copy(DOCS_DIR / "Quantinuum_logo_black.png", logo_copy_black)
shutil.copy(DOCS_DIR / "Quantinuum_logo_white.png", logo_copy_white)
remove_dir(mod_build)
index_rst = mod_docs / "index.rst"
with open(mod_docs / "intro.txt", "r") as f:
content = f.readlines()
content.append(
"\n.. toctree::\n\t:caption: pytket documentation:\n\t:maxdepth: 1\n\n"
)
content.append(f"\tpytket API docs <{PYTKET_DOCS_LINK}>\n")
content.append(f"\tpytket extensions <{PYTKET_EX_DOCS_LINK}>\n")
content.append(f"\tManual <{TKET_MANUAL_LINK}>\n")
content.append(f"\tExample notebooks <{TKET_EXAMPLES_LINK}>\n")
content.append(f"\tTKET website <{TKET_WEBSITE_LINK}>\n")
content.append("\n.. toctree::\n\t:caption: Links:\n\t:maxdepth: 1\n\n")
content.append(f"\tbug tracker <{GITHUB_LINK}/issues>\n")
content.append(f"\tGitHub <{GITHUB_LINK}>\n")
content.append(f"\tPyPi <{PYPI_LINK}>\n")

with open(index_rst, "w") as f:
f.writelines(content)
subprocess.run(
[
"sphinx-build",
"-b",
"html",
"-D",
f"project=pytket-{MODULE}",
"-D",
f"copyright={datetime.date.today().year} Quantinuum",
"-D",
f"version={'.'.join(v[:2])}",
"-D",
f"release={'.'.join(v)}",
".",
"build",
],
cwd=mod_docs,
)
for htmlfile in mod_build.rglob("*.html"):
fix_links(htmlfile)
fix_links(mod_build / "searchindex.js")
conf_copy.unlink()
logo_copy_black.unlink()
logo_copy_white.unlink()
index_rst.unlink()


if __name__ == "__main__":
parser = argparse.ArgumentParser(
description=f"Build HTML documentation for pytket-{MODULE}."
)
parser.add_argument("-d", "--dest", help="copy artifacts into destination folder")
args = parser.parse_args()

print("Building docs for module:", MODULE)
build_module_docs()

if args.dest is not None:
dest = Path(args.dest)
shutil.copytree(
MODULES_DIR / "docs" / "build",
dest,
dirs_exist_ok=True,
)
10 changes: 10 additions & 0 deletions .github/workflows/docs/check-build-docs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

./.github/workflows/docs/build-docs 1>out.txt 2>err.txt
cat out.txt err.txt
ERRS=`cat err.txt`
if [ ! -z $ERRS ]
then
echo "Docs build failed."
exit 1
fi
143 changes: 143 additions & 0 deletions .github/workflows/docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-

# Configuration file for the Sphinx documentation builder.
# See https://www.sphinx-doc.org/en/master/usage/configuration.html

copyright = "2024 Quantinuum"
author = "Quantinuum"

extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.intersphinx",
"sphinx.ext.mathjax",
"sphinx_copybutton",
]

html_theme = "sphinx_book_theme"

html_theme_options = {
"repository_url": "https://github.com/CQCL/pytket-azure",
"use_repository_button": True,
"use_issues_button": True,
"logo": {
"image_light": "Quantinuum_logo_black.png",
"image_dark": "Quantinuum_logo_white.png",
},
}

html_static_path = ["_static"]

html_css_files = ["custom.css"]

# -- Extension configuration -------------------------------------------------

pytketdoc_base = "https://tket.quantinuum.com/api-docs/"

intersphinx_mapping = {
"https://docs.python.org/3/": None,
pytketdoc_base: None,
"https://qiskit.org/documentation/": None,
"http://docs.qulacs.org/en/latest/": None,
}

autodoc_member_order = "groupwise"

# The following code is for resolving broken hyperlinks in the doc.

import re
from typing import Any, Dict, List, Optional
from urllib.parse import urljoin

from docutils import nodes
from docutils.nodes import Element, TextElement
from sphinx.application import Sphinx
from sphinx.environment import BuildEnvironment

# Mappings for broken hyperlinks that intersphinx cannot resolve
external_url_mapping = {
"BasePass": urljoin(pytketdoc_base, "passes.html#pytket.passes.BasePass"),
"Predicate": urljoin(pytketdoc_base, "predicates.html#pytket.predicates.Predicate"),
"ResultHandle": urljoin(
pytketdoc_base,
"backends.html#pytket.backends.resulthandle.ResultHandle",
),
"BackendResult": urljoin(
pytketdoc_base,
"backends.html#pytket.backends.backendresult.BackendResult",
),
"Circuit": urljoin(pytketdoc_base, "circuit_class.html#pytket.circuit.Circuit"),
"BasisOrder": urljoin(pytketdoc_base, "circuit.html#pytket.circuit.BasisOrder"),
"QubitPauliOperator": urljoin(
pytketdoc_base, "utils.html#pytket.utils.QubitPauliOperator"
),
"QubitPauliString": urljoin(
pytketdoc_base, "pauli.html#pytket.pauli.QubitPauliString"
),
}

# Correct mappings for intersphinx to resolve
custom_internal_mapping = {
"pytket.utils.outcomearray.OutcomeArray": "pytket.utils.OutcomeArray",
"pytket.utils.operators.QubitPauliOperator": "pytket.utils.QubitPauliOperator",
"pytket.backends.backend.Backend": "pytket.backends.Backend",
"qiskit.dagcircuit.dagcircuit.DAGCircuit": "qiskit.dagcircuit.DAGCircuit",
"qiskit.providers.basebackend.BaseBackend": "qiskit.providers.BaseBackend",
"qiskit.qobj.qasm_qobj.QasmQobj": "qiskit.qobj.QasmQobj",
"qiskit.result.result.Result": "qiskit.result.Result",
}


def add_reference(
app: Sphinx, env: BuildEnvironment, node: Element, contnode: TextElement
) -> Optional[nodes.reference]:
# Fix references in docstrings that are inherited from the base pytket.backends.Backend class.
mapping = app.config.external_url_mapping
if node.astext() in mapping:
newnode = nodes.reference(
"",
"",
internal=False,
refuri=mapping[node.astext()],
reftitle=node.get("reftitle", node.astext()),
)
newnode.append(contnode)
return newnode
return None


def correct_signature(
app: Sphinx,
what: str,
name: str,
obj: Any,
options: Dict,
signature: str,
return_annotation: str,
) -> (str, str):
new_signature = signature
new_return_annotation = return_annotation
for k, v in app.config.custom_internal_mapping.items():
if signature is not None:
new_signature = new_signature.replace(k, v)
if return_annotation is not None:
new_return_annotation = new_return_annotation.replace(k, v)
# e.g. Replace <CXConfigType.Snake: 0> by CXConfigType.Snake to avoid silent failure in later stages.
if new_signature is not None:
enums_signature = re.findall(r"<.+?\: \d+>", new_signature)
for e in enums_signature:
new_signature = new_signature.replace(e, e[1 : e.find(":")])

if new_return_annotation is not None:
enums_return = re.findall(r"<.+?\: \d+>", new_return_annotation)
for e in enums_return:
new_return_annotation = new_return_annotation.replace(e, e[1 : e.find(":")])

return new_signature, new_return_annotation


def setup(app):
app.add_config_value("custom_internal_mapping", {}, "env")
app.add_config_value("external_url_mapping", {}, "env")
app.connect("missing-reference", add_reference)
app.connect("autodoc-process-signature", correct_signature)
3 changes: 3 additions & 0 deletions .github/workflows/docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
sphinx >= 5.0, <6.2.0
sphinx_book_theme >= 1.0.1, <2.0
sphinx-copybutton
Empty file.

0 comments on commit 4b7002a

Please sign in to comment.