Fix Sphinx 9 compatibility for CSS and JS asset rendering#25
Fix Sphinx 9 compatibility for CSS and JS asset rendering#25mdickinson merged 7 commits intomainfrom
Conversation
In Sphinx 9, css_files and script_files contain _CascadingStyleSheet and _JavaScript objects instead of plain strings. Passing these objects to pathto() causes a TypeError because they don't support the `in` operator or string concatenation. Use css_tag() / js_tag() (available since Sphinx 7) to render asset objects, falling back to raw <link>/<script> tags for plain strings (older Sphinx versions). This mirrors the approach used in Sphinx's own basic/layout.html template. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
It would be good to see evidence of this. :-) I'll have a go at replicating the Traits doc build myself locally. |
|
Test run for Traits documentation build here: enthought/traits#1879. The build succeeds modulo some referencing issues that have nothing to do with the theme. |
|
Note: |
|
Before this goes in, we should document the new requirement for Sphinx >= 7.0. |
There was a problem hiding this comment.
Pull request overview
Updates the theme’s asset rendering to be compatible with Sphinx 9, where css_files / script_files may contain asset objects instead of plain strings, avoiding TypeError from passing objects into pathto().
Changes:
- Render JS assets via
js_tag()when a Sphinx asset object is provided; otherwise fall back to<script src="{{ pathto(...) }}">. - Render CSS assets via
css_tag()when a Sphinx asset object is provided; otherwise fall back to<link href="{{ pathto(...) }}">.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| {%- for js in script_files %} | ||
| {%- if js|attr("filename") is not none %} | ||
| {{ js_tag(js) }} | ||
| {%- else %} | ||
| <script type="text/javascript" src="{{ pathto(js, 1) }}"></script> | ||
| {%- endif %} | ||
| {%- endfor %} |
There was a problem hiding this comment.
js|attr("filename") is not none will also be true for plain string entries because attr("filename") typically yields an Undefined value (which is not none). That would route strings into js_tag(js), likely failing and reintroducing the incompatibility. Prefer a type-based check (e.g., test whether js is a string and use pathto only in that case) or explicitly check that the attribute is defined (e.g., js|attr("filename") is defined and not none). Apply the same approach consistently to CSS/JS handling to avoid subtle differences in behavior.
There was a problem hiding this comment.
Hmm. This does seem like a valid point. IIUC, the code is attempting to be backwards compatible with older versions of Sphinx - for those older versions, js is a plain string and so js|attr("filename") will be Undefined (at least according to the docs). Which is not none. If this analysis is correct, we never actually take the fallback path.
@dpinte What does Claude say about this?
There was a problem hiding this comment.
Claude said you and copilot are right. It also inspected the standard upstream themes and verified how the checks were done. It seems they were not checking anything and thus just called js_tag(js). We'll remove those.
There was a problem hiding this comment.
Thanks, @dpinte.
The fallback code was a good idea, though - it saves us from having to worry about pinning a minimum Sphinx version. (Of course, the upstream code doesn't need to worry about this - it's shipped with Sphinx, so it can assume the latest Sphinx bells and whistles.)
I'll update the PR to do the right thing (which is to just remove the is not none check).
The "Sphinx 7" here seems to be a bit of a hallucination. As I understand it, |
…irement
The js|attr("filename") is not none check was always true (Jinja2 Undefined
is not none), so the pathto() fallback was never taken. Use js_tag()
unconditionally for JS assets, matching Sphinx's own basic/layout.html.
Add Sphinx >= 4.5 to install_requires and document the requirement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
No we shouldn't: I misunderstood what the new code is doing - there's a fallback path for plain string objects, which should make the code backwards compatible with earlier versions of Sphinx. |
Ah, no: Claude has removed that fallback path in the latest commit (though it's only removed the fallback for JS files, and left it in for CSS files). I'll make a manual update to get us to the right place. |
|
Fallback path restored in 88c6f4f. The treatment of JS files and CSS files are now consistent with one another. |
|
Bumped the version number in setup.py so that this change is ready for immediate release (see 3f2ea65) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Release 0.7.4 | ||
| ------------- | ||
|
|
||
| Changes | ||
|
|
||
| * Fix Sphinx 9 compatibility for CSS and JS asset rendering. (#25) | ||
|
|
There was a problem hiding this comment.
The new 0.7.4 changelog section is missing a “Release date:” line, while all existing releases in this file include one. To keep the changelog consistent (and avoid ambiguity around whether 0.7.4 is actually released), add a release date or explicitly mark the section as unreleased.
Summary
css_filesandscript_filescontain_CascadingStyleSheetand_JavaScriptobjects instead of plain strings. Passing these topathto()causesTypeError: argument of type '_CascadingStyleSheet' is not iterable.css_tag()/js_tag()(available since Sphinx 7) to render asset objects, falling back to raw<link>/<script>tags for plain strings (older Sphinx). This mirrors Sphinx's ownbasic/layout.htmlapproach.Sphinx>=2.1.0.Test plan
🤖 Generated with Claude Code