summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorGravatar Hassan Abouelela <[email protected]>2022-02-24 21:58:42 +0400
committerGravatar GitHub <[email protected]>2022-02-24 21:58:42 +0400
commit554919b6314814320f35431a6cfb32ca81b09079 (patch)
treea330a6f7b8a4081be138c8f5acc3be3ca8ced99a /docs
parentMerge pull request #23 from python-discord/bump-deps (diff)
parentUpdate GHA Docs Build To Match Pyproject (diff)
Merge pull request #29 from python-discord/port-utilities
Port utilities
Diffstat (limited to 'docs')
-rw-r--r--docs/_static/changelog.css11
-rw-r--r--docs/_static/changelog.js37
-rw-r--r--docs/changelog.rst14
-rw-r--r--docs/conf.py125
-rw-r--r--docs/index.rst6
-rw-r--r--docs/utils.py117
6 files changed, 135 insertions, 175 deletions
diff --git a/docs/_static/changelog.css b/docs/_static/changelog.css
deleted file mode 100644
index 343792a1..00000000
--- a/docs/_static/changelog.css
+++ /dev/null
@@ -1,11 +0,0 @@
-[data-theme='dark'] #changelog .dark,
-[data-theme='light'] #changelog .light,
-[data-theme='auto'] #changelog .light {
- display: inline;
-}
-
-[data-theme='dark'] #changelog .light,
-[data-theme='light'] #changelog .dark,
-[data-theme='auto'] #changelog .dark {
- display: none;
-}
diff --git a/docs/_static/changelog.js b/docs/_static/changelog.js
deleted file mode 100644
index f72d025c..00000000
--- a/docs/_static/changelog.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/** Update the changelog colors in dark mode */
-
-const changelog = document.getElementById("changelog");
-
-function updateEntryColor(entry) {
- const line = entry.lastChild;
- const lightColorSpan = line.childNodes.item(1);
- const darkColorSpan = lightColorSpan.cloneNode(true);
-
- line.insertBefore(darkColorSpan, lightColorSpan);
-
- lightColorSpan.classList.add("light");
- darkColorSpan.classList.add("dark");
-
- let color;
- switch (darkColorSpan.textContent) {
- case "Feature":
- color = "#5BF38E";
- break;
- case "Support":
- color = "#55A5E7";
- break;
- case "Bug":
- color = "#E14F4F";
- break;
- default:
- color = null;
- }
-
- darkColorSpan.style["color"] = color;
-}
-
-if (changelog !== null) {
- for (let collection of changelog.getElementsByClassName("simple")) {
- Array.from(collection.children).forEach(updateEntryColor);
- }
-}
diff --git a/docs/changelog.rst b/docs/changelog.rst
deleted file mode 100644
index 743fcc20..00000000
--- a/docs/changelog.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-.. See docs for details on formatting your entries
- https://releases.readthedocs.io/en/latest/concepts.html
-
-
-Changelog
-=========
-
-- :release:`1.2.0 <9th January 2022>`
-- :feature:`12` Code block detection regex
-- :release:`1.1.0 <2nd December 2021>`
-- :support:`2` Autogenerated docs.
-- :feature:`2` Regex utility.
-- :release:`1.0.0 <17th November 2021>`
-- :support:`1` Core package, poetry, and linting CI.
diff --git a/docs/conf.py b/docs/conf.py
index 4ab831d3..476a4d36 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,17 +1,20 @@
# Configuration file for the Sphinx documentation builder.
# https://www.sphinx-doc.org/en/master/usage/configuration.html
-import ast
-import importlib
-import inspect
+import functools
+import os.path
import sys
-import typing
from pathlib import Path
import git
import tomli
from sphinx.application import Sphinx
+# Handle the path not being set correctly in actions.
+sys.path.insert(0, os.path.abspath('..'))
+
+from docs import utils # noqa: E402
+
# -- Project information -----------------------------------------------------
project = "Bot Core"
@@ -38,11 +41,11 @@ add_module_names = False
# ones.
extensions = [
"sphinx.ext.extlinks",
+ "sphinx.ext.intersphinx",
"sphinx.ext.autodoc",
"sphinx.ext.todo",
"sphinx.ext.napoleon",
"sphinx_autodoc_typehints",
- "releases",
"sphinx.ext.linkcode",
"sphinx.ext.githubpages",
]
@@ -80,52 +83,10 @@ html_logo = "https://raw.githubusercontent.com/python-discord/branding/main/logo
html_favicon = html_logo
html_css_files = [
- "changelog.css",
"logo.css",
]
-html_js_files = [
- "changelog.js",
-]
-
-
-# -- Autodoc cleanup ---------------------------------------------------------
-# Clean up the output generated by autodoc to produce a nicer documentation tree
-# This is kept in a function to avoid polluting the namespace
-def __cleanup() -> None:
- for file in (PROJECT_ROOT / "docs" / "output").iterdir():
- if file.name == "modules.rst":
- # We only have one module, so this is redundant
- # Remove it and flatten out the tree
- file.unlink()
-
- elif file.name == "botcore.rst":
- # We want to bring the submodule name to the top, and remove anything that's not a submodule
- result = ""
- for line in file.read_text(encoding="utf-8").splitlines(keepends=True):
- if ".." not in line and result == "":
- # We have not reached the first submodule, this is all filler
- continue
- elif "Module contents" in line:
- # We have parsed all the submodules, so let's skip the redudant module name
- break
- result += line
-
- result = "Botcore\n=======\n\n" + result
- file.write_text(result, encoding="utf-8")
-
- else:
- # Clean up the submodule name so it's just the name without the top level module name
- # example: `botcore.regex module` -> `regex`
- lines = file.read_text(encoding="utf-8").splitlines()
- lines[0] = lines[0].replace("botcore.", "").replace("module", "").strip()
-
- # Take the opportunity to configure autodoc
- lines = "\n".join(lines).replace("undoc-members", "special-members")
- file.write_text(lines, encoding="utf-8")
-
-
-__cleanup()
+utils.cleanup()
def skip(*args) -> bool:
@@ -159,70 +120,18 @@ napoleon_numpy_docstring = False
napoleon_attr_annotations = True
-# -- Options for releases extension ------------------------------------------
-releases_github_path = REPO_LINK.removeprefix("https://github.com/")
-
-
# -- Options for extlinks extension ------------------------------------------
extlinks = {
"repo-file": (f"{REPO_LINK}/blob/main/%s", "repo-file %s")
}
+# -- Options for intersphinx extension ---------------------------------------
+intersphinx_mapping = {
+ "python": ("https://docs.python.org/3", None),
+ "discord": ("https://discordpy.readthedocs.io/en/master/", None),
+}
+
+
# -- Options for the linkcode extension --------------------------------------
-def linkcode_resolve(domain: str, info: dict[str, str]) -> typing.Optional[str]:
- """
- Function called by linkcode to get the URL for a given resource.
-
- See for more details:
- https://www.sphinx-doc.org/en/master/usage/extensions/linkcode.html#confval-linkcode_resolve
- """
- if domain != "py":
- raise Exception("Unknown domain passed to linkcode function.")
-
- symbol_name = info["fullname"]
-
- module = importlib.import_module(info["module"])
-
- symbol = [module]
- for name in symbol_name.split("."):
- symbol.append(getattr(symbol[-1], name))
- symbol_name = name
-
- try:
- lines, start = inspect.getsourcelines(symbol[-1])
- end = start + len(lines)
- except TypeError:
- # Find variables by parsing the ast
- source = ast.parse(inspect.getsource(symbol[-2]))
- while isinstance(source.body[0], ast.ClassDef):
- source = source.body[0]
-
- for ast_obj in source.body:
- if isinstance(ast_obj, ast.Assign):
- names = []
- for target in ast_obj.targets:
- if isinstance(target, ast.Tuple):
- names.extend([name.id for name in target.elts])
- else:
- names.append(target.id)
-
- if symbol_name in names:
- start, end = ast_obj.lineno, ast_obj.end_lineno
- break
- else:
- raise Exception(f"Could not find symbol `{symbol_name}` in {module.__name__}.")
-
- _, offset = inspect.getsourcelines(symbol[-2])
- if offset != 0:
- offset -= 1
- start += offset
- end += offset
-
- file = Path(inspect.getfile(module)).relative_to(PROJECT_ROOT).as_posix()
-
- url = f"{SOURCE_FILE_LINK}/{file}#L{start}"
- if end != start:
- url += f"-L{end}"
-
- return url
+linkcode_resolve = functools.partial(utils.linkcode_resolve, SOURCE_FILE_LINK)
diff --git a/docs/index.rst b/docs/index.rst
index e7c25ef1..81975f35 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -13,11 +13,6 @@ Reference
output/botcore
-.. toctree::
- :caption: Other:
-
- changelog
-
Extras
==================
@@ -25,3 +20,4 @@ Extras
* :ref:`genindex`
* :ref:`search`
* :repo-file:`Information <docs/README.md>`
+* :repo-file:`Changelog <CHANGELOG.md>`
diff --git a/docs/utils.py b/docs/utils.py
new file mode 100644
index 00000000..76b3e098
--- /dev/null
+++ b/docs/utils.py
@@ -0,0 +1,117 @@
+"""Utilities used in generating docs."""
+
+import ast
+import importlib
+import inspect
+import typing
+from pathlib import Path
+
+PROJECT_ROOT = Path(__file__).parent.parent
+
+
+def linkcode_resolve(source_url: str, domain: str, info: dict[str, str]) -> typing.Optional[str]:
+ """
+ Function called by linkcode to get the URL for a given resource.
+
+ See for more details:
+ https://www.sphinx-doc.org/en/master/usage/extensions/linkcode.html#confval-linkcode_resolve
+ """
+ if domain != "py":
+ raise Exception("Unknown domain passed to linkcode function.")
+
+ symbol_name = info["fullname"]
+
+ module = importlib.import_module(info["module"])
+
+ symbol = [module]
+ for name in symbol_name.split("."):
+ symbol.append(getattr(symbol[-1], name))
+ symbol_name = name
+
+ try:
+ lines, start = inspect.getsourcelines(symbol[-1])
+ end = start + len(lines)
+ except TypeError:
+ # Find variables by parsing the ast
+ source = ast.parse(inspect.getsource(symbol[-2]))
+ while isinstance(source.body[0], ast.ClassDef):
+ source = source.body[0]
+
+ for ast_obj in source.body:
+ if isinstance(ast_obj, ast.Assign):
+ names = []
+ for target in ast_obj.targets:
+ if isinstance(target, ast.Tuple):
+ names.extend([name.id for name in target.elts])
+ else:
+ names.append(target.id)
+
+ if symbol_name in names:
+ start, end = ast_obj.lineno, ast_obj.end_lineno
+ break
+ else:
+ raise Exception(f"Could not find symbol `{symbol_name}` in {module.__name__}.")
+
+ _, offset = inspect.getsourcelines(symbol[-2])
+ if offset != 0:
+ offset -= 1
+ start += offset
+ end += offset
+
+ file = Path(inspect.getfile(module)).relative_to(PROJECT_ROOT).as_posix()
+
+ url = f"{source_url}/{file}#L{start}"
+ if end != start:
+ url += f"-L{end}"
+
+ return url
+
+
+def cleanup() -> None:
+ """Remove unneeded autogenerated doc files, and clean up others."""
+ included = __get_included()
+
+ for file in (PROJECT_ROOT / "docs" / "output").iterdir():
+ if file.name in ("botcore.rst", "botcore.exts.rst", "botcore.utils.rst") and file.name in included:
+ content = file.read_text(encoding="utf-8").splitlines(keepends=True)
+
+ # Rename the extension to be less wordy
+ # Example: botcore.exts -> Botcore Exts
+ title = content[0].split()[0].strip().replace("botcore.", "").replace(".", " ").title()
+ title = f"{title}\n{'=' * len(title)}\n\n"
+ content = title, *content[3:]
+
+ file.write_text("".join(content), encoding="utf-8")
+
+ elif file.name in included:
+ # Clean up the submodule name so it's just the name without the top level module name
+ # example: `botcore.regex module` -> `regex`
+ lines = file.read_text(encoding="utf-8").splitlines(keepends=True)
+ lines[0] = lines[0].replace("module", "").strip().split(".")[-1] + "\n"
+ file.write_text("".join(lines))
+
+ else:
+ # These are files that have not been explicitly included in the docs via __all__
+ print("Deleted file", file.name)
+ file.unlink()
+ continue
+
+ # Take the opportunity to configure autodoc
+ content = file.read_text(encoding="utf-8").replace("undoc-members", "special-members")
+ file.write_text(content, encoding="utf-8")
+
+
+def __get_included() -> set[str]:
+ """Get a list of files that should be included in the final build."""
+
+ def get_all_from_module(module_name: str) -> set[str]:
+ module = importlib.import_module(module_name)
+ _modules = {module.__name__ + ".rst"}
+
+ if hasattr(module, "__all__"):
+ for sub_module in module.__all__:
+ _modules.update(get_all_from_module(sub_module))
+
+ return _modules
+
+ return get_all_from_module("botcore")