Skip to content

Commit b04fdc9

Browse files
committed
docs(feat[gp-sphinx]): Migrate conf.py to merge_sphinx_config()
why: libtmux was maintaining ~290 lines of Sphinx configuration that duplicates what gp-sphinx now provides as shared defaults — fonts, theme, extensions, copybutton, autodoc, and linkcode resolution. what: - Replace manual conf.py with merge_sphinx_config() and make_linkcode_resolve() - Retain project-specific overrides: announcement banner, favicon, custom CSS, todo extension
1 parent 04b5cd8 commit b04fdc9

1 file changed

Lines changed: 30 additions & 265 deletions

File tree

docs/conf.py

Lines changed: 30 additions & 265 deletions
Original file line numberDiff line numberDiff line change
@@ -1,289 +1,54 @@
1-
# flake8: NOQA: E501
21
"""Sphinx configuration for libtmux."""
32

43
from __future__ import annotations
54

6-
import contextlib
7-
import inspect
85
import pathlib
96
import sys
10-
import typing as t
11-
from os.path import relpath
127

138
import libtmux
149

15-
if t.TYPE_CHECKING:
16-
from sphinx.application import Sphinx
10+
from gp_sphinx.config import make_linkcode_resolve, merge_sphinx_config
1711

1812
# Get the project root dir, which is the parent dir of this
1913
cwd = pathlib.Path(__file__).parent
2014
project_root = cwd.parent
2115
project_src = project_root / "src"
2216

2317
sys.path.insert(0, str(project_src))
24-
sys.path.insert(0, str(cwd / "_ext"))
2518

2619
# package data
2720
about: dict[str, str] = {}
2821
with (project_src / "libtmux" / "__about__.py").open() as fp:
2922
exec(fp.read(), about)
3023

31-
extensions = [
32-
"sphinx.ext.autodoc",
33-
"sphinx_pytest_fixtures",
34-
"sphinx_fonts",
35-
"sphinx.ext.intersphinx",
36-
"sphinx_autodoc_typehints",
37-
"sphinx.ext.todo",
38-
"sphinx.ext.linkcode",
39-
"sphinx.ext.napoleon",
40-
"sphinx_inline_tabs",
41-
"sphinx_copybutton",
42-
"sphinxext.opengraph",
43-
"sphinxext.rediraffe",
44-
"myst_parser",
45-
"linkify_issues",
46-
"sphinx_design",
47-
]
48-
49-
myst_enable_extensions = [
50-
"colon_fence",
51-
"substitution",
52-
"replacements",
53-
"strikethrough",
54-
"linkify",
55-
]
56-
57-
myst_heading_anchors = 4
58-
59-
templates_path = ["_templates"]
60-
61-
source_suffix = {".rst": "restructuredtext", ".md": "markdown"}
62-
63-
master_doc = "index"
64-
65-
project = about["__title__"]
66-
project_copyright = about["__copyright__"]
67-
68-
version = "{}".format(".".join(about["__version__"].split("."))[:2])
69-
release = "{}".format(about["__version__"])
70-
71-
exclude_patterns = ["_build"]
72-
73-
pygments_style = "monokai"
74-
pygments_dark_style = "monokai"
75-
76-
html_favicon = "_static/favicon.ico"
77-
html_static_path = ["_static"]
78-
html_css_files = ["css/custom.css"]
79-
html_extra_path = ["manifest.json"]
80-
html_theme = "furo"
81-
html_theme_path: list[str] = []
82-
html_theme_options: dict[str, str | list[dict[str, str]]] = {
83-
"light_logo": "img/libtmux.svg",
84-
"dark_logo": "img/libtmux.svg",
85-
"footer_icons": [
86-
{
87-
"name": "GitHub",
88-
"url": about["__github__"],
89-
"html": """
90-
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
91-
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
92-
</svg>
93-
""",
94-
"class": "",
95-
},
96-
],
97-
"source_repository": f"{about['__github__']}/",
98-
"source_branch": "master",
99-
"source_directory": "docs/",
100-
"announcement": "<em>Friendly reminder:</em> 📌 Pin the package, libtmux is pre-1.0 and APIs will be <a href='/migration.html'>changing</a> throughout 2026.",
101-
}
102-
html_sidebars = {
103-
"**": [
104-
"sidebar/scroll-start.html",
105-
"sidebar/brand.html",
106-
"sidebar/search.html",
107-
"sidebar/navigation.html",
108-
"sidebar/projects.html",
109-
"sidebar/scroll-end.html",
110-
],
111-
}
112-
113-
# linkify_issues
114-
issue_url_tpl = f"{about['__github__']}/issues/{{issue_id}}"
115-
116-
# sphinx.ext.autodoc
117-
autoclass_content = "both"
118-
autodoc_member_order = "bysource"
119-
# Automatically extract typehints when specified and place them in
120-
# descriptions of the relevant function/method.
121-
autodoc_typehints = "description"
122-
# Don't show class signature with the class' name.
123-
autodoc_class_signature = "separated"
124-
toc_object_entries_show_parents = "hide"
125-
126-
# sphinx-autodoc-typehints
127-
# Suppress warnings for forward references that can't be resolved
128-
# (types in TYPE_CHECKING blocks used for circular import avoidance)
129-
suppress_warnings = [
130-
"sphinx_autodoc_typehints.forward_reference",
131-
]
132-
133-
# sphinx-copybutton
134-
copybutton_prompt_text = (
135-
r">>> |\.\.\. |> |\$ |\# | In \[\d*\]: | {2,5}\.\.\.: | {5,8}: "
136-
)
137-
copybutton_prompt_is_regexp = True
138-
copybutton_remove_prompts = True
139-
copybutton_line_continuation_character = "\\"
140-
141-
# sphinxext-rediraffe
142-
rediraffe_redirects = "redirects.txt"
143-
rediraffe_branch = "master~1"
144-
145-
# sphinxext.opengraph
146-
ogp_site_url = about["__docs__"]
147-
ogp_image = "_static/img/icons/icon-192x192.png"
148-
ogp_site_name = about["__title__"]
149-
150-
# sphinx_fonts — self-hosted IBM Plex via Fontsource CDN
151-
sphinx_fonts = [
152-
{
153-
"family": "IBM Plex Sans",
154-
"package": "@fontsource/ibm-plex-sans",
155-
"version": "5.2.8",
156-
"weights": [400, 500, 600, 700],
157-
"styles": ["normal", "italic"],
158-
"subsets": ["latin", "latin-ext"],
159-
},
160-
{
161-
"family": "IBM Plex Mono",
162-
"package": "@fontsource/ibm-plex-mono",
163-
"version": "5.2.7",
164-
"weights": [400, 500, 600, 700],
165-
"styles": ["normal", "italic"],
166-
"subsets": ["latin", "latin-ext"],
24+
conf = merge_sphinx_config(
25+
project=about["__title__"],
26+
version=about["__version__"],
27+
copyright=about["__copyright__"],
28+
source_repository=f"{about['__github__']}/",
29+
docs_url=about["__docs__"],
30+
source_branch="master",
31+
light_logo="img/libtmux.svg",
32+
dark_logo="img/libtmux.svg",
33+
extra_extensions=["sphinx_pytest_fixtures", "sphinx.ext.todo"],
34+
intersphinx_mapping={
35+
"python": ("https://docs.python.org/", None),
36+
"pytest": ("https://docs.pytest.org/en/stable/", None),
16737
},
168-
]
169-
170-
sphinx_font_preload = [
171-
("IBM Plex Sans", 400, "normal"), # body text
172-
("IBM Plex Sans", 700, "normal"), # headings
173-
("IBM Plex Mono", 400, "normal"), # code blocks
174-
]
175-
176-
sphinx_font_fallbacks = [
177-
{
178-
"family": "IBM Plex Sans Fallback",
179-
"src": 'local("Arial"), local("Helvetica Neue"), local("Helvetica")',
180-
"size_adjust": "110.6%",
181-
"ascent_override": "92.7%",
182-
"descent_override": "24.9%",
183-
"line_gap_override": "0%",
38+
linkcode_resolve=make_linkcode_resolve(
39+
libtmux, about["__github__"], src_dir="src"
40+
),
41+
# Project-specific overrides
42+
theme_options={
43+
"announcement": (
44+
"<em>Friendly reminder:</em> 📌 Pin the package, libtmux is"
45+
" pre-1.0 and APIs will be <a href='/migration.html'>changing</a>"
46+
" throughout 2026."
47+
),
18448
},
185-
{
186-
"family": "IBM Plex Mono Fallback",
187-
"src": 'local("Courier New"), local("Courier")',
188-
"size_adjust": "100%",
189-
"ascent_override": "102.5%",
190-
"descent_override": "27.5%",
191-
"line_gap_override": "0%",
192-
},
193-
]
194-
195-
sphinx_font_css_variables = {
196-
"--font-stack": '"IBM Plex Sans", "IBM Plex Sans Fallback", -apple-system, BlinkMacSystemFont, sans-serif',
197-
"--font-stack--monospace": '"IBM Plex Mono", "IBM Plex Mono Fallback", SFMono-Regular, Menlo, Consolas, monospace',
198-
"--font-stack--headings": "var(--font-stack)",
199-
}
200-
201-
intersphinx_mapping = {
202-
"python": ("https://docs.python.org/", None),
203-
"pytest": ("https://docs.pytest.org/en/stable/", None),
204-
}
205-
206-
207-
def linkcode_resolve(domain: str, info: dict[str, str]) -> None | str:
208-
"""
209-
Determine the URL corresponding to Python object.
210-
211-
Notes
212-
-----
213-
From https://github.com/numpy/numpy/blob/v1.15.1/doc/source/conf.py, 7c49cfa
214-
on Jul 31. License BSD-3. https://github.com/numpy/numpy/blob/v1.15.1/LICENSE.txt
215-
"""
216-
if domain != "py":
217-
return None
218-
219-
modname = info["module"]
220-
fullname = info["fullname"]
221-
222-
submod = sys.modules.get(modname)
223-
if submod is None:
224-
return None
225-
226-
obj = submod
227-
for part in fullname.split("."):
228-
try:
229-
obj = getattr(obj, part)
230-
except Exception: # noqa: PERF203
231-
return None
232-
233-
# strip decorators, which would resolve to the source of the decorator
234-
# possibly an upstream bug in getsourcefile, bpo-1764286
235-
try:
236-
unwrap = inspect.unwrap
237-
except AttributeError:
238-
pass
239-
else:
240-
if callable(obj):
241-
obj = unwrap(obj)
242-
243-
try:
244-
fn = inspect.getsourcefile(obj)
245-
except Exception:
246-
fn = None
247-
if not fn:
248-
return None
249-
250-
try:
251-
source, lineno = inspect.getsourcelines(obj)
252-
except Exception:
253-
lineno = None
254-
255-
linespec = f"#L{lineno}-L{lineno + len(source) - 1}" if lineno else ""
256-
257-
fn = relpath(fn, start=pathlib.Path(libtmux.__file__).parent)
258-
259-
if "dev" in about["__version__"]:
260-
return "{}/blob/master/{}/{}/{}{}".format(
261-
about["__github__"],
262-
"src",
263-
about["__package_name__"],
264-
fn,
265-
linespec,
266-
)
267-
return "{}/blob/v{}/{}/{}/{}{}".format(
268-
about["__github__"],
269-
about["__version__"],
270-
"src",
271-
about["__package_name__"],
272-
fn,
273-
linespec,
274-
)
275-
276-
277-
def remove_tabs_js(app: Sphinx, exc: Exception) -> None:
278-
"""Remove tabs.js from _static after build."""
279-
# Fix for sphinx-inline-tabs#18
280-
if app.builder.format == "html" and not exc:
281-
tabs_js = pathlib.Path(app.builder.outdir) / "_static" / "tabs.js"
282-
with contextlib.suppress(FileNotFoundError):
283-
tabs_js.unlink() # When python 3.7 deprecated, use missing_ok=True
284-
285-
286-
def setup(app: Sphinx) -> None:
287-
"""Configure Sphinx app hooks."""
288-
app.add_js_file("js/spa-nav.js", loading_method="defer")
289-
app.connect("build-finished", remove_tabs_js)
49+
html_favicon="_static/favicon.ico",
50+
html_css_files=["css/custom.css"],
51+
html_extra_path=["manifest.json"],
52+
rediraffe_redirects="redirects.txt",
53+
)
54+
globals().update(conf)

0 commit comments

Comments
 (0)