Improve developer experience: Write better docs. Stay concise. Never miss a detail.
jsphinx helps you to achieve what's mentioned above.
You could see it as a mix of loosely coupled software components and
guidelines to make things perfect.
Let me ask you a couple of conceptually connected questions:
- Do you write documentation?
- If you do, do you provide code examples along?
- Are you able to test them? Do you want to?
- Do you struggle making examples compact, yet fully functional?
- And do you want to learn how?
What if I tell you that there's an easy, non-intrusive solution? It doesn't reinvent the wheel; just leverages what's already there.
Move on to the demos section to see it in action.
See the list of available demos below. Pick a demo and from within the example
page, click on any See the full example link to see how it works.
- alabaster demo
- furo demo
- pydata-sphinx-theme demo
- sphinx-book-theme demo
- sphinx-bootstrap demo
- sphinx-material demo
- sphinx-immaterial demo
- sphinx-rtd-theme demo
- faker-file documentation
Impressed? Want to know how it works?
For total clarity, see the following tree structure of the docs directory,
located in the project root (a typical location for storing project docs):
├── conf.py
├── examples -> ../examples
│ └── simple
│ ├── snippet_1.py
│ ├── snippet_2.py
│ ├── snippet_3.py
│ └── snippet_4.py
├── example.rst
├── index.rst
└── test_docs.py
- The
conf.pyis the Sphinx configuration file. - The
examplesdirectory, in this case, is sym-linked to anexamplesdirectory located in the project root. - The
snippet_*.pyfiles are simple standalone Python code examples/snippets. - The
example.rstfile is a part of the supposed documentation, containing source code examples. - The
index.rstis the entry-point of the supposed documentation. - The
test_docs.pyis a Python module containing tests (of all code examples/snippets).
Sphinx is a documentation generator. It has many directives, among which
the .. literalinclude::, which allows us to include content of a file
directly into your documentation.
.. literalinclude:: itself has a :lines: option, which allows us to
specify which parts of the code to show. That's what is used to keep the
primary focus on the most important parts of the code, reducing cognitive
load for the reader.
Consider the following code example (fake.py is used for the demo purposes):
Filename: examples/simple/snippet_1.py
# Required imports
from fake import FAKER
# Generate DOCX file
docx_file = FAKER.docx_file()
# Tests
assert docx_file.data["storage"].exists(docx_file)
assert len(docx_file.data["content"]) > 0See the following documentation snippet:
Filename: example.rst
.. literalinclude:: examples/simple/snippet_1.py
:language: python
:lines: 1-5The above mentioned snippet will be rendered as follows:
# Required imports
from fake import FAKER
# Generate DOCX file
docx_file = FAKER.docx_file()However, we also understand the importance of the broader context. For that
the :download: directive is used, which allows us to create a downloadable
link to a file (the same file we already included into the documentation
using .. literalinclude::). By that we ensure that those interested in the
complete code can easily access it.
See the following documentation snippet:
Filename: example.rst
.. container:: jsphinx-download
*See the full example*
:download:`here <examples/simple/snippet_1.py>`The above mentioned snippet will be produce the following HTML:
<p class="jsphinx-download">
<em>See the full example</em>
<a class="reference download internal" href="examples/simple/snippet_1.py">
<span class="pre">here</span>
</a>
</p>See the jsphinx-download demo to see how it's rendered.
This is where jsphinx steps in. Using provided JavaScript,
we hook to the links generated by the :download: directive and instead
of downloading the content, show it inline, right in place.
The .. container:: jsphinx-download directive wraps the download link into
an element with jsphinx-download class so that we can safely hook to all
underlying download links without a risk to cause unwanted behavior for other
places where you might have used :download: directive for other purposes.
Finally, PrismJS syntax highlighter is used to beautify the code and make it look close to the code highlighting of your Sphinx theme of choice.
Just in case you were wondering whether you should use code quality tools (linters, type checkers) on your documentation code snippets, the answer is - yes! Furthermore, if you are worried that your pragma comments might appear in the generated documentation, please, go check the sphinx-no-pragma project.
For clarity, you should nest both .. literalinclude:: and :download:
under .. container:: jsphinx-download container as shown below:
.. container:: jsphinx-download
.. literalinclude:: examples/simple/snippet_1.py
:language: python
:lines: 1-5
*See the full example*
:download:`here <examples/simple/snippet_1.py>`Works similar to .. container:: jsphinx-download directive, except
that it replaces the compact code snippet with a full one.
Consider the following documentation snippet:
Filename: example.rst
.. container:: jsphinx-download-replace
.. literalinclude:: examples/simple/snippet_1.py
:language: python
:lines: 1-5
*Toggle the full example*
:download:`here <examples/simple/snippet_1.py>`See the jsphinx-download-replace demo to see how it's rendered.
Another popular Sphinx directive is the .. code-block::, which enables
us to display code blocks within your documentation.
The .. code-block:: directive itself has a :emphasize-lines: option,
which is particularly useful for highlighting specific lines of code within
the code block. This helps to draw attention to most important parts of the
code and helps the reader to understand the code.
Consider the following documentation snippet (fake.py is used for the demo purposes):
Filename: example.rst
.. container:: jsphinx-toggle-emphasis
.. code-block:: python
:emphasize-lines: 3-5
from fake import FAKER
txt_file = FAKER.txt_file() # Generate a TXT file
pdf_file = FAKER.pdf_file() # Generate a PDF file
png_file = FAKER.png_file() # Generate a PNG fileSee the jsphinx-toggle-emphasis demo to see how it's rendered.
jsphinx will add a link to each .. container:: jsphinx-toggle-emphasis
block for toggling the visibility of non-emphasized elements.
Works similar to .. container:: jsphinx-toggle-emphasis directive, except
that it replaces the compact code snippet with a full one.
Filename: example.rst
.. container:: jsphinx-toggle-emphasis-replace
.. code-block:: python
:emphasize-lines: 3-5
from fake import FAKER
txt_file = FAKER.txt_file() # Generate a TXT file
pdf_file = FAKER.pdf_file() # Generate a PDF file
png_file = FAKER.png_file() # Generate a PNG filePrismJS themes based on Sphinx's aesthetics:
- alabaster (key:
alabaster, alabaster demo) - furo (key:
furo, furo demo) - pydata-sphinx-theme (key:
pydata_sphinx_theme, pydata-sphinx-theme demo) - sphinx-book-theme (key:
sphinx_book_theme, sphinx-book-theme demo) - sphinx-bootstrap-theme (key:
bootstrap, sphinx-bootstrap demo) - sphinx-material (key:
sphinx_material, sphinx-material demo) - sphinx-immaterial (key:
sphinx_immaterial, sphinx-immaterial demo) - sphinx-rtd-theme (key:
sphinx_rtd_theme, sphinx-rtd-theme demo)
To use both the theme and adapter in your HTML:
<!-- CSS for PrismJS Sphinx RTD theme -->
<link href="https://cdn.jsdelivr.net/gh/barseghyanartur/jsphinx/src/css/sphinx_rtd_theme.css"
rel="stylesheet">
<!-- JS for PrismJS Sphinx Adapter -->
<script src="https://cdn.jsdelivr.net/gh/barseghyanartur/jsphinx/src/js/download_adapter.js">
</script>To integrate both into your Sphinx project, add the following in
your conf.py:
Filename: conf.py
# ************************************************************
# ************************** The theme ***********************
# ************************************************************
html_theme = "sphinx_rtd_theme"
# ************************************************************
# ***************** Additional JS/CSS files ******************
# ************************************************************
html_css_files = [
# ...
"https://cdn.jsdelivr.net/gh/barseghyanartur/jsphinx/src/css/sphinx_rtd_theme.css",
# ...
]
html_js_files = [
# ...
"https://cdn.jsdelivr.net/gh/barseghyanartur/jsphinx/src/js/download_adapter.js",
# ...
]A complete configuration example, together with loaded PrismJS and the toolbar with plugins, would look as follows:
Filename: conf.py
prismjs_base = "//cdnjs.cloudflare.com/ajax/libs/prism/1.29.0"
html_css_files = [
f"{prismjs_base}/themes/prism.min.css",
f"{prismjs_base}/plugins/toolbar/prism-toolbar.min.css",
"https://cdn.jsdelivr.net/gh/barseghyanartur/jsphinx/src/css/sphinx_rtd_theme.css",
]
html_js_files = [
f"{prismjs_base}/prism.min.js",
f"{prismjs_base}/plugins/autoloader/prism-autoloader.min.js",
f"{prismjs_base}/plugins/toolbar/prism-toolbar.min.js",
f"{prismjs_base}/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js",
"https://cdn.jsdelivr.net/gh/barseghyanartur/jsphinx/src/js/download_adapter.js",
]You can also use other Sphinx themes, such as alabaster, furo, pydata-sphinx-theme, sphinx-book-theme, sphinx-bootstrap-theme, sphinx-material or sphinx-rtd-theme.
Make sure to specify appropriate value (theme key) in html_theme,
as follows (pick one):
Filename: conf.py
html_theme = "alabaster"
html_theme = "bootstrap"
html_theme = "furo"
html_theme = "pydata_sphinx_theme"
html_theme = "sphinx_book_theme"
html_theme = "sphinx_material"
html_theme = "sphinx_immaterial"
html_theme = "sphinx_rtd_theme"Finally, make sure to specify correct path to the desired theme:
Filename: conf.py
html_css_files = [
# ...
f"https://cdn.jsdelivr.net/gh/barseghyanartur/jsphinx/src/css/{html_theme}.css",
]Only for sphinx-immaterial, you need to add the following:
Filename: conf.py
extensions.append("sphinx_immaterial")All code snippets of this repository can be tested with pytest (using pytest-codeblock plugin) as follows:
pytestThe pytest-codeblock will automatically discover all code blocks in the documentation and run them as tests. This way you can ensure that all your code examples are functional and up-to-date.
Soms of the icons used have been taken from the amazing iconify.design (MIT licensed).
MIT
For security issues contact me at the e-mail given in the Author section.
For overall issues, go to GitHub issues.
Artur Barseghyan artur.barseghyan@gmail.com.