From 35bdb5b22421fea43d35bf5baa77b012d072d7ac Mon Sep 17 00:00:00 2001
From: Duncan Macleod <macleoddm@cardiff.ac.uk>
Date: Mon, 17 Mar 2025 16:52:38 +0000
Subject: [PATCH 1/3] Improvements to the documentation

A few miscellaneous improvements to the documentation, including some content restructuring and configuration updates
---
 .gitignore                    |   3 +-
 .gitlab-ci.yml                |   1 +
 README.md                     |   3 +-
 docs/api.rst                  |  18 ----
 docs/api/gwdatafind.rst       |   7 ++
 docs/api/gwdatafind.utils.rst |   5 ++
 docs/auth.rst                 |   4 +-
 docs/commandline.rst          |  13 +++
 docs/conf.py                  | 154 ++++++++++++----------------------
 docs/index.rst                |  39 +++++++--
 docs/install.rst              |   5 +-
 docs/intro.rst                |   8 +-
 pyproject.toml                |   6 +-
 13 files changed, 123 insertions(+), 143 deletions(-)
 delete mode 100644 docs/api.rst
 create mode 100644 docs/api/gwdatafind.rst
 create mode 100644 docs/commandline.rst

diff --git a/.gitignore b/.gitignore
index 7d3643b..81c6f2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ __pycache__/
 
 # documentation outputs
 /docs/_build/
-/docs/api/
+/docs/api/*.rst
+!/docs/api/gwdatafind.rst
 !/docs/api/gwdatafind.utils.rst
 *.automodapi
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index da51b1a..110494c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -50,6 +50,7 @@ include:
 
   - component: $CI_SERVER_FQDN/computing/gitlab/components/sphinx/build@1
     inputs:
+      apt_packages: graphviz
       requirements: ".[docs]"
 
 
diff --git a/README.md b/README.md
index acb3270..2d4ddfd 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,7 @@ Gravitational-Wave Frame (GWF) files containing data from the current
 gravitational-wave detectors.
 
 [![PyPI version](https://badge.fury.io/py/gwdatafind.svg)](http://badge.fury.io/py/gwdatafind)
-[![Linux status](https://git.ligo.org/lscsoft/gwdatafind/badges/main/pipeline.svg)](https://git.ligo.org/lscsoft/gwdatafind/commits/main)
-[![Windows status](https://ci.appveyor.com/api/projects/status/js6gql8960qa9pkl?svg=true)](https://ci.appveyor.com/project/duncanmmacleod/gwdatafind)
+[![Conda version](https://img.shields.io/conda/vn/conda-forge/gwdatafind.svg)](https://anaconda.org/conda-forge/gwdatafind/)
 [![License](https://img.shields.io/pypi/l/gwdatafind.svg)](https://choosealicense.com/licenses/gpl-3.0/)
 [![Documentation status](https://readthedocs.org/projects/gwdatafind/badge/?version=latest)](https://gwdatafind.readthedocs.io/en/latest/?badge=latest)
 
diff --git a/docs/api.rst b/docs/api.rst
deleted file mode 100644
index 7df04ae..0000000
--- a/docs/api.rst
+++ /dev/null
@@ -1,18 +0,0 @@
-===================
- API documentation
-===================
-
-.. automodapi:: gwdatafind
-   :no-inheritance-diagram:
-   :no-heading:
-   :no-main-docstr:
-   :headings: =-
-   :skip: Session
-
-
-Submodules
-----------
-
-.. toctree::
-
-   api/gwdatafind.utils
diff --git a/docs/api/gwdatafind.rst b/docs/api/gwdatafind.rst
new file mode 100644
index 0000000..68157d8
--- /dev/null
+++ b/docs/api/gwdatafind.rst
@@ -0,0 +1,7 @@
+############
+`gwdatafind`
+############
+
+.. automodapi:: gwdatafind
+   :no-heading:
+   :headings: =-
diff --git a/docs/api/gwdatafind.utils.rst b/docs/api/gwdatafind.utils.rst
index 4ad0d52..ae5bdd2 100644
--- a/docs/api/gwdatafind.utils.rst
+++ b/docs/api/gwdatafind.utils.rst
@@ -1 +1,6 @@
+##################
+`gwdatafind.utils`
+##################
+
 .. automodapi:: gwdatafind.utils
+    :no-heading:
diff --git a/docs/auth.rst b/docs/auth.rst
index b51a920..2b266c7 100644
--- a/docs/auth.rst
+++ b/docs/auth.rst
@@ -33,7 +33,7 @@ GWDataFind servers may be operated with support for
 `SciTokens <https://scitokens.org>`__, an implementation of
 JSON Web Tokens designed for distributed scientific computing.
 
-When using the :doc:`API <api>`, the following keyword arguments
+When using :doc:`api/gwdatafind`, the following keyword arguments
 can be used with all functions to control the use of SciTokens:
 
 ``token``
@@ -83,7 +83,7 @@ proxies as authorisation credentials.
 This requires the X.509 credential _subject_ to be known to the server
 ahead of time.
 
-When using the :doc:`API <api>`, the following keyword arguments
+When using :doc:`api/gwdatafind`, the following keyword arguments
 can be used to control the use of X.509 credentials:
 
 ``cert``
diff --git a/docs/commandline.rst b/docs/commandline.rst
new file mode 100644
index 0000000..5231c5e
--- /dev/null
+++ b/docs/commandline.rst
@@ -0,0 +1,13 @@
+================
+``gw_data_find``
+================
+
+GWDataFind queries can be made using the command-line interface
+accessible via module execution (``python -m gwdatafind``) or
+the ``gw_data_find`` entry point script:
+
+.. argparse::
+    :module: gwdatafind.__main__
+    :func: command_line
+    :prog: gw_data_find
+    :nodescription:
diff --git a/docs/conf.py b/docs/conf.py
index a0ebf60..4396419 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,20 +1,38 @@
-# gwdatafind documentation build configuration file
+# Copyright (C) 2025 Cardiff University
+#
+# This file is part of GWDataFind.
+#
+# GWDataFind is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# GWDataFind is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GWDataFind.  If not, see <http://www.gnu.org/licenses/>.
+
+"""GWDataFind documentation configuration file."""
+
+from datetime import (
+    datetime,
+    timezone,
+)
 
-import inspect
-import re
-import sys
-from os import getenv
-from pathlib import Path
+import sphinx_github_style
 
 import gwdatafind
 
 # -- metadata
 
 project = "gwdatafind"
-copyright = "2018-2025, Cardiff University"
+copyright = f"{datetime.now(tz=timezone.utc).date().year}, Cardiff University"
 author = "Duncan Macleod"
 release = gwdatafind.__version__
-version = re.split(r"[\w-]", gwdatafind.__version__)[0]
+version = release.split("+", 1)[0]
 
 # -- config
 
@@ -26,6 +44,7 @@ default_role = "obj"
 # -- theme
 
 html_theme = "furo"
+html_title = f"{project} {version}"
 
 html_theme_options = {
     "footer_icons": [
@@ -52,6 +71,7 @@ extensions = [
     "sphinx.ext.intersphinx",
     "sphinx.ext.napoleon",
     "sphinx.ext.linkcode",
+    "sphinxarg.ext",
     "sphinx_automodapi.automodapi",
     "sphinx_copybutton",
     "sphinxarg.ext",
@@ -60,99 +80,33 @@ extensions = [
 # automodapi
 automodapi_inherited_members = False
 
+# copybutton
+copybutton_prompt_text = " |".join((  # noqa: FLY002
+    ">>>",
+    r"\.\.\.",
+    r"\$"
+    r"In \[\d*\]:",
+    r" {2,5}\.\.\.:",
+    " {5,8}: ",
+))
+copybutton_prompt_is_regexp = True
+copybutton_line_continuation_character = "\\"
+
 # intersphinx
-intersphinx_mapping = {
-    "igwn-auth-utils": (
-        "https://igwn-auth-utils.readthedocs.io/en/stable/",
-        None,
-    ),
-    "igwn-segments": (
-        "https://igwn-segments.readthedocs.io/en/stable/",
-        None,
-    ),
-    "python": (
-        "https://docs.python.org/",
-        None,
-    ),
-    "requests": (
-        "https://requests.readthedocs.io/en/stable/",
-        None,
-    ),
-    "scitokens": (
-        "https://scitokens.readthedocs.io/en/stable/",
-        None,
-    ),
-}
+intersphinx_mapping = {key: (value, None) for key, value in {
+    "igwn-auth-utils": "https://igwn-auth-utils.readthedocs.io/en/stable/",
+    "igwn-segments": "https://igwn-segments.readthedocs.io/en/stable/",
+    "python": "https://docs.python.org/",
+    "requests": "https://requests.readthedocs.io/en/stable/",
+    "scitokens": "https://scitokens.readthedocs.io/en/stable/",
+}.items()}
+
+# linkcode
+linkcode_url = sphinx_github_style.get_linkcode_url(
+    blob=sphinx_github_style.get_linkcode_revision("head"),
+    url="https://git.ligo.org/computing/gwdatafind/client",
+)
+linkcode_resolve = sphinx_github_style.get_linkcode_resolve(linkcode_url)
 
 # napoleon
 napoleon_use_rtype = False
-
-
-# -- linkcode
-
-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|\.)",
-    )
-    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
diff --git a/docs/index.rst b/docs/index.rst
index 1981e3e..b9d62ea 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,14 +1,32 @@
-
 ##########
 GWDataFind
 ##########
 
-.. toctree::
-    :hidden:
+The client library for the GWDataFind service.
 
-    GWDatafind <self>
+.. image:: https://badge.fury.io/py/gwdatafind.svg
+    :target: https://badge.fury.io/py/gwdatafind
+    :alt: gwdatafind PyPI release badge
 
-The client library for the GWDataFind service.
+.. image:: https://img.shields.io/conda/vn/conda-forge/gwdatafind.svg
+    :target: https://anaconda.org/conda-forge/gwdatafind/
+    :alt: gwdatafind conda-forge release badge
+
+.. image:: https://img.shields.io/pypi/l/gwdatafind.svg
+    :target: https://choosealicense.com/licenses/gpl-3.0/
+    :alt: gwdatafind license
+
+.. raw:: html
+
+    <br>
+
+.. image:: https://img.shields.io/gitlab/issues/open/computing%2Fgwdatafind%2Fclient?gitlab_url=https%3A%2F%2Fgit.ligo.org
+    :target: https://git.ligo.org/computing/gwdatafind/client/issues/
+    :alt: GitLab Issues
+
+.. image:: https://img.shields.io/gitlab/merge-requests/open/computing%2Fgwdatafind%2Fclient?gitlab_url=https%3A%2F%2Fgit.ligo.org
+    :target: https://git.ligo.org/computing/gwdatafind/client/merge_requests/
+    :alt: GitLab Merge Requests
 
 .. toctree::
     :caption: Documentation
@@ -21,6 +39,13 @@ The client library for the GWDataFind service.
 
 .. toctree::
     :caption: Reference
-    :maxdepth: 2
+    :maxdepth: 1
+
+    api/gwdatafind
+    api/gwdatafind.utils
+
+.. toctree::
+    :caption: Command-line interface
+    :maxdepth: 1
 
-    api
+    commandline
diff --git a/docs/install.rst b/docs/install.rst
index 082d7b7..88b06d7 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -70,10 +70,9 @@ RedHat / CentOS / Scientific / Rocky Linux
     dnf install gwdatafind
 
 See the IGWN Computing Guide software repositories entries for
-`Scientific Linux 7
-<https://computing.docs.ligo.org/guide/software/sl7/>`__
-or
 `Rocky Linux 8 <https://computing.docs.ligo.org/guide/software/rl8/>`__
+or
+`Rocky Linux 9 <https://computing.docs.ligo.org/guide/software/rl9/>`__
 for instructions on how to configure the required IGWN Yum repositories.
 
 To install the Python 3 library only (and not any command-line entry points):
diff --git a/docs/intro.rst b/docs/intro.rst
index 1184c93..6264426 100644
--- a/docs/intro.rst
+++ b/docs/intro.rst
@@ -63,10 +63,4 @@ Command-line interface
 
 GWDataFind also provides a command-line interface accessible via
 module execution (``python -m gwdatafind``) or the ``gw_data_find``
-entry point script:
-
-.. argparse::
-    :module: gwdatafind.__main__
-    :func: command_line
-    :prog: gw_data_find
-    :nodescription:
+entry point script. See :doc:`commandline`.
diff --git a/pyproject.toml b/pyproject.toml
index e10dd73..a04fa11 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -45,11 +45,11 @@ dynamic = [
 [project.optional-dependencies]
 docs = [
   "furo",
-  "numpydoc",
-  "Sphinx >= 4.4.0",
+  "Sphinx >=4.4.0",
   "sphinx-argparse",
-  "sphinx_automodapi",
+  "sphinx-automodapi",
   "sphinx-copybutton",
+  "sphinx-github-style",
 ]
 test = [
   "pytest >= 3.9.3",
-- 
GitLab


From c947392daefa0e595d268305909cd43240cc9f04 Mon Sep 17 00:00:00 2001
From: Duncan Macleod <macleoddm@cardiff.ac.uk>
Date: Tue, 18 Mar 2025 10:09:53 +0000
Subject: [PATCH 2/3] ui: fix incorrect RequestException intersphinx ref

---
 gwdatafind/ui.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/gwdatafind/ui.py b/gwdatafind/ui.py
index a95164e..c4bc38e 100644
--- a/gwdatafind/ui.py
+++ b/gwdatafind/ui.py
@@ -212,7 +212,7 @@ def find_observatories(
 
     Raises
     ------
-    requests.RequestsException
+    requests.RequestException
         if the request fails for any reason
 
     Examples
@@ -280,7 +280,7 @@ def find_types(
 
     Raises
     ------
-    requests.RequestsException
+    requests.RequestException
         if the request fails for any reason
 
     Examples
@@ -372,7 +372,7 @@ def find_times(
 
     Raises
     ------
-    requests.RequestsException
+    requests.RequestException
         if the request fails for any reason
     """  # noqa: E501
     qurl = _url(
@@ -459,7 +459,7 @@ def find_url(
 
     Raises
     ------
-    requests.RequestsException
+    requests.RequestException
         if the request fails for any reason
 
     RuntimeError
@@ -536,7 +536,7 @@ def find_latest(
 
     Raises
     ------
-    requests.RequestsException
+    requests.RequestException
         if the request fails for any reason
 
     RuntimeError
@@ -627,7 +627,7 @@ def find_urls(
 
     Raises
     ------
-    requests.RequestsException
+    requests.RequestException
         if the request fails for any reason
 
     RuntimeError
-- 
GitLab


From 57f271bc0acedfec8c46a3c246b75a099438d174 Mon Sep 17 00:00:00 2001
From: Duncan Macleod <macleoddm@cardiff.ac.uk>
Date: Tue, 18 Mar 2025 10:32:31 +0000
Subject: [PATCH 3/3] docs: remove redundant targets

---
 docs/auth.rst    | 2 --
 docs/install.rst | 6 ------
 2 files changed, 8 deletions(-)

diff --git a/docs/auth.rst b/docs/auth.rst
index 2b266c7..0494954 100644
--- a/docs/auth.rst
+++ b/docs/auth.rst
@@ -23,8 +23,6 @@ for the `GW Open Science Center (GWOSC) <https://www.gwosc.org/>`__:
     https://datafind.gwosc.org
 
 
-.. _scitokens:
-
 =========
 SciTokens
 =========
diff --git a/docs/install.rst b/docs/install.rst
index 88b06d7..4e4e27e 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -4,8 +4,6 @@
 Installing GWDataFind
 #####################
 
-.. _conda:
-
 =====
 Conda
 =====
@@ -20,8 +18,6 @@ The recommended method of installing GWDataFind is with
 
     conda install -c conda-forge gwdatafind
 
-.. _debian:
-
 ======
 Debian
 ======
@@ -45,8 +41,6 @@ To install the Python 3 library only (and not any command-line entry points):
 
     apt-get install python3-gwdatafind
 
-.. _pip:
-
 ===
 Pip
 ===
-- 
GitLab