Skip to content

Commit 45b9a64

Browse files
committed
Merge branch 'main' into mm/top-navigation-edit
2 parents ad9383c + d207049 commit 45b9a64

File tree

11 files changed

+393
-116
lines changed

11 files changed

+393
-116
lines changed

CHANGES.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,25 @@ CHANGES
66
Unreleased
77
----------
88

9+
2024/10/08 0.35.0
10+
-----------------
11+
- RTD: Add compatibility fixes for upstream changes at Read The Docs,
12+
`enabling Read the Docs Addons by default`_.
13+
- RTD: Fix CSS to hide RTD-injected elements: Ads, fly-out, and footer.
14+
- RTD: Vendorize ``sphinx-build-compatibility`` to permit publishing
15+
``crate-docs-theme`` to PyPI.
16+
- RTD: Fix inquiring active project versions.
17+
The v2 API returns or started returning inactive builds (PR numbers) in
18+
inquiries to active project versions. The v3 API works better, so the
19+
code in ``sphinx-build-compatibility`` has been adjusted correspondingly.
20+
- `New GitHub Issues`_: Make link checker ignore HTML anchor references
21+
on GitHub after switching to the evolved GitHub Issues. This includes an
22+
update to ``sphinx>=7.1,<9``, to respect the
23+
``linkcheck_anchors_ignore_for_url`` configuration setting.
24+
25+
.. _enabling Read the Docs Addons by default: https://about.readthedocs.com/blog/2024/07/addons-by-default/
26+
.. _New GitHub Issues: https://github.blog/changelog/2024-10-01-evolving-github-issues-public-beta/
27+
928
2024/09/24 0.34.1
1029
-----------------
1130
- Added a "Academy" menu item

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
"js-cookie": "^3.0.5",
88
"normalize.css": "^8.0.1",
99
"postcss-loader": "^8.1",
10-
"sass": "^1.77.8",
10+
"sass": "^1.79.4",
1111
"sass-loader": "^13.2",
1212
"sticky-sidebar": "^3.3.1",
1313
"style-loader": "^4.0",
14-
"webpack": "^5.94",
14+
"webpack": "^5.95",
1515
"webpack-cli": "^4.10",
1616
"webpack-modernizr-loader": "^5.0.0"
1717
},

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"furo==2024.05.06",
6464
"jinja2>=3,<4",
6565
"myst-parser[linkify]<5",
66-
"sphinx>=4.6,<7",
66+
"sphinx>=7.1,<9",
6767
"sphinx-basic-ng==1.0.0b2",
6868
"sphinx-copybutton>=0.3.1,<1",
6969
"sphinx-design-elements==0.4.0",

src/crate/theme/rtd/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
import os
2525

26-
VERSION = (0, 34, 1)
26+
VERSION = (0, 35, 0)
2727

2828
__version__ = ".".join(str(v) for v in VERSION)
2929
__version_full__ = __version__

src/crate/theme/rtd/conf/__init__.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# However, if you have executed another commercial license agreement
1919
# with Crate these terms will supersede the license and you may use the
2020
# software solely pursuant to the terms of the relevant commercial agreement.
21+
import os
2122

2223
from crate.theme import rtd as theme
2324
from crate.theme.rtd import __version__
@@ -170,6 +171,11 @@
170171
# 403 Client Error: Forbidden for url
171172
"https://unsplash.com/.*",
172173
]
174+
linkcheck_anchors_ignore_for_url = [
175+
# Requires JavaScript.
176+
# After opting-in to new GitHub issues, Sphinx can no longer grok the HTML anchor references.
177+
r"https://github.com",
178+
]
173179
linkcheck_retries = 3
174180
linkcheck_timeout = 15
175181

@@ -193,6 +199,35 @@
193199

194200
def setup(app):
195201

202+
def setup_sphinx_compatibility():
203+
"""
204+
Resolve problem with `sphinx_build_compatibility` extension.
205+
206+
Add Sphinx extension at runtime, in order to be able to configure it previously.
207+
This is needed because it has some quirks that reveal themselves when invoked in
208+
non-RTD environments.
209+
210+
- https://github.com/crate/crate-docs-theme/issues/536
211+
- https://about.readthedocs.com/blog/2024/07/addons-by-default/
212+
- https://github.com/readthedocs/sphinx-build-compatibility
213+
"""
214+
215+
# Extension error (sphinx_build_compatibility.extension):
216+
# Handler <function manipulate_config at 0x10a4289a0> for event 'config-inited' threw an exception
217+
# (exception: argument of type 'NoneType' is not iterable)
218+
os.environ.setdefault("READTHEDOCS_GIT_CLONE_URL", "")
219+
220+
# IndexError: list index out of range
221+
# project_id = response_project["results"][0]["id"]
222+
# Currently needs a valid project on PyPI. Long-term fix should go into upstream code.
223+
os.environ.setdefault("READTHEDOCS_PROJECT", "crate-docs-theme")
224+
225+
# Exception: 'NoneType' object is not subscriptable
226+
os.environ.setdefault("READTHEDOCS_GIT_COMMIT_HASH", "")
227+
228+
# Register vendorized Sphinx plugin.
229+
app.setup_extension("crate.theme.vendor.rtd_compat.extension")
230+
196231
# Configure Sphinx/RTD to host projects on a custom domain, but also on a non-root resource.
197232
def configure_self_hosted_on_path(app_inited):
198233
"""
@@ -286,6 +321,9 @@ def apply_html_context_custom(app_inited):
286321
except Exception as ex:
287322
print(f"ERROR: Unable to adjust `html_context`. Reason: {ex}")
288323

324+
# Read The Docs compatibility issues.
325+
setup_sphinx_compatibility()
326+
289327
# Modern / NG / Furo.
290328
app.require_sphinx("3.0")
291329
app.connect("html-page-context", _html_page_context)

src/crate/theme/rtd/crate/static/css/custom.css

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,9 +1520,9 @@ ul.search li {
15201520
}
15211521
}
15221522

1523-
/* hide RTD injected footer */
1524-
.injected {
1525-
display: none;
1523+
/* Hide RTD-injected elements: Ads, fly-out, and footer. */
1524+
#readthedocs-ea, readthedocs-flyout, .injected {
1525+
display: none !important;
15261526
}
15271527

15281528
.mb-0 {

src/crate/theme/vendor/__init__.py

Whitespace-only changes.

src/crate/theme/vendor/rtd_compat/__init__.py

Whitespace-only changes.
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
import os
2+
3+
from sphinx import version_info
4+
from sphinx.util import logging
5+
6+
import requests
7+
8+
from .utils import get_github_username_repo, get_bitbucket_username_repo, get_gitlab_username_repo
9+
10+
11+
logger = logging.getLogger(__name__)
12+
13+
14+
# https://www.sphinx-doc.org/en/stable/extdev/appapi.html#event-html-page-context
15+
def manipulate_config(app, config):
16+
logger.info(
17+
'Running "manipulate_config" from Read the Docs "sphinx_build_compatibility" extension. '
18+
'Consider removing it from your requirements and migrating your documentation accordingly. '
19+
'This extension is useful only as a transition but it will not be maintained.'
20+
)
21+
22+
# Add Read the Docs' static path.
23+
# Add to the end because it overwrites previous files.
24+
if not hasattr(config, "html_static_path"):
25+
config.html_static_path = []
26+
if os.path.exists('_static'):
27+
config.html_static_path.append('_static')
28+
29+
# Define this variable in case it's not defined by the user.
30+
# It defaults to `alabaster` which is the default from Sphinx.
31+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_theme
32+
if not hasattr(config, "html_theme"):
33+
config.html_theme = 'alabaster'
34+
35+
# Example: ``/docs/``
36+
conf_py_path = "/"
37+
conf_py_path += os.path.relpath(
38+
str(app.srcdir),
39+
os.environ.get("READTHEDOCS_REPOSITORY_PATH"),
40+
).strip("/")
41+
conf_py_path += "/"
42+
43+
git_clone_url = os.environ.get("READTHEDOCS_GIT_CLONE_URL")
44+
github_user, github_repo = get_github_username_repo(git_clone_url)
45+
bitbucket_user, bitbucket_repo = get_bitbucket_username_repo(git_clone_url)
46+
gitlab_user, gitlab_repo = get_gitlab_username_repo(git_clone_url)
47+
48+
project_slug = os.environ.get("READTHEDOCS_PROJECT")
49+
version_slug = os.environ.get("READTHEDOCS_VERSION")
50+
production_domain = os.environ.get("READTHEDOCS_PRODUCTION_DOMAIN", "readthedocs.org")
51+
52+
scheme = "https"
53+
if production_domain.startswith("devthedocs"):
54+
scheme = "http"
55+
56+
# We are using APIv2 to pull active versions, downloads and subprojects
57+
# because APIv3 requires a token.
58+
try:
59+
response_project = requests.get(
60+
f"{scheme}://{production_domain}/api/v3/projects/{project_slug}/",
61+
timeout=2,
62+
).json()
63+
language = response_project["language"]["code"]
64+
except Exception:
65+
logger.warning(
66+
"An error ocurred when hitting API to fetch project language. Defaulting to 'en'.",
67+
exc_info=True,
68+
)
69+
language = "en"
70+
71+
try:
72+
response_versions = requests.get(
73+
f"{scheme}://{production_domain}/api/v3/projects/{project_slug}/versions/?active=true",
74+
timeout=2,
75+
).json()
76+
versions = [
77+
(version["slug"], f"/{language}/{version['slug']}/")
78+
for version in response_versions["results"]
79+
]
80+
except Exception:
81+
logger.warning(
82+
"An error ocurred when hitting API to fetch active versions. Defaulting to an empty list.",
83+
exc_info=True,
84+
)
85+
versions = []
86+
87+
try:
88+
downloads = []
89+
for version in response_versions["results"]:
90+
if version["slug"] != version_slug:
91+
continue
92+
93+
for key, value in version["downloads"]:
94+
downloads.append(
95+
(
96+
key,
97+
value,
98+
),
99+
)
100+
except Exception:
101+
logger.warning(
102+
"An error ocurred when generating the list of downloads. Defaulting to an empty list.",
103+
exc_info=True,
104+
)
105+
downloads = []
106+
107+
try:
108+
subprojects = []
109+
response_project = requests.get(
110+
f"{scheme}://{production_domain}/api/v2/project/?slug={project_slug}",
111+
timeout=2,
112+
).json()
113+
project_id = response_project["results"][0]["id"]
114+
115+
response_subprojects = requests.get(
116+
f"{scheme}://readthedocs.org/api/v2/project/{project_id}/subprojects/",
117+
timeout=2,
118+
).json()
119+
for subproject in response_subprojects["subprojects"]:
120+
subprojects.append(
121+
(
122+
subproject["slug"],
123+
subproject["canonical_url"],
124+
),
125+
)
126+
except Exception:
127+
logger.warning(
128+
"An error ocurred when hitting API to fetch project/subprojects. Defaulting to an empty list.",
129+
exc_info=True,
130+
)
131+
subprojects = []
132+
133+
# Add project information to the template context.
134+
context = {
135+
'html_theme': config.html_theme,
136+
'current_version': os.environ.get("READTHEDOCS_VERSION_NAME"),
137+
'version_slug': version_slug,
138+
139+
# NOTE: these are used to dump them in some JS files and to build the URLs in flyout.
140+
# However, we are replacing them with the new Addons.
141+
# I wouldn't include them in the first version of the extension.
142+
# We could hardcode them if we want, tho.
143+
#
144+
# 'MEDIA_URL': "{{ settings.MEDIA_URL }}",
145+
# 'STATIC_URL': "{{ settings.STATIC_URL }}",
146+
# 'proxied_static_path': "{{ proxied_static_path }}",
147+
148+
'PRODUCTION_DOMAIN': production_domain,
149+
'versions': versions,
150+
"downloads": downloads,
151+
"subprojects": subprojects,
152+
153+
'slug': project_slug,
154+
'rtd_language': os.environ.get("READTHEDOCS_LANGUAGE"),
155+
'canonical_url': os.environ.get("READTHEDOCS_CANONICAL_URL"),
156+
157+
# NOTE: these seem to not be used.
158+
# 'name': u'{{ project.name }}',
159+
# 'analytics_code': '{{ project.analytics_code }}',
160+
# 'single_version': {{ project.is_single_version }},
161+
# 'programming_language': u'{{ project.programming_language }}',
162+
163+
'conf_py_path': conf_py_path,
164+
# Used only for "readthedocs-sphinx-ext" which we are not installing anymore.
165+
# 'api_host': '{{ api_host }}',
166+
# 'proxied_api_host': '{{ project.proxied_api_host }}',
167+
168+
'github_user': github_user,
169+
'github_repo': github_repo,
170+
'github_version': os.environ.get("READTHEDOCS_GIT_IDENTIFIER"),
171+
'display_github': github_user is not None,
172+
'bitbucket_user': bitbucket_user,
173+
'bitbucket_repo': bitbucket_repo,
174+
'bitbucket_version': os.environ.get("READTHEDOCS_GIT_IDENTIFIER"),
175+
'display_bitbucket': bitbucket_user is not None,
176+
'gitlab_user': gitlab_user,
177+
'gitlab_repo': gitlab_repo,
178+
'gitlab_version': os.environ.get("READTHEDOCS_GIT_IDENTIFIER"),
179+
'display_gitlab': gitlab_user is not None,
180+
'READTHEDOCS': True,
181+
'using_theme': (config.html_theme == "default"),
182+
'new_theme': (config.html_theme == "sphinx_rtd_theme"),
183+
'source_suffix': ".rst",
184+
'ad_free': False,
185+
'docsearch_disabled': False,
186+
187+
# We don't support Google analytics anymore.
188+
# See https://github.com/readthedocs/readthedocs.org/issues/9530
189+
'user_analytics_code': "",
190+
'global_analytics_code': None,
191+
192+
'commit': os.environ.get("READTHEDOCS_GIT_COMMIT_HASH")[:8],
193+
}
194+
195+
# For sphinx >=1.8 we can use html_baseurl to set the canonical URL.
196+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_baseurl
197+
if version_info >= (1, 8):
198+
if not hasattr(config, 'html_baseurl'):
199+
config.html_baseurl = context['canonical_url']
200+
context['canonical_url'] = None
201+
202+
203+
if hasattr(config, 'html_context'):
204+
for key in context:
205+
if key not in config.html_context:
206+
config.html_context[key] = context[key]
207+
else:
208+
config.html_context = context
209+
210+
project_language = os.environ.get("READTHEDOCS_LANGUAGE")
211+
212+
# User's Sphinx configurations
213+
language_user = config.language
214+
latex_engine_user = config.latex_engine
215+
latex_elements_user = config.latex_elements
216+
217+
# Remove this once xindy gets installed in Docker image and XINDYOPS
218+
# env variable is supported
219+
# https://github.com/rtfd/readthedocs-docker-images/pull/98
220+
latex_use_xindy = False
221+
222+
chinese = any([
223+
language_user in ('zh_CN', 'zh_TW'),
224+
project_language in ('zh_CN', 'zh_TW'),
225+
])
226+
227+
japanese = any([
228+
language_user == 'ja',
229+
project_language == 'ja',
230+
])
231+
232+
if chinese:
233+
config.latex_engine = latex_engine_user or 'xelatex'
234+
235+
latex_elements_rtd = {
236+
'preamble': '\\usepackage[UTF8]{ctex}\n',
237+
}
238+
config.latex_elements = latex_elements_user or latex_elements_rtd
239+
elif japanese:
240+
config.latex_engine = latex_engine_user or 'platex'
241+
242+
# Make sure our build directory is always excluded
243+
if not hasattr(config, "exclude_patterns"):
244+
config.exclude_patterns = []
245+
config.exclude_patterns.extend(['_build'])
246+
247+
248+
def setup(app):
249+
app.connect('config-inited', manipulate_config)
250+
251+
return {
252+
'version': "0.0.0",
253+
'parallel_read_safe': True,
254+
'parallel_write_safe': True,
255+
}

0 commit comments

Comments
 (0)