mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '3.x'
This commit is contained in:
commit
c9480f9943
15
CHANGES
15
CHANGES
@ -122,6 +122,7 @@ Features added
|
||||
:event:`html-page-context` event
|
||||
* #6550: html: Allow to use HTML permalink texts via
|
||||
:confval:`html_permalinks_icon`
|
||||
* #1638: html: Add permalink icons to glossary terms
|
||||
* #8649: imgconverter: Skip availability check if builder supports the image
|
||||
type
|
||||
* #8573: napoleon: Allow to change the style of custom sections using
|
||||
@ -130,6 +131,7 @@ Features added
|
||||
references when :confval:`napoleon_preprocess_types` enabled
|
||||
* #6241: mathjax: Include mathjax.js only on the document using equations
|
||||
* #8651: std domain: cross-reference for a rubric having inline item is broken
|
||||
* #7642: std domain: Optimize case-insensitive match of term
|
||||
* #8681: viewcode: Support incremental build
|
||||
* #8132: Add :confval:`project_copyright` as an alias of :confval:`copyright`
|
||||
* #207: Now :confval:`highlight_language` supports multiple languages
|
||||
@ -150,19 +152,26 @@ Bugs fixed
|
||||
* #8652: autodoc: All variable comments in the module are ignored if the module
|
||||
contains invalid type comments
|
||||
* #8693: autodoc: Default values for overloaded functions are rendered as string
|
||||
* #8134: autodoc: crashes when mocked decorator takes arguments
|
||||
* #8306: autosummary: mocked modules are documented as empty page when using
|
||||
:recursive: option
|
||||
* #8618: html: kbd role produces incorrect HTML when compound-key separators (-,
|
||||
+ or ^) are used as keystrokes
|
||||
* #8629: html: A type warning for html_use_opensearch is shown twice
|
||||
* #8714: html: kbd role with "Caps Lock" rendered incorrectly
|
||||
* #8123: html search: fix searching for terms containing + (Requires a custom
|
||||
search language that does not split on +)
|
||||
* #8665: html theme: Could not override globaltoc_maxdepth in theme.conf
|
||||
* #8745: i18n: crashes with KeyError when translation message adds a new auto
|
||||
footnote reference
|
||||
* #4304: linkcheck: Fix race condition that could lead to checking the
|
||||
availability of the same URL twice
|
||||
* #7118: sphinx-quickstart: questionare got Mojibake if libreadline unavailable
|
||||
* #8094: texinfo: image files on the different directory with document are not
|
||||
copied
|
||||
* #8720: viewcode: module pages are generated for epub on incremental build
|
||||
* #8704: viewcode: anchors are generated in incremental build after singlehtml
|
||||
* #8756: viewcode: highlighted code is generated even if not referenced
|
||||
* #8671: :confval:`highlight_options` is not working
|
||||
* #8341: C, fix intersphinx lookup types for names in declarations.
|
||||
* C, C++: in general fix intersphinx and role lookup types.
|
||||
@ -170,8 +179,14 @@ Bugs fixed
|
||||
* #8683: :confval:`html_last_updated_fmt` generates wrong time zone for %Z
|
||||
* #1112: ``download`` role creates duplicated copies when relative path is
|
||||
specified
|
||||
* #7576: LaTeX with French babel and memoir crash: "Illegal parameter number
|
||||
in definition of ``\FNH@prefntext``"
|
||||
* #8214: LaTeX: The :rst:role:`index` role and the glossary generate duplicate
|
||||
entries in the LaTeX index (if both used for same term)
|
||||
* #8735: LaTeX: wrong internal links in pdf to captioned code-blocks when
|
||||
:confval:`numfig` is not True
|
||||
* #8442: LaTeX: some indexed terms are ignored when using xelatex engine
|
||||
(or pdflatex and :confval:`latex_use_xindy` set to True) with memoir class
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
@ -8,4 +8,9 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\hypersetup{bookmarksdepth=1}% pdf bookmarks
|
||||
\addtocontents{toc}{\protect\setcounter{tocdepth}{1}}%
|
||||
|
||||
.. include:: ../CHANGES
|
||||
|
23
doc/conf.py
23
doc/conf.py
@ -58,8 +58,27 @@ latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation',
|
||||
latex_logo = '_static/sphinx.png'
|
||||
latex_elements = {
|
||||
'fontenc': r'\usepackage[LGR,X2,T1]{fontenc}',
|
||||
'passoptionstopackages': '\\PassOptionsToPackage{svgnames}{xcolor}',
|
||||
'preamble': '\\DeclareUnicodeCharacter{229E}{\\ensuremath{\\boxplus}}',
|
||||
'fontpkg': r'''
|
||||
\usepackage[sc]{mathpazo}
|
||||
\usepackage[scaled]{helvet}
|
||||
\usepackage{courier}
|
||||
\substitutefont{LGR}{\rmdefault}{cmr}
|
||||
\substitutefont{LGR}{\sfdefault}{cmss}
|
||||
\substitutefont{LGR}{\ttdefault}{cmtt}
|
||||
\substitutefont{X2}{\rmdefault}{cmr}
|
||||
\substitutefont{X2}{\sfdefault}{cmss}
|
||||
\substitutefont{X2}{\ttdefault}{cmtt}
|
||||
''',
|
||||
'passoptionstopackages': r'''
|
||||
\PassOptionsToPackage{svgnames}{xcolor}
|
||||
\PassOptionsToPackage{bookmarksdepth=3}{hyperref}% depth of pdf bookmarks
|
||||
''',
|
||||
'preamble': r'''
|
||||
\DeclareUnicodeCharacter{229E}{\ensuremath{\boxplus}}
|
||||
\setcounter{tocdepth}{3}% depth of what is kept from toc file
|
||||
\setcounter{secnumdepth}{1}% depth of section numbering
|
||||
''',
|
||||
'fvset': '\\fvset{fontsize=auto}',
|
||||
# fix missing index entry due to RTD doing only once pdflatex after makeindex
|
||||
'printindex': r'''
|
||||
\IfFileExists{\jobname.ind}
|
||||
|
@ -46,14 +46,15 @@ organization. If you wish to include your extension in this organization,
|
||||
simply follow the instructions provided in the `github-administration`__
|
||||
project. This is optional and there are several extensions hosted elsewhere.
|
||||
The `awesome-sphinxdoc`__ project contains a curated list of Sphinx packages,
|
||||
and many packages use the ``Framework :: Sphinx :: Extension`` and
|
||||
``Framework :: Sphinx :: Theme`` `trove classifiers`__ for Sphinx extensions
|
||||
and themes, respectively.
|
||||
and many packages use the `Framework :: Sphinx :: Extension`__ and
|
||||
`Framework :: Sphinx :: Theme`__ trove classifiers for Sphinx extensions and
|
||||
themes, respectively.
|
||||
|
||||
.. __: https://github.com/sphinx-contrib/
|
||||
.. __: https://github.com/sphinx-contrib/github-administration
|
||||
.. __: https://github.com/yoloseem/awesome-sphinxdoc
|
||||
.. __: https://pypi.org/classifiers/
|
||||
.. __: https://pypi.org/search/?c=Framework+%3A%3A+Sphinx+%3A%3A+Extension
|
||||
.. __: https://pypi.org/search/?c=Framework+%3A%3A+Sphinx+%3A%3A+Theme
|
||||
|
||||
Where to put your own extensions?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -18,6 +18,7 @@ module.exports = function(config) {
|
||||
'sphinx/themes/basic/static/underscore.js',
|
||||
'sphinx/themes/basic/static/jquery.js',
|
||||
'sphinx/themes/basic/static/doctools.js',
|
||||
'sphinx/themes/basic/static/searchtools.js',
|
||||
'tests/js/*.js'
|
||||
],
|
||||
|
||||
|
@ -494,31 +494,34 @@ class Sphinx:
|
||||
"""Register a configuration value.
|
||||
|
||||
This is necessary for Sphinx to recognize new values and set default
|
||||
values accordingly. The *name* should be prefixed with the extension
|
||||
name, to avoid clashes. The *default* value can be any Python object.
|
||||
The string value *rebuild* must be one of those values:
|
||||
values accordingly.
|
||||
|
||||
* ``'env'`` if a change in the setting only takes effect when a
|
||||
document is parsed -- this means that the whole environment must be
|
||||
rebuilt.
|
||||
* ``'html'`` if a change in the setting needs a full rebuild of HTML
|
||||
documents.
|
||||
* ``''`` if a change in the setting will not need any special rebuild.
|
||||
|
||||
The *types* value takes a list of types that describes the type of
|
||||
configuration value. For example, ``[str]`` is used to describe a
|
||||
configuration that takes string value.
|
||||
:param name: The name of configuration value. It is recommended to be prefixed
|
||||
with the extension name (ex. ``html_logo``, ``epub_title``)
|
||||
:param default: The default value of the configuration.
|
||||
:param rebuild: The condition of rebuild. It must be one of those values:
|
||||
|
||||
.. versionchanged:: 0.6
|
||||
Changed *rebuild* from a simple boolean (equivalent to ``''`` or
|
||||
``'env'``) to a string. However, booleans are still accepted and
|
||||
converted internally.
|
||||
* ``'env'`` if a change in the setting only takes effect when a
|
||||
document is parsed -- this means that the whole environment must be
|
||||
rebuilt.
|
||||
* ``'html'`` if a change in the setting needs a full rebuild of HTML
|
||||
documents.
|
||||
* ``''`` if a change in the setting will not need any special rebuild.
|
||||
:param types: The type of configuration value. A list of types can be specified. For
|
||||
example, ``[str]`` is used to describe a configuration that takes string
|
||||
value.
|
||||
|
||||
.. versionchanged:: 0.4
|
||||
If the *default* value is a callable, it will be called with the
|
||||
config object as its argument in order to get the default value.
|
||||
This can be used to implement config values whose default depends on
|
||||
other values.
|
||||
|
||||
.. versionchanged:: 0.6
|
||||
Changed *rebuild* from a simple boolean (equivalent to ``''`` or
|
||||
``'env'``) to a string. However, booleans are still accepted and
|
||||
converted internally.
|
||||
"""
|
||||
logger.debug('[app] adding config value: %r',
|
||||
(name, default, rebuild) + ((types,) if types else ()))
|
||||
@ -530,6 +533,8 @@ class Sphinx:
|
||||
"""Register an event called *name*.
|
||||
|
||||
This is needed to be able to emit it.
|
||||
|
||||
:param name: The name of the event
|
||||
"""
|
||||
logger.debug('[app] adding event: %r', name)
|
||||
self.events.add(name)
|
||||
@ -560,6 +565,11 @@ class Sphinx:
|
||||
This is necessary for Docutils internals. It may also be used in the
|
||||
future to validate nodes in the parsed documents.
|
||||
|
||||
:param node: A node class
|
||||
:param kwargs: Visitor functions for each builder (see below)
|
||||
:param override: If true, install the node forcedly even if another node is already
|
||||
installed as the same name
|
||||
|
||||
Node visitor functions for the Sphinx HTML, LaTeX, text and manpage
|
||||
writers can be given as keyword arguments: the keyword should be one or
|
||||
more of ``'html'``, ``'latex'``, ``'text'``, ``'man'``, ``'texinfo'``
|
||||
@ -581,9 +591,6 @@ class Sphinx:
|
||||
Obviously, translators for which you don't specify visitor methods will
|
||||
choke on the node when encountered in a document to translate.
|
||||
|
||||
If *override* is True, the given *node* is forcedly installed even if
|
||||
a node having the same name is already installed.
|
||||
|
||||
.. versionchanged:: 0.5
|
||||
Added the support for keyword arguments giving visit functions.
|
||||
"""
|
||||
@ -603,24 +610,21 @@ class Sphinx:
|
||||
Sphinx numbers the node automatically. And then the users can refer it
|
||||
using :rst:role:`numref`.
|
||||
|
||||
*figtype* is a type of enumerable nodes. Each figtypes have individual
|
||||
numbering sequences. As a system figtypes, ``figure``, ``table`` and
|
||||
``code-block`` are defined. It is able to add custom nodes to these
|
||||
default figtypes. It is also able to define new custom figtype if new
|
||||
figtype is given.
|
||||
|
||||
*title_getter* is a getter function to obtain the title of node. It
|
||||
takes an instance of the enumerable node, and it must return its title
|
||||
as string. The title is used to the default title of references for
|
||||
:rst:role:`ref`. By default, Sphinx searches
|
||||
``docutils.nodes.caption`` or ``docutils.nodes.title`` from the node as
|
||||
a title.
|
||||
|
||||
Other keyword arguments are used for node visitor functions. See the
|
||||
:meth:`.Sphinx.add_node` for details.
|
||||
|
||||
If *override* is True, the given *node* is forcedly installed even if
|
||||
a node having the same name is already installed.
|
||||
:param node: A node class
|
||||
:param figtype: The type of enumerable nodes. Each figtypes have individual numbering
|
||||
sequences. As a system figtypes, ``figure``, ``table`` and
|
||||
``code-block`` are defined. It is able to add custom nodes to these
|
||||
default figtypes. It is also able to define new custom figtype if new
|
||||
figtype is given.
|
||||
:param title_getter: A getter function to obtain the title of node. It takes an
|
||||
instance of the enumerable node, and it must return its title as
|
||||
string. The title is used to the default title of references for
|
||||
:rst:role:`ref`. By default, Sphinx searches
|
||||
``docutils.nodes.caption`` or ``docutils.nodes.title`` from the
|
||||
node as a title.
|
||||
:param kwargs: Visitor functions for each builder (same as :meth:`add_node`)
|
||||
:param override: If true, install the node forcedly even if another node is already
|
||||
installed as the same name
|
||||
|
||||
.. versionadded:: 1.4
|
||||
"""
|
||||
@ -679,7 +683,7 @@ class Sphinx:
|
||||
"""Register a Docutils role.
|
||||
|
||||
:param name: The name of role
|
||||
:param cls: A role function
|
||||
:param role: A role function
|
||||
:param override: If true, install the role forcedly even if another role is already
|
||||
installed as the same name
|
||||
|
||||
@ -720,11 +724,9 @@ class Sphinx:
|
||||
def add_domain(self, domain: "Type[Domain]", override: bool = False) -> None:
|
||||
"""Register a domain.
|
||||
|
||||
Make the given *domain* (which must be a class; more precisely, a
|
||||
subclass of :class:`~sphinx.domains.Domain`) known to Sphinx.
|
||||
|
||||
If *override* is True, the given *domain* is forcedly installed even if
|
||||
a domain having the same name is already installed.
|
||||
:param domain: A domain class
|
||||
:param override: If true, install the domain forcedly even if another domain
|
||||
is already installed as the same name
|
||||
|
||||
.. versionadded:: 1.0
|
||||
.. versionchanged:: 1.8
|
||||
@ -739,8 +741,11 @@ class Sphinx:
|
||||
Like :meth:`add_directive`, but the directive is added to the domain
|
||||
named *domain*.
|
||||
|
||||
If *override* is True, the given *directive* is forcedly installed even if
|
||||
a directive named as *name* is already installed.
|
||||
:param domain: The name of target domain
|
||||
:param name: A name of directive
|
||||
:param cls: A directive class
|
||||
:param override: If true, install the directive forcedly even if another directive
|
||||
is already installed as the same name
|
||||
|
||||
.. versionadded:: 1.0
|
||||
.. versionchanged:: 1.8
|
||||
@ -755,8 +760,11 @@ class Sphinx:
|
||||
Like :meth:`add_role`, but the role is added to the domain named
|
||||
*domain*.
|
||||
|
||||
If *override* is True, the given *role* is forcedly installed even if
|
||||
a role named as *name* is already installed.
|
||||
:param domain: The name of target domain
|
||||
:param name: A name of role
|
||||
:param role: A role function
|
||||
:param override: If true, install the role forcedly even if another role is already
|
||||
installed as the same name
|
||||
|
||||
.. versionadded:: 1.0
|
||||
.. versionchanged:: 1.8
|
||||
@ -768,11 +776,12 @@ class Sphinx:
|
||||
) -> None:
|
||||
"""Register a custom index for a domain.
|
||||
|
||||
Add a custom *index* class to the domain named *domain*. *index* must
|
||||
be a subclass of :class:`~sphinx.domains.Index`.
|
||||
Add a custom *index* class to the domain named *domain*.
|
||||
|
||||
If *override* is True, the given *index* is forcedly installed even if
|
||||
an index having the same name is already installed.
|
||||
:param domain: The name of target domain
|
||||
:param index: A index class
|
||||
:param override: If true, install the index forcedly even if another index is
|
||||
already installed as the same name
|
||||
|
||||
.. versionadded:: 1.0
|
||||
.. versionchanged:: 1.8
|
||||
@ -893,6 +902,8 @@ class Sphinx:
|
||||
the list of transforms that are applied after Sphinx parses a reST
|
||||
document.
|
||||
|
||||
:param transform: A transform class
|
||||
|
||||
.. list-table:: priority range categories for Sphinx transforms
|
||||
:widths: 20,80
|
||||
|
||||
@ -925,6 +936,8 @@ class Sphinx:
|
||||
Add the standard docutils :class:`Transform` subclass *transform* to
|
||||
the list of transforms that are applied before Sphinx writes a
|
||||
document.
|
||||
|
||||
:param transform: A transform class
|
||||
"""
|
||||
self.registry.add_post_transform(transform)
|
||||
|
||||
@ -1196,9 +1209,10 @@ class Sphinx:
|
||||
def add_message_catalog(self, catalog: str, locale_dir: str) -> None:
|
||||
"""Register a message catalog.
|
||||
|
||||
The *catalog* is a name of catalog, and *locale_dir* is a base path
|
||||
of message catalog. For more details, see
|
||||
:func:`sphinx.locale.get_translation()`.
|
||||
:param catalog: A name of catalog
|
||||
:param locale_dir: The base path of message catalog
|
||||
|
||||
For more details, see :func:`sphinx.locale.get_translation()`.
|
||||
|
||||
.. versionadded:: 1.8
|
||||
"""
|
||||
@ -1209,7 +1223,7 @@ class Sphinx:
|
||||
def is_parallel_allowed(self, typ: str) -> bool:
|
||||
"""Check parallel processing is allowed or not.
|
||||
|
||||
``typ`` is a type of processing; ``'read'`` or ``'write'``.
|
||||
:param typ: A type of processing; ``'read'`` or ``'write'``.
|
||||
"""
|
||||
if typ == 'read':
|
||||
attrname = 'parallel_read_safe'
|
||||
|
@ -118,10 +118,6 @@ class CheckExternalLinksBuilder(DummyBuilder):
|
||||
self._redirected = {} # type: Dict[str, Tuple[str, int]]
|
||||
# set a timeout for non-responding servers
|
||||
socket.setdefaulttimeout(5.0)
|
||||
# create output file
|
||||
open(path.join(self.outdir, 'output.txt'), 'w').close()
|
||||
# create JSON output file
|
||||
open(path.join(self.outdir, 'output.json'), 'w').close()
|
||||
|
||||
# create queues and worker threads
|
||||
self.rate_limits = {} # type: Dict[str, RateLimit]
|
||||
@ -435,26 +431,25 @@ class CheckExternalLinksBuilder(DummyBuilder):
|
||||
|
||||
def write_entry(self, what: str, docname: str, filename: str, line: int,
|
||||
uri: str) -> None:
|
||||
with open(path.join(self.outdir, 'output.txt'), 'a') as output:
|
||||
output.write("%s:%s: [%s] %s\n" % (filename, line, what, uri))
|
||||
self.txt_outfile.write("%s:%s: [%s] %s\n" % (filename, line, what, uri))
|
||||
|
||||
def write_linkstat(self, data: dict) -> None:
|
||||
with open(path.join(self.outdir, 'output.json'), 'a') as output:
|
||||
output.write(json.dumps(data))
|
||||
output.write('\n')
|
||||
self.json_outfile.write(json.dumps(data))
|
||||
self.json_outfile.write('\n')
|
||||
|
||||
def finish(self) -> None:
|
||||
logger.info('')
|
||||
n = 0
|
||||
|
||||
for hyperlink in self.hyperlinks.values():
|
||||
self.wqueue.put(hyperlink, False)
|
||||
n += 1
|
||||
|
||||
total_links = len(self.hyperlinks)
|
||||
done = 0
|
||||
while done < n:
|
||||
self.process_result(self.rqueue.get())
|
||||
done += 1
|
||||
with open(path.join(self.outdir, 'output.txt'), 'w') as self.txt_outfile,\
|
||||
open(path.join(self.outdir, 'output.json'), 'w') as self.json_outfile:
|
||||
while done < total_links:
|
||||
self.process_result(self.rqueue.get())
|
||||
done += 1
|
||||
|
||||
if self._broken:
|
||||
self.app.statuscode = 1
|
||||
|
@ -27,6 +27,7 @@ try:
|
||||
readline.parse_and_bind("tab: complete")
|
||||
USE_LIBEDIT = False
|
||||
except ImportError:
|
||||
readline = None
|
||||
USE_LIBEDIT = False
|
||||
|
||||
from docutils.utils import column_width
|
||||
@ -139,8 +140,11 @@ def do_prompt(text: str, default: str = None, validator: Callable[[str], Any] =
|
||||
# sequence (see #5335). To avoid the problem, all prompts are not colored
|
||||
# on libedit.
|
||||
pass
|
||||
else:
|
||||
elif readline:
|
||||
# pass input_mode=True if readline available
|
||||
prompt = colorize(COLOR_QUESTION, prompt, input_mode=True)
|
||||
else:
|
||||
prompt = colorize(COLOR_QUESTION, prompt, input_mode=False)
|
||||
x = term_input(prompt).strip()
|
||||
if default and not x:
|
||||
x = default
|
||||
|
@ -308,7 +308,7 @@ def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index
|
||||
document.note_explicit_target(term)
|
||||
|
||||
std = cast(StandardDomain, env.get_domain('std'))
|
||||
std.note_object('term', termtext, node_id, location=term)
|
||||
std._note_term(termtext, node_id, location=term)
|
||||
|
||||
# add an index entry too
|
||||
indexnode = addnodes.index()
|
||||
@ -679,6 +679,20 @@ class StandardDomain(Domain):
|
||||
RemovedInSphinx50Warning, stacklevel=2)
|
||||
self.objects[objtype, name] = (docname, labelid)
|
||||
|
||||
@property
|
||||
def _terms(self) -> Dict[str, Tuple[str, str]]:
|
||||
""".. note:: Will be removed soon. internal use only."""
|
||||
return self.data.setdefault('terms', {}) # (name) -> docname, labelid
|
||||
|
||||
def _note_term(self, term: str, labelid: str, location: Any = None) -> None:
|
||||
"""Note a term for cross reference.
|
||||
|
||||
.. note:: Will be removed soon. internal use only.
|
||||
"""
|
||||
self.note_object('term', term, labelid, location)
|
||||
|
||||
self._terms[term.lower()] = (self.env.docname, labelid)
|
||||
|
||||
@property
|
||||
def progoptions(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
|
||||
return self.data.setdefault('progoptions', {}) # (program, name) -> docname, labelid
|
||||
@ -699,6 +713,9 @@ class StandardDomain(Domain):
|
||||
for key, (fn, _l) in list(self.objects.items()):
|
||||
if fn == docname:
|
||||
del self.objects[key]
|
||||
for key, (fn, _l) in list(self._terms.items()):
|
||||
if fn == docname:
|
||||
del self._terms[key]
|
||||
for key, (fn, _l, _l) in list(self.labels.items()):
|
||||
if fn == docname:
|
||||
del self.labels[key]
|
||||
@ -714,6 +731,9 @@ class StandardDomain(Domain):
|
||||
for key, data in otherdata['objects'].items():
|
||||
if data[0] in docnames:
|
||||
self.objects[key] = data
|
||||
for key, data in otherdata['terms'].items():
|
||||
if data[0] in docnames:
|
||||
self._terms[key] = data
|
||||
for key, data in otherdata['labels'].items():
|
||||
if data[0] in docnames:
|
||||
self.labels[key] = data
|
||||
@ -947,19 +967,12 @@ class StandardDomain(Domain):
|
||||
if result:
|
||||
return result
|
||||
else:
|
||||
for objtype, term in self.objects:
|
||||
if objtype == 'term' and term.lower() == target.lower():
|
||||
docname, labelid = self.objects[objtype, term]
|
||||
logger.warning(__('term %s not found in case sensitive match.'
|
||||
'made a reference to %s instead.'),
|
||||
target, term, location=node, type='ref', subtype='term')
|
||||
break
|
||||
# fallback to case insentive match
|
||||
if target.lower() in self._terms:
|
||||
docname, labelid = self._terms[target.lower()]
|
||||
return make_refnode(builder, fromdocname, docname, labelid, contnode)
|
||||
else:
|
||||
docname, labelid = '', ''
|
||||
if not docname:
|
||||
return None
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
|
||||
def _resolve_obj_xref(self, env: "BuildEnvironment", fromdocname: str,
|
||||
builder: "Builder", typ: str, target: str,
|
||||
@ -1115,7 +1128,7 @@ def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'env_version': 1,
|
||||
'env_version': 2,
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ from sphinx.deprecation import RemovedInSphinx50Warning, RemovedInSphinx60Warnin
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.ext.autodoc.importer import (get_class_members, get_object_members, import_module,
|
||||
import_object)
|
||||
from sphinx.ext.autodoc.mock import ismock, mock
|
||||
from sphinx.ext.autodoc.mock import ismock, mock, undecorate
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
||||
from sphinx.util import inspect, logging
|
||||
@ -418,6 +418,8 @@ class Documenter:
|
||||
attrgetter=self.get_attr,
|
||||
warningiserror=self.config.autodoc_warningiserror)
|
||||
self.module, self.parent, self.object_name, self.object = ret
|
||||
if ismock(self.object):
|
||||
self.object = undecorate(self.object)
|
||||
return True
|
||||
except ImportError as exc:
|
||||
if raiseerror:
|
||||
@ -1046,6 +1048,8 @@ class ModuleDocumenter(Documenter):
|
||||
for name in dir(self.object):
|
||||
try:
|
||||
value = safe_getattr(self.object, name, None)
|
||||
if ismock(value):
|
||||
value = undecorate(value)
|
||||
docstring = attr_docs.get(('', name), [])
|
||||
members[name] = ObjectMember(name, value, docstring="\n".join(docstring))
|
||||
except AttributeError:
|
||||
|
@ -14,6 +14,7 @@ import warnings
|
||||
from typing import Any, Callable, Dict, List, NamedTuple, Optional, Tuple
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning
|
||||
from sphinx.ext.autodoc.mock import ismock, undecorate
|
||||
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.inspect import (getannotations, getmro, getslots, isclass, isenumclass,
|
||||
@ -273,6 +274,9 @@ def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable
|
||||
for name in dir(subject):
|
||||
try:
|
||||
value = attrgetter(subject, name)
|
||||
if ismock(value):
|
||||
value = undecorate(value)
|
||||
|
||||
unmangled = unmangle(subject, name)
|
||||
if unmangled and unmangled not in members:
|
||||
if name in obj_dict:
|
||||
|
@ -13,7 +13,7 @@ import os
|
||||
import sys
|
||||
from importlib.abc import Loader, MetaPathFinder
|
||||
from importlib.machinery import ModuleSpec
|
||||
from types import FunctionType, MethodType, ModuleType
|
||||
from types import ModuleType
|
||||
from typing import Any, Generator, Iterator, List, Optional, Sequence, Tuple, Union
|
||||
|
||||
from sphinx.util import logging
|
||||
@ -27,6 +27,7 @@ class _MockObject:
|
||||
|
||||
__display_name__ = '_MockObject'
|
||||
__sphinx_mock__ = True
|
||||
__sphinx_decorator_args__ = () # type: Tuple[Any, ...]
|
||||
|
||||
def __new__(cls, *args: Any, **kwargs: Any) -> Any:
|
||||
if len(args) == 3 and isinstance(args[1], tuple):
|
||||
@ -60,18 +61,19 @@ class _MockObject:
|
||||
return _make_subclass(key, self.__display_name__, self.__class__)()
|
||||
|
||||
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
||||
if args and type(args[0]) in [type, FunctionType, MethodType]:
|
||||
# Appears to be a decorator, pass through unchanged
|
||||
return args[0]
|
||||
return self
|
||||
call = self.__class__()
|
||||
call.__sphinx_decorator_args__ = args
|
||||
return call
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.__display_name__
|
||||
|
||||
|
||||
def _make_subclass(name: str, module: str, superclass: Any = _MockObject,
|
||||
attributes: Any = None) -> Any:
|
||||
attrs = {'__module__': module, '__display_name__': module + '.' + name}
|
||||
attributes: Any = None, decorator_args: Tuple = ()) -> Any:
|
||||
attrs = {'__module__': module,
|
||||
'__display_name__': module + '.' + name,
|
||||
'__sphinx_decorator_args__': decorator_args}
|
||||
attrs.update(attributes or {})
|
||||
|
||||
return type(name, (superclass,), attrs)
|
||||
@ -172,3 +174,14 @@ def ismock(subject: Any) -> bool:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def undecorate(subject: _MockObject) -> Any:
|
||||
"""Unwrap mock if *subject* is decorated by mocked object.
|
||||
|
||||
If not decorated, returns given *subject* itself.
|
||||
"""
|
||||
if ismock(subject) and subject.__sphinx_decorator_args__:
|
||||
return subject.__sphinx_decorator_args__[0]
|
||||
else:
|
||||
return subject
|
||||
|
@ -149,6 +149,18 @@ def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str],
|
||||
env._viewcode_modules.update(other._viewcode_modules) # type: ignore
|
||||
|
||||
|
||||
def env_purge_doc(app: Sphinx, env: BuildEnvironment, docname: str) -> None:
|
||||
modules = getattr(env, '_viewcode_modules', {})
|
||||
|
||||
for modname, (code, tags, used, refname) in list(modules.items()):
|
||||
for fullname in list(used):
|
||||
if used[fullname] == docname:
|
||||
used.pop(fullname)
|
||||
|
||||
if len(used) == 0:
|
||||
modules.pop(modname)
|
||||
|
||||
|
||||
class ViewcodeAnchorTransform(SphinxPostTransform):
|
||||
"""Convert or remove viewcode_anchor nodes depends on builder."""
|
||||
default_priority = 100
|
||||
@ -323,6 +335,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_config_value('viewcode_follow_imported_members', True, False)
|
||||
app.connect('doctree-read', doctree_read)
|
||||
app.connect('env-merge-info', env_merge_info)
|
||||
app.connect('env-purge-doc', env_purge_doc)
|
||||
app.connect('html-collect-pages', collect_pages)
|
||||
app.connect('missing-reference', missing_reference)
|
||||
# app.add_config_value('viewcode_include_modules', [], 'env')
|
||||
|
@ -20,6 +20,9 @@
|
||||
%% turn off hyperref patch of \index as sphinx.xdy xindy module takes care of
|
||||
%% suitable \hyperpage mark-up, working around hyperref-xindy incompatibility
|
||||
\PassOptionsToPackage{hyperindex=false}{hyperref}
|
||||
%% memoir class requires extra handling
|
||||
\makeatletter\@ifclassloaded{memoir}
|
||||
{\ifdefined\memhyperindexfalse\memhyperindexfalse\fi}{}\makeatother
|
||||
<% endif -%>
|
||||
<%= passoptionstopackages %>
|
||||
\PassOptionsToPackage{warn}{textcomp}
|
||||
|
@ -1,9 +1,9 @@
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesPackage{footnotehyper-sphinx}%
|
||||
[2017/10/27 v1.7 hyperref aware footnote.sty for sphinx (JFB)]
|
||||
[2021/01/26 v1.1b hyperref aware footnote.sty for sphinx (JFB)]
|
||||
%%
|
||||
%% Package: footnotehyper-sphinx
|
||||
%% Version: based on footnotehyper.sty 2017/03/07 v1.0
|
||||
%% Version: based on footnotehyper.sty 2021/01/26 v1.1b
|
||||
%% as available at https://www.ctan.org/pkg/footnotehyper
|
||||
%% License: the one applying to Sphinx
|
||||
%%
|
||||
@ -16,7 +16,7 @@
|
||||
%% 3. use of \sphinxunactivateextrasandspace from sphinx.sty,
|
||||
%% 4. macro definition \sphinxfootnotemark,
|
||||
%% 5. macro definition \sphinxlongtablepatch
|
||||
%% 6. replaced an \undefined by \@undefined
|
||||
%% 6. replaced some \undefined by \@undefined
|
||||
\DeclareOption*{\PackageWarning{footnotehyper-sphinx}{Option `\CurrentOption' is unknown}}%
|
||||
\ProcessOptions\relax
|
||||
\newbox\FNH@notes
|
||||
@ -206,9 +206,20 @@
|
||||
\FNH@@@1.2!3?4,\FNH@@@\relax
|
||||
}%
|
||||
\long\def\FNH@check@a #11.2!3?4,#2\FNH@@@#3{%
|
||||
\ifx\relax#3\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
|
||||
\FNH@bad@makefntext@alert
|
||||
{\def\FNH@prefntext{#1}\def\FNH@postfntext{#2}\FNH@check@b}%
|
||||
\ifx\relax#3\FNH@bad@makefntext@alert
|
||||
\else
|
||||
\edef\FNH@restore@{\catcode`\noexpand\@\the\catcode`\@\relax}%
|
||||
\makeatletter
|
||||
\ifx\@makefntextFB\@undefined
|
||||
\expandafter\@gobble\else\expandafter\@firstofone\fi
|
||||
{\@ifclassloaded{memoir}%
|
||||
{\ifFBFrenchFootnotes\expandafter\@gobble\fi}%
|
||||
{}}%
|
||||
\@secondoftwo
|
||||
\scantokens{\def\FNH@prefntext{#1}\def\FNH@postfntext{#2}}%
|
||||
\FNH@restore@
|
||||
\expandafter\FNH@check@b
|
||||
\fi
|
||||
}%
|
||||
\def\FNH@check@b #1\relax{%
|
||||
\expandafter\expandafter\expandafter\FNH@check@c
|
||||
|
@ -1859,8 +1859,8 @@
|
||||
\def\sphinxstyleindexextra #1{ (\emph{#1})}
|
||||
\def\sphinxstyleindexpageref #1{, \pageref{#1}}
|
||||
\def\sphinxstyleindexpagemain#1{\textbf{#1}}
|
||||
\protected\def\spxentry#1{#1}% will get \let to \sphinxstyleindexentry in index
|
||||
\protected\def\spxextra#1{#1}% will get \let to \sphinxstyleindexextra in index
|
||||
\def\spxentry{\@backslashchar spxentry}% let to \sphinxstyleindexentry in index
|
||||
\def\spxextra{\@backslashchar spxextra}% let to \sphinxstyleindexextra in index
|
||||
\def\sphinxstyleindexlettergroup #1%
|
||||
{{\Large\sffamily#1}\nopagebreak\vspace{1mm}}
|
||||
\def\sphinxstyleindexlettergroupDefault #1%
|
||||
|
@ -29,9 +29,14 @@ if (!window.console || !console.firebug) {
|
||||
|
||||
/**
|
||||
* small helper function to urldecode strings
|
||||
*
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
|
||||
*/
|
||||
jQuery.urldecode = function(x) {
|
||||
return decodeURIComponent(x).replace(/\+/g, ' ');
|
||||
if (!x) {
|
||||
return x
|
||||
}
|
||||
return decodeURIComponent(x.replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -379,6 +379,13 @@ var Search = {
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
|
||||
*/
|
||||
escapeRegExp : function(string) {
|
||||
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
},
|
||||
|
||||
/**
|
||||
* search for full-text terms in the index
|
||||
*/
|
||||
@ -402,13 +409,14 @@ var Search = {
|
||||
];
|
||||
// add support for partial matches
|
||||
if (word.length > 2) {
|
||||
var word_regex = this.escapeRegExp(word);
|
||||
for (var w in terms) {
|
||||
if (w.match(word) && !terms[word]) {
|
||||
if (w.match(word_regex) && !terms[word]) {
|
||||
_o.push({files: terms[w], score: Scorer.partialTerm})
|
||||
}
|
||||
}
|
||||
for (var w in titleterms) {
|
||||
if (w.match(word) && !titleterms[word]) {
|
||||
if (w.match(word_regex) && !titleterms[word]) {
|
||||
_o.push({files: titleterms[w], score: Scorer.partialTitle})
|
||||
}
|
||||
}
|
||||
|
@ -312,6 +312,7 @@ class Locale(SphinxTransform):
|
||||
refname = newf.get('refname')
|
||||
refs = old_foot_namerefs.get(refname, [])
|
||||
if not refs:
|
||||
newf.parent.remove(newf)
|
||||
continue
|
||||
|
||||
oldf = refs.pop(0)
|
||||
|
@ -386,6 +386,10 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
# there's a classifier.
|
||||
pass
|
||||
else:
|
||||
if isinstance(node.parent.parent.parent, addnodes.glossary):
|
||||
# add permalink if glossary terms
|
||||
self.add_permalink_ref(node, _('Permalink to this term'))
|
||||
|
||||
self.body.append('</dt>')
|
||||
|
||||
# overwritten
|
||||
|
@ -337,6 +337,10 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
# there's a classifier.
|
||||
pass
|
||||
else:
|
||||
if isinstance(node.parent.parent.parent, addnodes.glossary):
|
||||
# add permalink if glossary terms
|
||||
self.add_permalink_ref(node, _('Permalink to this term'))
|
||||
|
||||
self.body.append('</dt>')
|
||||
|
||||
# overwritten
|
||||
|
@ -12,6 +12,10 @@ describe('jQuery extensions', function() {
|
||||
expect(jQuery.urldecode(test_encoded_string)).toEqual(test_decoded_string);
|
||||
});
|
||||
|
||||
it('+ should result in " "', function() {
|
||||
expect(jQuery.urldecode('+')).toEqual(' ');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('getQueryParameters', function() {
|
||||
|
32
tests/js/searchtools.js
Normal file
32
tests/js/searchtools.js
Normal file
@ -0,0 +1,32 @@
|
||||
describe('Basic html theme search', function() {
|
||||
|
||||
describe('terms search', function() {
|
||||
|
||||
it('should find "C++" when in index', function() {
|
||||
index = {
|
||||
docnames:["index"],
|
||||
filenames:["index.rst"],
|
||||
terms:{'c++':0},
|
||||
titles:["<no title>"],
|
||||
titleterms:{}
|
||||
}
|
||||
Search.setIndex(index);
|
||||
searchterms = ['c++'];
|
||||
excluded = [];
|
||||
terms = index.terms;
|
||||
titleterms = index.titleterms;
|
||||
|
||||
hits = [[
|
||||
"index",
|
||||
"<no title>",
|
||||
"",
|
||||
null,
|
||||
2,
|
||||
"index.rst"
|
||||
]];
|
||||
expect(Search.performTermsSearch(searchterms, excluded, terms, titleterms)).toEqual(hits);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -9,7 +9,7 @@ import sphinx.missing_module4 # NOQA
|
||||
from sphinx.missing_module4 import missing_name2 # NOQA
|
||||
|
||||
|
||||
@missing_name
|
||||
@missing_name(int)
|
||||
def decoratedFunction():
|
||||
"""decoratedFunction docstring"""
|
||||
return None
|
||||
|
@ -254,6 +254,7 @@ def test_html4_output(app, status, warning):
|
||||
(".//p[@class='centered']/strong", 'LICENSE'),
|
||||
# a glossary
|
||||
(".//dl/dt[@id='term-boson']", 'boson'),
|
||||
(".//dl/dt[@id='term-boson']/a", '¶'),
|
||||
# a production list
|
||||
(".//pre/strong", 'try_stmt'),
|
||||
(".//pre/a[@href='#grammar-token-try1_stmt']/code/span", 'try1_stmt'),
|
||||
|
@ -15,7 +15,7 @@ from typing import TypeVar
|
||||
|
||||
import pytest
|
||||
|
||||
from sphinx.ext.autodoc.mock import _MockModule, _MockObject, ismock, mock
|
||||
from sphinx.ext.autodoc.mock import _MockModule, _MockObject, ismock, mock, undecorate
|
||||
|
||||
|
||||
def test_MockModule():
|
||||
@ -115,20 +115,25 @@ def test_mock_decorator():
|
||||
|
||||
@mock.function_deco
|
||||
def func():
|
||||
"""docstring"""
|
||||
pass
|
||||
|
||||
class Foo:
|
||||
@mock.method_deco
|
||||
def meth(self):
|
||||
"""docstring"""
|
||||
pass
|
||||
|
||||
@mock.class_deco
|
||||
class Bar:
|
||||
"""docstring"""
|
||||
pass
|
||||
|
||||
assert func.__doc__ == "docstring"
|
||||
assert Foo.meth.__doc__ == "docstring"
|
||||
assert Bar.__doc__ == "docstring"
|
||||
@mock.funcion_deco(Foo)
|
||||
class Baz:
|
||||
pass
|
||||
|
||||
assert undecorate(func).__name__ == "func"
|
||||
assert undecorate(Foo.meth).__name__ == "meth"
|
||||
assert undecorate(Bar).__name__ == "Bar"
|
||||
assert undecorate(Baz).__name__ == "Baz"
|
||||
|
||||
|
||||
def test_ismock():
|
||||
|
@ -363,8 +363,12 @@ def get_verifier(verify, verify_re):
|
||||
# glossary (description list): multiple terms
|
||||
'verify',
|
||||
'.. glossary::\n\n term1\n term2\n description',
|
||||
('<dl class="glossary docutils">\n<dt id="term-term1">term1</dt>'
|
||||
'<dt id="term-term2">term2</dt><dd>description</dd>\n</dl>'),
|
||||
('<dl class="glossary docutils">\n'
|
||||
'<dt id="term-term1">term1<a class="headerlink" href="#term-term1"'
|
||||
' title="Permalink to this term">¶</a></dt>'
|
||||
'<dt id="term-term2">term2<a class="headerlink" href="#term-term2"'
|
||||
' title="Permalink to this term">¶</a></dt>'
|
||||
'<dd>description</dd>\n</dl>'),
|
||||
None,
|
||||
),
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user