jupyter-book
jupyter-book copied to clipboard
[ENH] Add tag options to _config.yml for conditional content
Add support to specify tags in _config.yml. Requires Jupyter Book processing of the Sphinx object (app) in sphinx_build to manipulate tags, similar to how latex_documents are configured. No support for adding tags in the jupyter book command line.
This addresses issue #1290 (mistakenly refers to "open" directive). Possibly also #1425.
(comment similar to the prior PR #1618 for command line tags)
The background context is that the tags are set, added, and removed during initialization of a Sphinx object. Sphinx achieves this by executing conf.py to call the Tags.add() and Tags.remove() methods. That's why conf.py contains lines like tags.add('cowboy') and tag entries in the confoverrides dict passed to build_sphinx result in warnings when building (e.g., WARNING: unknown config value 'tags_add' in override, ignoring).
Users may add/remove tags in _config.yml like
config : # key-value pairs to directly over-ride the Sphinx configuration
html_theme : sphinx_book_theme
tags_add : cowboy
tags_remove : cowgirl
Changes
config.yaml_to_sphinx() parses the _config.yml and the keys tags_add and tags_remove are removed from the sphinx_config dict and returned in a separate dict. config.get_final_config() handles updating a default with this user-supplied config and also returns this new dict.
cli.main.sphinx() uses this new dict to append the tags.add() and tags.remove() lines when writing conf.py, and sphinx.build_sphinx() uses the new dict to adjust app.tags.tags :
Note that passing the new conf.py and its location confdir to Sphinx in sphinx.build_sphinx() (below) would handle adding and removing tags, but is prevented because of patch_docutils. I don't know why that is there, so it's probably not wise to tinker with it. But I think that would be an alternate entry point.
with patch_docutils(confdir), docutils_namespace():
app = Sphinx(
srcdir=sourcedir,
confdir=confdir,
outdir=outputdir,
doctreedir=doctreedir,
buildername=builder,
confoverrides=sphinx_config,
After initialization, the Spinx object is reconfigured with the new dict created through parsing _config.yml
tags_add = tags_config.get("tags_add", None)
if tags_add:
for tag in tags_add:
app.tags.tags[tag] = True
tags_remove = tags_config.get("tags_remove", None)
if tags_remove:
for tag in tags_remove:
app.tags.tags.pop(tag, None)
Thanks for this PR and all of the explanation - I will try and figure out what's going on here :-) maybe @chrisjsewell also has a moment to look since he's more familiar with the guts of Sphinx's machinery than I am.
One thing that would be helpful is a user-level explanation of this feature in the docs. What are tags and why would somebody want to use them? What's the minimal use-case that this functionality is designed for? Where can a person go to learn more if they really want to dive into this feature? I think motivating the PR with a clear example would be a helpful way to understand the value that this functionality is bringing.
Thanks for the feedback. I'll look through the docs to see where this would fit.
Quick answer here: a typical use is to mark content that is rendered only for certain builders or audiences. For example, a textbook might have additional content in the teacher edition.
The _conf_teacher.yaml uses tags_add like below to include content that is not rendered for students, whose _conf_student.yaml lacks that line.
sphinx:
config : # key-value pairs to directly over-ride the Sphinx configuration
html_theme : sphinx_book_theme
tags_add : teacher # this line only in _conf_teacher.yaml
Command jupyter-book build --config textbook/_conf_teacher.yaml textbook includes content with the teacher tag following the only directive.
```{only} teacher
This is the answer key!
````
Latest commit adds explanation. Similar to toggling and cell tags, so I added it to hiding.md even though it's nested under web and internet features.
Any advice on relocating? I considered placing into content-blocks.md because it's a directive-level block. Also considered mentioning on advanced Sphinx usage but I didn't want to over-do it.
It looks like this PR has been left to languish. @choldgraf @chrisjsewell Any chance we can get something like this, or at least get only support?
See also: https://github.com/executablebooks/jupyter-book/pull/1618 https://github.com/executablebooks/jupyter-book/issues/1425
I'd really value having optional content support. I'm trying to write some generic materials with optional elements , and the ability to have conditional content in generic files would be hugely beneficial, rather than having to create custom files that share 95% of the content, and custom toc files for different set-ups. [@agoose77 @choldgraf ]