From dc0ed5dd7added92df40a8a59569dfaacf5bedf2 Mon Sep 17 00:00:00 2001
From: Duncan Macleod <macleoddm@cardiff.ac.uk>
Date: Mon, 13 Jan 2025 13:08:48 +0000
Subject: [PATCH 1/3] docs: use furo docs theme

numerous improvements over sphinx_rtd_theme, namely automatic dark mode
---
 docs/Makefile  | 20 -----------
 docs/conf.py   | 98 ++++++++++++++------------------------------------
 pyproject.toml |  5 +--
 3 files changed, 30 insertions(+), 93 deletions(-)
 delete mode 100644 docs/Makefile

diff --git a/docs/Makefile b/docs/Makefile
deleted file mode 100644
index 8af9df2..0000000
--- a/docs/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
-SPHINXPROJ    = GWDataFind
-SOURCEDIR     = .
-BUILDDIR      = _build
-
-.PHONY: help html
-
-# Put it first so that "make" without argument is like "make help".
-help:
-	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-
-# Catch-all target: route all unknown targets to Sphinx using the new
-# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
-html:
-	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/conf.py b/docs/conf.py
index 7ab8599..6335b97 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,44 +1,44 @@
-#
 # gwdatafind documentation build configuration file
 
-import glob
-import os.path
 import re
 
 from gwdatafind import __version__ as gwdatafind_version
 
-extensions = [
-    'sphinx.ext.intersphinx',
-    'sphinx.ext.napoleon',
-    'sphinx_automodapi.automodapi',
-    'sphinxarg.ext',
-]
+# -- metadta
 
-#templates_path = ['_templates']
+project = "gwdatafind"
+copyright = "2018-2025, Cardiff University"
+author = "Duncan Macleod"
+release = gwdatafind_version
+version = re.split(r'[\w-]', gwdatafind_version)[0]
 
-source_suffix = '.rst'
+# -- config
 
+source_suffix = '.rst'
 master_doc = 'index'
 
-# General information about the project.
-project = "gwdatafind"
-copyright = "2018-2021, Cardiff University"
-author = "Duncan Macleod"
+default_role = 'obj'
 
-# The short X.Y version.
-version = re.split(r'[\w-]', gwdatafind_version)[0]
-# The full version, including alpha/beta/rc tags.
-release = gwdatafind_version
+# -- theme
 
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This patterns also effect to html_static_path and html_extra_path
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+html_theme = "furo"
+pygments_dark_style = "monokai"
 
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'monokai'
 
-# Intersphinx directory
+# -- extensions
+
+extensions = [
+    "sphinx.ext.intersphinx",
+    "sphinx.ext.napoleon",
+    "sphinx_automodapi.automodapi",
+    "sphinx_copybutton",
+    "sphinxarg.ext",
+]
+
+# automodapi
+automodapi_inherited_members = False
+
+# intersphinx
 intersphinx_mapping = {
     "igwn-auth-utils": (
         "https://igwn-auth-utils.readthedocs.io/en/stable/",
@@ -62,49 +62,5 @@ intersphinx_mapping = {
     ),
 }
 
-# The reST default role (used for this markup: `text`) to use for all
-# documents.
-default_role = 'obj'
-
-# napoleon configuration
+# napoleon
 napoleon_use_rtype = False
-
-# Don't inherit in automodapi
-numpydoc_show_class_members = False
-automodapi_inherited_members = False
-
-# -- Options for HTML output ----------------------------------------------
-
-# The theme to use for HTML and HTML Help pages.  See the documentation for
-# a list of builtin themes.
-#
-html_theme = 'sphinx_rtd_theme'
-
-# 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_static_path = ['_static']
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'gwdatafinddoc'
-
-# -- add static files----------------------------------------------------------
-
-def setup_static_content(app):
-    curdir = os.path.abspath(os.path.dirname(__file__))
-    # configure stylesheets
-    for sdir in html_static_path:
-        staticdir = os.path.join(curdir, sdir)
-
-        # add stylesheets
-        for cssf in glob.glob(os.path.join(staticdir, 'css', '*.css')):
-            app.add_css_file(cssf[len(staticdir)+1:])
-
-        # add custom javascript
-        for jsf in glob.glob(os.path.join(staticdir, 'js', '*.js')):
-            app.add_js_file(jsf[len(staticdir)+1:])
-
-# -- setup --------------------------------------------------------------------
-
-def setup(app):
-    setup_static_content(app)
diff --git a/pyproject.toml b/pyproject.toml
index 1801bd3..9db2a4f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -44,11 +44,12 @@ dynamic = [
 
 [project.optional-dependencies]
 docs = [
+  "furo",
   "numpydoc",
-  "sphinx >= 4.4.0",
+  "Sphinx >= 4.4.0",
   "sphinx-argparse",
   "sphinx_automodapi",
-  "sphinx_rtd_theme",
+  "sphinx-copybutton",
 ]
 test = [
   "pytest >= 2.8.0",
-- 
GitLab


From 0c4039218570adff9d703205b9e0877f8264acb8 Mon Sep 17 00:00:00 2001
From: Duncan Macleod <macleoddm@cardiff.ac.uk>
Date: Mon, 13 Jan 2025 17:32:26 +0000
Subject: [PATCH 2/3] docs: add linkcode and gitlab footer link

closes #38
---
 docs/conf.py | 96 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 91 insertions(+), 5 deletions(-)

diff --git a/docs/conf.py b/docs/conf.py
index 6335b97..15f6d73 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,16 +1,20 @@
 # gwdatafind documentation build configuration file
 
+import inspect
 import re
+import sys
+from os import getenv
+from pathlib import Path
 
-from gwdatafind import __version__ as gwdatafind_version
+import gwdatafind
 
-# -- metadta
+# -- metadata
 
 project = "gwdatafind"
 copyright = "2018-2025, Cardiff University"
 author = "Duncan Macleod"
-release = gwdatafind_version
-version = re.split(r'[\w-]', gwdatafind_version)[0]
+release = gwdatafind.__version__
+version = re.split(r'[\w-]', gwdatafind.__version__)[0]
 
 # -- config
 
@@ -22,14 +26,32 @@ default_role = 'obj'
 # -- theme
 
 html_theme = "furo"
-pygments_dark_style = "monokai"
 
+html_theme_options = {
+    "footer_icons": [
+        {
+            "name": "GitLab",
+            "url": "https://git.ligo.org/computing/gwdatafind/client",
+            "class": "fa-brands fa-gitlab",
+        },
+    ],
+}
+
+# need fontawesome for the gitlab icon in the footer
+html_css_files = [
+    "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/fontawesome.min.css",
+    "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/solid.min.css",
+    "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.2/css/brands.min.css",
+]
+
+pygments_dark_style = "monokai"
 
 # -- extensions
 
 extensions = [
     "sphinx.ext.intersphinx",
     "sphinx.ext.napoleon",
+    "sphinx.ext.linkcode",
     "sphinx_automodapi.automodapi",
     "sphinx_copybutton",
     "sphinxarg.ext",
@@ -64,3 +86,67 @@ intersphinx_mapping = {
 
 # napoleon
 napoleon_use_rtype = False
+
+
+# -- linkcode
+
+def _project_git_ref(version, prefix="v"):
+    """Returns the git reference for the given full release version.
+    """
+    _setuptools_scm_version_regex = re.compile(
+        r"\+g(\w+)(?:\Z|\.)",
+    )
+    if match := _setuptools_scm_version_regex.search(version):
+        return match.groups()[0]
+    return f"{prefix}{version}"
+
+
+PROJECT_GIT_REF = _project_git_ref(release, prefix="")
+PROJECT_PATH = Path(gwdatafind.__file__).parent
+PROJECT_URL = getenv(
+    "CI_PROJECT_URL",
+    "https://git.ligo.org/computing/gwdatafind/client",
+)
+PROJECT_BLOB_URL = f"{PROJECT_URL}/-/blob/{PROJECT_GIT_REF}/{PROJECT_PATH.name}"
+
+
+def linkcode_resolve(domain, info):
+    """Determine the URL corresponding to Python object.
+    """
+    if domain != "py" or not info["module"]:
+        return None
+
+    def find_source(module, fullname):
+        """Construct a source file reference for an object reference.
+        """
+        # resolve object
+        obj = sys.modules[module]
+        for part in fullname.split("."):
+            obj = getattr(obj, part)
+        # get filename relative to project
+        filename = Path(
+            inspect.getsourcefile(obj),  # type: ignore [arg-type]
+        ).relative_to(PROJECT_PATH).as_posix()
+        # get line numbers of this object
+        lines, lineno = inspect.findsource(obj)
+        if lineno:
+            start = lineno + 1  # 0-index
+            end = lineno + len(inspect.getblock(lines[lineno:]))
+        else:
+            start = end = 0
+        return filename, start, end
+
+    try:
+        path, start, end = find_source(info["module"], info["fullname"])
+    except (
+        AttributeError,  # object not found
+        OSError,  # file not found
+        TypeError,  # source for object not found
+        ValueError,  # file not from this project
+    ):
+        return None
+
+    url = f"{PROJECT_BLOB_URL}/{path}"
+    if start:
+        url += f"#L{start}-L{end}"
+    return url
-- 
GitLab


From 41b37bb1214d529e515dce95f41935bf11c7c5a4 Mon Sep 17 00:00:00 2001
From: Duncan Macleod <macleoddm@cardiff.ac.uk>
Date: Wed, 15 Jan 2025 11:58:16 +0000
Subject: [PATCH 3/3] docs: improve linkcode git ref handling

---
 docs/conf.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/docs/conf.py b/docs/conf.py
index 15f6d73..9e29178 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -93,6 +93,12 @@ napoleon_use_rtype = False
 def _project_git_ref(version, prefix="v"):
     """Returns the git reference for the given full release version.
     """
+    # handle builds in CI
+    if getenv("GITLAB_CI"):
+        return getenv("CI_COMMIT_REF")
+    if getenv("GITHUB_ACTIONS"):
+        return getenv("GITHUB_SHA")
+    # otherwise use the project metadata
     _setuptools_scm_version_regex = re.compile(
         r"\+g(\w+)(?:\Z|\.)",
     )
@@ -107,7 +113,7 @@ PROJECT_URL = getenv(
     "CI_PROJECT_URL",
     "https://git.ligo.org/computing/gwdatafind/client",
 )
-PROJECT_BLOB_URL = f"{PROJECT_URL}/-/blob/{PROJECT_GIT_REF}/{PROJECT_PATH.name}"
+PROJECT_BLOB_URL = f"{PROJECT_URL}/blob/{PROJECT_GIT_REF}/{PROJECT_PATH.name}"
 
 
 def linkcode_resolve(domain, info):
-- 
GitLab