Declare additional dependency to sphinx-build in an extension - python-sphinx

TL,DR: From a Sphinx extension, how do I tell sphinx-build to treat an additional file as a dependency? In my immediate use case, this is the extension's source code, but the question could equally apply to some auxiliary file used by the extension.
I'm generating documentation with Sphinx using a custom extension. I'm using sphinx-build to build the documentation. For example, I use this command to generate the HTML (this is the command in the makefile generated by sphinx-quickstart):
sphinx-build -b html -d _build/doctrees . _build/html
Since my custom extension is maintained together with the source of the documentation, I want sphinx-build to treat it as a dependency of the generated HTML (and LaTeX, etc.). So whenever I change my extension's source code, I want sphinx-build to regenerate the output.
How do I tell sphinx-build to treat an additional file as a dependency? That is not mentioned in the toctree, since it isn't part of the source. Logically, this should be something I do from my extension's setup function.
Sample extension (my_extension.py):
from docutils import nodes
from docutils.parsers.rst import Directive
class Foo(Directive):
def run(self):
node = nodes.paragraph(text='Hello world\n')
return [node]
def setup(app):
app.add_directive('foo', Foo)
Sample source (index.rst):
.. toctree::
:maxdepth: 2
.. foo::
Sample conf.py (basically the output of sphinx-quickstart plus my extension):
import sys
import os
sys.path.insert(0, os.path.abspath('.'))
extensions = ['my_extension']
templates_path = ['_templates']
source_suffix = '.rst'
master_doc = 'index'
project = 'Hello directive'
copyright = '2019, Gilles'
author = 'Gilles'
version = '1'
release = '1'
language = None
exclude_patterns = ['_build']
pygments_style = 'sphinx'
todo_include_todos = False
html_theme = 'alabaster'
html_static_path = ['_static']
htmlhelp_basename = 'Hellodirectivedoc'
latex_elements = {
}
latex_documents = [
(master_doc, 'Hellodirective.tex', 'Hello directive Documentation',
'Gilles', 'manual'),
]
man_pages = [
(master_doc, 'hellodirective', 'Hello directive Documentation',
[author], 1)
]
texinfo_documents = [
(master_doc, 'Hellodirective', 'Hello directive Documentation',
author, 'Hellodirective', 'One line description of project.',
'Miscellaneous'),
]
Validation of a solution:
Run make html (or sphinx-build as above).
Modify my_extension.py to replace Hello world by Hello again.
Run make html again.
The generated HTML (_build/html/index.html) must now contain Hello again instead of Hello world.

It looks like the note_dependency method in the build environment API should do what I want. But when should I call it? I tried various events but none seemed to hit the environment object in the right state. What did work was to call it from a directive.
import os
from docutils import nodes
from docutils.parsers.rst import Directive
import sphinx.application
class Foo(Directive):
def run(self):
self.state.document.settings.env.note_dependency(__file__)
node = nodes.paragraph(text='Hello done\n')
return [node]
def setup(app):
app.add_directive('foo', Foo)
If a document contains at least one foo directive, it'll get marked as stale when the extension that introduces this directive changes. This makes sense, although it could get tedious if an extension adds many directives or makes different changes. I don't know if there's a better way.
Inspired by Luc Van Oostenryck's autodoc-C.

As far as I know app.env.note_dependency can be called within the doctree-read to add any file as a dependency to the document currently being read.
So in your use case, I assume this would work:
from typing import Any, Dict
from sphinx.application import Sphinx
import docutils.nodes as nodes
def doctree-read(app: Sphinx, doctree: nodes.document):
app.env.note_dependency(file)
def setup(app: Sphinx):
app.connect("doctree-read", doctree-read)

Related

How does readthedocs generate Sphinx HTML from RST without a conf.py?

I am looking at making changes to an existing project hosted on github and readthedocs. However the generated HTML looks to be built by Sphinx without a conf.py.
$ ls
appendixA.rst chapter11.rst chapter17.rst chapter4.rst html
appendixB.rst chapter12.rst chapter18.rst chapter5.rst images
appendixC.rst chapter13.rst chapter19.rst chapter6.rst index.rst
attribution.rst chapter14.rst chapter2.rst chapter7.rst sandbox
chapter1.rst chapter15.rst chapter20.rst chapter8.rst src
chapter10.rst chapter16.rst chapter3.rst chapter9.rst toc.txt
Note particularly that index.rst exists but conf.py does not. find also shows it is not hiding somewhere else in the project. The generated site on readthedocs works and is consistent with the latest, including some problems seen in the github project, eg Chapter 1 is not indexed properly due to being listed under another name in index.rst.
I am new to Sphinx and readthedocs. In my new local build environment, sphinx doesn't like it at all:
> sphinx-build -b html . html/
Application error:
config directory doesn't contain a conf.py file (.)
That's consistent with the documentation, but not the readthedocs website behaviour. I'm guessing that readthedocs has some fallback behaviour for these cases, probably by generating a simple conf.py from other configuration it holds. However, it makes it hard to reproduce when making changes locally, especially for a project I don't own. If this is the case, I can't find any documentation on this feature. If I am not missing something simple (entirely possible), is there any?
My next step will be to write a new conf.py, and get it to conform to the existing behaviour on a local site. This would be easier if I understood the existing behaviour.
The actual project in question is the Jython book:
https://jython.readthedocs.io/en/latest/
https://github.com/jython/book
Had no luck finding related issues or questions on google, stackoverflow, readthedocs doco or issues. The readthedocs code at https://github.com/rtfd/readthedocs.org/blob/master/readthedocs/projects/models.py seems to have a check for conf.py, too.
Huh, that's interesting that you don't have a conf.py but the docs still built successfully on Date: 2017-10-24T19:18:40.379930Z. I'm just as dumbfounded as you.
Anyway, you can find the conf.py that RTD ends up using under the project's build's raw log file. That might save you some grief. Note that the versions are about 1.5 years old, so you would need to pin versions to try to reproduce it exactly.
cat conf.py
# -*- coding: utf-8 -*-
from recommonmark.parser import CommonMarkParser
extensions = []
templates_path = ['/home/docs/checkouts/readthedocs.org/readthedocs/templates/sphinx', 'templates', '_templates', '.templates']
source_suffix = ['.rst', '.md']
source_parsers = {
'.md': CommonMarkParser,
}
master_doc = 'index'
project = u'jython'
copyright = u'2016'
version = 'latest'
release = 'latest'
exclude_patterns = ['_build']
pygments_style = 'sphinx'
htmlhelp_basename = 'jython'
html_theme = 'sphinx_rtd_theme'
file_insertion_enabled = False
latex_documents = [
('index', 'jython.tex', u'jython Documentation',
u'', 'manual'),
]
###########################################################################
# auto-created readthedocs.org specific configuration #
###########################################################################
#
# The following code was added during an automated build on readthedocs.org
# It is auto created and injected for every build. The result is based on the
# conf.py.tmpl file found in the readthedocs.org codebase:
# https://github.com/rtfd/readthedocs.org/blob/master/readthedocs/doc_builder/templates/doc_builder/conf.py.tmpl
#
import sys
import os.path
from six import string_types
from sphinx import version_info
# Get suffix for proper linking to GitHub
# This is deprecated in Sphinx 1.3+,
# as each page can have its own suffix
if globals().get('source_suffix', False):
if isinstance(source_suffix, string_types):
SUFFIX = source_suffix
else:
SUFFIX = source_suffix[0]
else:
SUFFIX = '.rst'
# Add RTD Static Path. Add to the end because it overwrites previous files.
if not 'html_static_path' in globals():
html_static_path = []
if os.path.exists('_static'):
html_static_path.append('_static')
html_static_path.append('/home/docs/checkouts/readthedocs.org/readthedocs/templates/sphinx/_static')
# Add RTD Theme only if they aren't overriding it already
using_rtd_theme = False
if 'html_theme' in globals():
if html_theme in ['default']:
# Allow people to bail with a hack of having an html_style
if not 'html_style' in globals():
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_style = None
html_theme_options = {}
if 'html_theme_path' in globals():
html_theme_path.append(sphinx_rtd_theme.get_html_theme_path())
else:
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
using_rtd_theme = True
else:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_style = None
html_theme_options = {}
if 'html_theme_path' in globals():
html_theme_path.append(sphinx_rtd_theme.get_html_theme_path())
else:
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
using_rtd_theme = True
if globals().get('websupport2_base_url', False):
websupport2_base_url = 'https://readthedocs.org/websupport'
if 'http' not in settings.MEDIA_URL:
websupport2_static_url = 'https://media.readthedocs.org/static/'
else:
websupport2_static_url = 'https://media.readthedocs.org//static'
#Add project information to the template context.
context = {
'using_theme': using_rtd_theme,
'html_theme': html_theme,
'current_version': "latest",
'MEDIA_URL': "https://media.readthedocs.org/",
'PRODUCTION_DOMAIN': "readthedocs.org",
'versions': [
("latest", "/en/latest/"),
],
'downloads': [
("pdf", "//readthedocs.org/projects/jython/downloads/pdf/latest/"),
("htmlzip", "//readthedocs.org/projects/jython/downloads/htmlzip/latest/"),
("epub", "//readthedocs.org/projects/jython/downloads/epub/latest/"),
],
'subprojects': [
],
'slug': 'jython',
'name': u'jython',
'rtd_language': u'en',
'canonical_url': 'http://jython.readthedocs.io/en/latest/',
'analytics_code': 'None',
'single_version': False,
'conf_py_path': '/./',
'api_host': 'https://readthedocs.org',
'github_user': 'jython',
'github_repo': 'book',
'github_version': 'master',
'display_github': True,
'bitbucket_user': 'None',
'bitbucket_repo': 'None',
'bitbucket_version': 'master',
'display_bitbucket': False,
'READTHEDOCS': True,
'using_theme': (html_theme == "default"),
'new_theme': (html_theme == "sphinx_rtd_theme"),
'source_suffix': SUFFIX,
'user_analytics_code': '',
'global_analytics_code': 'UA-17997319-1',
'commit': 'cf5cf6de',
}
if 'html_context' in globals():
html_context.update(context)
else:
html_context = context
# Add custom RTD extension
if 'extensions' in globals():
extensions.append("readthedocs_ext.readthedocs")
else:
extensions = ["readthedocs_ext.readthedocs"]

Is it possible to reuse hyperlink defined in another file in restructuredtext (or sphinx)

Suppose I have two files a.rst and b.rst in the same folder, and a.rst looks like this
.. _foo: http://stackoverflow.com
`foo`_ is a website
It seems using foo in b.rst is not allowed. Is there a way to define hyperlinks and use them in multiple files?
Followup
I used the extlinks extension as Steve Piercy suggested. Its implementation and docstring can be seen here on github.
In my case, I define wikipedia link in my conf.py
extlinks = {'wiki': ('https://en.wikipedia.org/wiki/%s', '')}
and in the .rst files, use them like
:wiki:`Einstein <Albert_Einstein>`
where Einstein will be displayed as a link to https://en.wikipedia.org/wiki/Albert_Einstein
There are at least four possible solutions.
1. repeat yourself
Put your complete reST in each file. You probably don't want that.
2. combined rst_epilog and substitution
This one is clever. Configure the rst_epilog value, in your conf.py along with a substition with the replace directive:
rst_epilog = """
.. |foo| replace:: foo
.. _foo: http://stackoverflow.com
"""
and reST:
|foo|_ is a website
yields:
<a class="reference external" href="http://stackoverflow.com">foo</a>
3. extlinks
For links to external websites where you want to have a base URL and append path segments or arguments, you can use extlinks in your conf.py:
extensions = [
...
'sphinx.ext.extlinks',
...
]
...
extlinks = {'so': ('https://stackoverflow.com/%s', None)}
Then in your reST:
:so:`questions/49016433`
Yields:
<a class="reference external"
href="https://stackoverflow.com/questions/49016433">
https://stackoverflow.com/questions/49016433
</a>
4. intersphinx
For external websites that are documentation generated by Sphinx, then you can use intersphinx, in your conf.py:
extensions = [
...
'sphinx.ext.intersphinx',
...
]
...
intersphinx_mapping = {
'python': ('https://docs.python.org/3', None),
}
Then in your reST:
:py:mod:`doctest`
Yields:
<a class="reference external"
href="https://docs.python.org/3/library/doctest.html#module-doctest"
title="(in Python v3.6)">
<code class="xref py py-mod docutils literal">
<span class="pre">doctest</span>
</code>
</a>
This might come a bit late but I have found a solution that works very neatly for me and it is not among the answers already given.
In my case, I create a file with all the links used in my project, save it as /include/links.rst, and looking something like:
.. _PEP8: https://www.python.org/dev/peps/pep-0008/
.. _numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html
.. _googledoc: https://google.github.io/styleguide/pyguide.html
Then there are the files a.rst and b.rst looking like:
.. include:: /include/links.rst
File A.rst
##########
Click `here <PEP8_>`_ to see the PEP8 coding style
Alternatively, visit either:
- `Numpy Style <numpydoc_>`_
- `Google Style <googledoc_>`_
and
.. include:: /include/links.rst
File B.rst
##########
You can visit `Python's PEP8 Style Guide <PEP8_>`_
For docstrings, you can use either `Numpy's <numpydoc_>`_ or `Google's <googledoc_>`_
respectively.
The produced output for both cases is:
and
respectively.
Moreover, I would like to emphasize the fact of which I was actually really struggling to achieve, to use different names (displayed text) for the same link at different locations and which I have achieved with the double _, one inside the <..._> and another outside.
This is another solution: it is a bit hacky and a little bit different respect to the officially supported way to share external links.
First complete the Setup then:
in conf.py add the commonlinks entry in extensions
in conf.py configure the map of common links:
For example:
extensions = [
...,
'sphinx.ext.commonlinks'
]
commonlinks = {
'issues': 'https://github.com/sphinx-doc/sphinx/issues',
'github': 'https://github.com'
}
Then in .rst files you can do these:
The :github:`_url_` url is aliased to :github:`GitHub` and also to :github:`this`
Setup
All that is needed is to copy into sphinx/ext directory the file commonlinks.py:
# -*- coding: utf-8 -*-
"""
sphinx.ext.commonlinks
~~~~~~~~~~~~~~~~~~~~~~
Extension to save typing and prevent hard-coding of common URLs in the reST
files.
This adds a new config value called ``commonlinks`` that is created like this::
commonlinks = {'exmpl': 'http://example.com/mypage.html', ...}
Now you can use e.g. :exmpl:`foo` in your documents. This will create a
link to ``http://example.com/mypage.html``. The link caption depends on the
role content:
- If it is ``_url_``, the caption will be the full URL.
- If it is a string, the caption will be the role content.
"""
from six import iteritems
from docutils import nodes, utils
import sphinx
from sphinx.util.nodes import split_explicit_title
def make_link_role(base_url):
def role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
text = utils.unescape(text)
if text == '_url_':
title = base_url
else:
title = text
pnode = nodes.reference(title, title, internal=False, refuri=base_url)
return [pnode], []
return role
def setup_link_roles(app):
for name, base_url in iteritems(app.config.commonlinks):
app.add_role(name, make_link_role(base_url))
def setup(app):
app.add_config_value('commonlinks', {}, 'env')
app.connect('builder-inited', setup_link_roles)
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
To locate the sphinx installation directory one way is:
$ python 3
> import sphinx
> sphinx
<module 'sphinx' from '/usr/local/lib/python3.5/dist-packages/sphinx/__init__.py'>
then:
% cp commonlinks.py /usr/local/lib/python3.5/dist-packages/sphinx/ext

How to include pygments styles in a sphinx project?

Sphinx can define themes as well as a pygments style to use.
I couldn't however - find a good way for a Sphinx project to define a custom style (color scheme) for pygments to use.
From the docs:
To make the style usable for Pygments, you must
either register it as a plugin (see the plugin docs)
or drop it into the styles subpackage of your Pygments distribution one style class per style, where the file name is the style name and the class name is StylenameClass.
From what I can tell the first option is what I'm after since it should be possible to extend pygments dynamically. Although from checking the link I'm not sure how this would be done (no examples of how to use the plugin system).
The second example involves copying files into pygments which isn't practical especially since the path may not be writable by the user.
I did manage to hack in a style, although it's not a nice solution:
including for completeness
# Sphinx "conf.py"
# Master toctree document
master_doc = 'contents'
# BEGIN MONKEY-PATCH
from pygments.style import Style
from pygments.token import Text, Other, Comment, Whitespace
class MyFancyStyle(Style):
background_color = "#1e1e27"
default_style = ""
styles = {
Text: "#cfbfad",
Other: "#cfbfad",
Whitespace: "#434357",
Comment: "#cd8b00",
Comment.Preproc: "#409090",
Comment.PreprocFile: "bg:#404040 #ffcd8b",
Comment.Special: "#808bed",
# ... snip (just more colors, you get the idea) ...
}
def pygments_monkeypatch_style(mod_name, cls):
import sys
import pygments.styles
cls_name = cls.__name__
mod = type(__import__("os"))(mod_name)
setattr(mod, cls_name, cls)
setattr(pygments.styles, mod_name, mod)
sys.modules["pygments.styles." + mod_name] = mod
from pygments.styles import STYLE_MAP
STYLE_MAP[mod_name] = mod_name + "::" + cls_name
pygments_monkeypatch_style("my_fancy_style", MyFancyStyle)
pygments_style = "my_fancy_style"
# END MONKEY-PATCH
In your conf.py specify the Pygments style you want to use. From the Sphinx documentation:
pygments_style
The style name to use for Pygments highlighting of source code. If not set, either the theme’s default style or 'sphinx' is selected for HTML output.
Available names can be retrieved by:
>>> from pygments.styles import get_all_styles
>>> styles = list(get_all_styles())
An online preview of some Sphinx theme and Pygments style combinations is available.
If out-of-the-box Pygments styles are not to your liking, then you can create a custom Pygments style.
This is how I set it up:
Folder Structure:
docs
├── source
│ ├── conf.py <--
│ ├── _pygments
│ │ ├── style.py <--
│ ├── _static
│ ├── ...
conf.py
(at the very top)
import sys, os
sys.path.append(os.path.abspath("./_pygments"))
pygments_style = 'style.MonokaiStyle'
...
style.py
from pygments.style import Style
from pygments.token import Keyword, Name, Comment, String, Error, Text, \
Number, Operator, Generic, Whitespace, Punctuation, Other, Literal
class MonokaiStyle(Style):
"""
This style mimics the Monokai color scheme.
"""
background_color = "#272822"
highlight_color = "#49483e"
styles = {
# No corresponding class for the following:
Text: "#f8f8f2", # class: ''
Whitespace: "", # class: 'w'
Error: "#960050 bg:#1e0010", # class: 'err'
Other: "", # class 'x'
...
}
You can choose a predefined style here (as I did) and put the corresponding *.py file from the official pygment repo into the _pygment folder. Or you can define your own style, renaming the class to your liking (don't forget to adapt the import clause in conf.py to the new names)
EDIT: This is an even better resource for style lookup.
I had a similar need, though what I really wanted was to slightly change an existing style (called the base style below). I was able to extent the code in the question for my needs. I post it here for anyone else coming across this problem.
# Sphinx "conf.py"
# Syntax highlighting of code blocks
import pygments.styles, pygments.token
def monkeypatch_pygments(name, base_name='default', attrs={}):
import importlib, sys
base_module = importlib.import_module('.'.join(['pygments', 'styles', base_name]))
def name_to_class_name(name):
return name.capitalize() + 'Style'
base_class = getattr(base_module, name_to_class_name(base_name))
styles = getattr(base_class, 'styles', {}).copy()
styles.update(attrs.pop('styles', {}))
attrs['styles'] = styles
class_name = name_to_class_name(name)
Style = type(class_name, (base_class,), attrs)
module = type(base_module)(name)
setattr(module, class_name, Style)
setattr(pygments.styles, name, module)
pygments.styles.STYLE_MAP[name] = f'{name}::{class_name}'
sys.modules['.'.join(['pygments', 'styles', name])] = module
pygments_style = 'custom' # Arbitrary name of new style
monkeypatch_pygments(
pygments_style,
'friendly', # Name of base style to use
{
# Changes to base style
'background_color': '#f6f6f6',
'styles': {
pygments.token.Comment: 'italic #688F98',
pygments.token.Name.Variable: '#d27a0a',
},
},
)
In the above example, the friendly style is used as the base style. Its 'background_color' and a few items within the 'styles' dictionary are redefined. Note that items not specified in 'styles' will be taken from the base style. The base style itself is not changed.
The "proper" way to include a pygments style as a plugin is to make a new package and install it via setuptools.
Use the usual process to create a setup.cfg (https://setuptools.readthedocs.io/en/latest/userguide/declarative_config.html)
Add the following section to it:
[options.entry_points]
pygments.styles =
my_fancy_style = mypackage.mystyle:MyFancyStyle
Create your style as class MyFancyStyle in mypackage/mystyle.py
Install the package: pip install -e .
Profit! You can now refer use "my_fancy_style" anywhere a Pygments style is expected. Phew.
I adopt the solution of Glades and it works well, except in the case that the style-python package is installed (style-1.1.0 in my case).
It lead to the ERROR (sorry for the part of french in the ouput) :
Une exception a été levée :
File "/home/bp/.local/lib/python3.8/site-packages/style/styled_string_builder.py", line 44, in __getattr__
raise AttributeError('%r object has no attribute %r' % (self.__class__.__name__, attr))
AttributeError: '_StyledStringBuilder' object has no attribute 'MonokaiStyle'
Only solution I find is just to uninstall this package named style :
$ pip uninstall style

Documenting Python coroutines with Sphinx autodoc

I'm starting to document my first asyncio-based project with Sphinx. I noticed some projects have this "coroutine" prefix before some methods and I'd like to do the same in my project's documentation, but I can't figure out how.
For example, aiohttp's HTTP client reference shows this:
class aiohttp.ClientSession(...):
coroutine request(...)
That project seems to use a coroutinemethod directive to achieve this, but I document all my functions and classes inline using docstrings and this directive only works if you write the docs in a reStructuredText document.
Does anybody know how to achieve this result with autodoc?
Edit: I will also accept answers that explain how to make a Sphinx extension to do this if Sphinx doesn't support it. Bonus points if someone can point my to some kind of way that automatically detects whether the method is a coroutine or not using inspect.iscoroutinefunction().
Edit: I'm looking at the "pyspecific" Sphinx extension in the CPython project for inspiration. However, I need to change autodoc's behavior, not add new directives. After a bit of research, it looks like autodoc has an autodoc-process-signature event which can be used to customize the function signature, but it doesn't seem to have the object used by the "pyspecific" extension.
This functionality is not already built-in to Sphinx. However, pull request #1826 adds support for generators, coroutine functions, coroutine methods with built-in detection of coroutines in autodoc's autofunction and automethod directives.
Here is a patch that I applied locally to enable this in Sphinx 1.4 (requires disabling sphinx-build's -W "turn warnings into errors" option):
# Recipe stolen from open PR (https://github.com/sphinx-doc/sphinx/pull/1826).
from inspect import iscoroutinefunction
from sphinx import addnodes
from sphinx.domains.python import (
PyClassmember,
PyModulelevel,
)
from sphinx.ext.autodoc import FunctionDocumenter as _FunctionDocumenter
from sphinx.ext.autodoc import MethodDocumenter as _MethodDocumenter
class PyCoroutineMixin(object):
"""Helper for coroutine-related Sphinx custom directives."""
def handle_signature(self, sig, signode):
ret = super(PyCoroutineMixin, self).handle_signature(sig, signode)
signode.insert(0, addnodes.desc_annotation('coroutine ', 'coroutine '))
return ret
class PyCoroutineFunction(PyCoroutineMixin, PyModulelevel):
"""Sphinx directive for coroutine functions."""
def run(self):
self.name = 'py:function'
return PyModulelevel.run(self)
class PyCoroutineMethod(PyCoroutineMixin, PyClassmember):
"""Sphinx directive for coroutine methods."""
def run(self):
self.name = 'py:method'
return PyClassmember.run(self)
class FunctionDocumenter(_FunctionDocumenter):
"""Automatically detect coroutine functions."""
def import_object(self):
ret = _FunctionDocumenter.import_object(self)
if not ret:
return ret
obj = self.parent.__dict__.get(self.object_name)
if iscoroutinefunction(obj):
self.directivetype = 'coroutine'
self.member_order = _FunctionDocumenter.member_order + 2
return ret
class MethodDocumenter(_MethodDocumenter):
"""Automatically detect coroutine methods."""
def import_object(self):
ret = _MethodDocumenter.import_object(self)
if not ret:
return ret
obj = self.parent.__dict__.get(self.object_name)
if iscoroutinefunction(obj):
self.directivetype = 'coroutinemethod'
self.member_order = _MethodDocumenter.member_order + 2
return ret
def setup(app):
"""Sphinx extension entry point."""
# Add new directives.
app.add_directive_to_domain('py', 'coroutine', PyCoroutineFunction)
app.add_directive_to_domain('py', 'coroutinemethod', PyCoroutineMethod)
# Customize annotations for anything that looks like a coroutine.
app.add_autodocumenter(FunctionDocumenter)
app.add_autodocumenter(MethodDocumenter)
# Return extension meta data.
return {
'version': '1.0',
'parallel_read_safe': True,
}

Pygments style not found

I have created a pygments style, which uses the same colors as xcode, and named it xcode.py:
from pygments.style import Style
from pygments.token import Keyword, Name, Comment, String, Error, \
Number, Operator, Generic
class xcodeStyle(Style):
default_style = ""
styles = {
Text: '#000000',
Comment: '#008426',
String: '#D92823',
Number: '#2F2ECF',
Keyword: '#C22A9C',
Name.Class: '#753EA3'
}
I tried placing it in /Library/Python/2.7/site-packages/pygments/styles but when I list the available styles with
from pygments.styles import get_all_styles
styles = list(get_all_styles())
print styles
my style doesn't get recognized. Any ideas why?
Indeed, it's not quite clear how to add custom pygments style from their official docs. But I've figured it out after a while.
Sphinx has a conf.py parameter https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-pygments_style
Which could be a fully-qualified name of a custom Pygments style class. This is what we should use.
OK, the steps:
Create a python module, e.g. my_fancy_style.py with your style class MyFancyStyle
Put my_fancy_style.py in the same dir where your conf.py is located.
Uncomment/write in conf.py lines, so sphinx will be able to find your class
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
# ...
pygments_style = 'my_fancy_style.MyFancyStyle'
That's it!

Resources