mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '1.7'
This commit is contained in:
commit
506d4c87ef
6
CHANGES
6
CHANGES
@ -161,6 +161,12 @@ Bugs fixed
|
||||
* #4969: autodoc: constructor method should not have return annotation
|
||||
* latex: deeply nested enumerated list which is beginning with non-1 causes
|
||||
LaTeX engine crashed
|
||||
* #4978: latex: shorthandoff is not set up for Brazil locale
|
||||
* #4928: i18n: Ignore dot-directories like .git/ in LC_MESSAGES/
|
||||
* #4946: py domain: type field could not handle "None" as a type
|
||||
* #4979: latex: Incorrect escaping of curly braces in index entries
|
||||
* #4956: autodoc: Failed to extract document from a subclass of the class on
|
||||
mocked module
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
@ -27,6 +27,7 @@ from sphinx.util.build_phase import BuildPhase
|
||||
from sphinx.util.console import bold # type: ignore
|
||||
from sphinx.util.docutils import sphinx_domains
|
||||
from sphinx.util.i18n import find_catalog
|
||||
from sphinx.util.matching import Matcher
|
||||
from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath
|
||||
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \
|
||||
parallel_available
|
||||
@ -261,7 +262,8 @@ class Builder(object):
|
||||
self.config.language,
|
||||
charset=self.config.source_encoding,
|
||||
gettext_compact=self.config.gettext_compact,
|
||||
force_all=True)
|
||||
force_all=True,
|
||||
excluded=Matcher(['**/.?**']))
|
||||
message = __('all of %d po files') % len(catalogs)
|
||||
self.compile_catalogs(catalogs, message)
|
||||
|
||||
@ -282,7 +284,8 @@ class Builder(object):
|
||||
self.config.language,
|
||||
domains=list(specified_domains),
|
||||
charset=self.config.source_encoding,
|
||||
gettext_compact=self.config.gettext_compact)
|
||||
gettext_compact=self.config.gettext_compact,
|
||||
excluded=Matcher(['**/.?**']))
|
||||
message = __('targets for %d po files that are specified') % len(catalogs)
|
||||
self.compile_catalogs(catalogs, message)
|
||||
|
||||
@ -292,7 +295,8 @@ class Builder(object):
|
||||
[path.join(self.srcdir, x) for x in self.config.locale_dirs],
|
||||
self.config.language,
|
||||
charset=self.config.source_encoding,
|
||||
gettext_compact=self.config.gettext_compact)
|
||||
gettext_compact=self.config.gettext_compact,
|
||||
excluded=Matcher(['**/.?**']))
|
||||
message = __('targets for %d po files that are out of date') % len(catalogs)
|
||||
self.compile_catalogs(catalogs, message)
|
||||
|
||||
|
@ -176,7 +176,15 @@ class PyGroupedField(PyXrefMixin, GroupedField):
|
||||
|
||||
|
||||
class PyTypedField(PyXrefMixin, TypedField):
|
||||
pass
|
||||
def make_xref(self, rolename, domain, target,
|
||||
innernode=nodes.emphasis, contnode=None, env=None):
|
||||
# type: (unicode, unicode, unicode, nodes.Node, nodes.Node, BuildEnvironment) -> nodes.Node # NOQA
|
||||
if rolename == 'class' and target == 'None':
|
||||
# None is not a type, so use obj role instead.
|
||||
rolename = 'obj'
|
||||
|
||||
return super(PyTypedField, self).make_xref(rolename, domain, target,
|
||||
innernode, contnode, env)
|
||||
|
||||
|
||||
class PyObject(ObjectDescription):
|
||||
|
@ -23,7 +23,7 @@ from sphinx.util.inspect import isenumclass, safe_getattr
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Callable, Dict, Generator, List, Optional # NOQA
|
||||
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple # NOQA
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -31,6 +31,14 @@ logger = logging.getLogger(__name__)
|
||||
class _MockObject(object):
|
||||
"""Used by autodoc_mock_imports."""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
# type: (Any, Any) -> Any
|
||||
if len(args) == 3 and isinstance(args[1], tuple) and args[1][-1].__class__ is cls:
|
||||
# subclassing MockObject
|
||||
return type(args[0], (_MockObject,), args[2], **kwargs) # type: ignore
|
||||
else:
|
||||
return super(_MockObject, cls).__new__(cls)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# type: (Any, Any) -> None
|
||||
pass
|
||||
@ -47,6 +55,10 @@ class _MockObject(object):
|
||||
# type: () -> None
|
||||
pass
|
||||
|
||||
def __mro_entries__(self, bases):
|
||||
# type: (Tuple) -> Tuple
|
||||
return bases
|
||||
|
||||
def __getitem__(self, key):
|
||||
# type: (str) -> _MockObject
|
||||
return self
|
||||
|
@ -1612,6 +1612,10 @@
|
||||
% figure legend comes after caption and may contain arbitrary body elements
|
||||
\newenvironment{sphinxlegend}{\par\small}{\par}
|
||||
|
||||
% For curly braces inside \index macro
|
||||
\def\sphinxleftcurlybrace{\{}
|
||||
\def\sphinxrightcurlybrace{\}}
|
||||
|
||||
% Declare Unicode characters used by linux tree command to pdflatex utf8/utf8x
|
||||
\def\spx@bd#1#2{%
|
||||
\leavevmode
|
||||
|
@ -23,8 +23,10 @@ from babel.messages.pofile import read_po
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.matching import Matcher
|
||||
from sphinx.util.osutil import SEP, relpath, walk
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if False:
|
||||
@ -102,8 +104,9 @@ def find_catalog_files(docname, srcdir, locale_dirs, lang, compaction):
|
||||
|
||||
|
||||
def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact=False,
|
||||
charset='utf-8', force_all=False):
|
||||
# type: (List[unicode], unicode, List[unicode], bool, unicode, bool) -> Set[CatalogInfo]
|
||||
charset='utf-8', force_all=False,
|
||||
excluded=Matcher([])):
|
||||
# type: (List[unicode], unicode, List[unicode], bool, unicode, bool, Matcher) -> Set[CatalogInfo] # NOQA
|
||||
"""
|
||||
:param list locale_dirs:
|
||||
list of path as `['locale_dir1', 'locale_dir2', ...]` to find
|
||||
@ -137,6 +140,8 @@ def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact
|
||||
for dirpath, dirnames, filenames in walk(base_dir, followlinks=True):
|
||||
filenames = [f for f in filenames if f.endswith('.po')]
|
||||
for filename in filenames:
|
||||
if excluded(path.join(relpath(dirpath, base_dir), filename)):
|
||||
continue
|
||||
base = path.splitext(filename)[0]
|
||||
domain = relpath(path.join(dirpath, base), base_dir)
|
||||
if gettext_compact and path.sep in domain:
|
||||
|
@ -196,6 +196,7 @@ class ExtBabel(Babel):
|
||||
'ngerman': '"',
|
||||
'slovene': '"',
|
||||
'portuges': '"',
|
||||
'brazil': '"',
|
||||
'spanish': '"',
|
||||
'dutch': '"',
|
||||
'polish': '"',
|
||||
@ -1932,6 +1933,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
|
||||
def visit_index(self, node, scre=re.compile(r';\s*')):
|
||||
# type: (nodes.Node, Pattern) -> None
|
||||
def escape(value):
|
||||
value = self.encode(value)
|
||||
value = value.replace(r'\{', r'\sphinxleftcurlybrace')
|
||||
value = value.replace(r'\}', r'\sphinxrightcurlybrace')
|
||||
return value
|
||||
|
||||
if not node.get('inline', True):
|
||||
self.body.append('\n')
|
||||
entries = node['entries']
|
||||
@ -1941,24 +1948,23 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
m = '|textbf'
|
||||
try:
|
||||
if type == 'single':
|
||||
p = scre.sub('!', self.encode(string))
|
||||
p = scre.sub('!', escape(string))
|
||||
self.body.append(r'\index{%s%s}' % (p, m))
|
||||
elif type == 'pair':
|
||||
p1, p2 = [self.encode(x) for x in split_into(2, 'pair', string)]
|
||||
p1, p2 = [escape(x) for x in split_into(2, 'pair', string)]
|
||||
self.body.append(r'\index{%s!%s%s}\index{%s!%s%s}' %
|
||||
(p1, p2, m, p2, p1, m))
|
||||
elif type == 'triple':
|
||||
p1, p2, p3 = [self.encode(x)
|
||||
for x in split_into(3, 'triple', string)]
|
||||
p1, p2, p3 = [escape(x) for x in split_into(3, 'triple', string)]
|
||||
self.body.append(
|
||||
r'\index{%s!%s %s%s}\index{%s!%s, %s%s}'
|
||||
r'\index{%s!%s %s%s}' %
|
||||
(p1, p2, p3, m, p2, p3, p1, m, p3, p1, p2, m))
|
||||
elif type == 'see':
|
||||
p1, p2 = [self.encode(x) for x in split_into(2, 'see', string)]
|
||||
p1, p2 = [escape(x) for x in split_into(2, 'see', string)]
|
||||
self.body.append(r'\index{%s|see{%s}}' % (p1, p2))
|
||||
elif type == 'seealso':
|
||||
p1, p2 = [self.encode(x) for x in split_into(2, 'seealso', string)]
|
||||
p1, p2 = [escape(x) for x in split_into(2, 'seealso', string)]
|
||||
self.body.append(r'\index{%s|see{%s}}' % (p1, p2))
|
||||
else:
|
||||
logger.warning(__('unknown index entry type %s found'), type)
|
||||
|
@ -10,3 +10,7 @@ A :index:`famous` :index:`equation`:
|
||||
.. index:: Einstein, relativity
|
||||
|
||||
and some text.
|
||||
|
||||
.. index:: main {
|
||||
|
||||
An index entry containing non paired curly brace
|
||||
|
@ -1201,6 +1201,7 @@ def test_latex_index(app, status, warning):
|
||||
result = (app.outdir / 'Python.tex').text(encoding='utf8')
|
||||
assert 'A \\index{famous}famous \\index{equation}equation:\n' in result
|
||||
assert '\n\\index{Einstein}\\index{relativity}\\ignorespaces \nand' in result
|
||||
assert '\n\\index{main \\sphinxleftcurlybrace}\\ignorespaces ' in result
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='latex-equations')
|
||||
|
31
tests/test_ext_autodoc_importer.py
Normal file
31
tests/test_ext_autodoc_importer.py
Normal file
@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
test_ext_autodoc_importer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Test the autodoc extension.
|
||||
|
||||
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.ext.autodoc.importer import _MockObject
|
||||
|
||||
|
||||
def test_MockObject():
|
||||
mock = _MockObject()
|
||||
assert isinstance(mock.some_attr, _MockObject)
|
||||
assert isinstance(mock.some_method, _MockObject)
|
||||
assert isinstance(mock.attr1.attr2, _MockObject)
|
||||
assert isinstance(mock.attr1.attr2.meth(), _MockObject)
|
||||
|
||||
class SubClass(mock.SomeClass):
|
||||
"""docstring of SubClass"""
|
||||
def method(self):
|
||||
return "string"
|
||||
|
||||
obj = SubClass()
|
||||
assert SubClass.__doc__ == "docstring of SubClass"
|
||||
assert isinstance(obj, SubClass)
|
||||
assert obj.method() == "string"
|
||||
assert isinstance(obj.other_method(), SubClass)
|
@ -157,6 +157,17 @@ def test_get_catalogs_with_compact(tempdir):
|
||||
assert domains == set(['test1', 'test2', 'sub'])
|
||||
|
||||
|
||||
def test_get_catalogs_excluded(tempdir):
|
||||
(tempdir / 'loc1' / 'en' / 'LC_MESSAGES' / '.git').makedirs()
|
||||
(tempdir / 'loc1' / 'en' / 'LC_MESSAGES' / 'en_dom.po').write_text('#')
|
||||
(tempdir / 'loc1' / 'en' / 'LC_MESSAGES' / '.git' / 'no_no.po').write_text('#')
|
||||
|
||||
catalogs = i18n.find_catalog_source_files(
|
||||
[tempdir / 'loc1'], 'en', force_all=False, excluded=lambda path: '.git' in path)
|
||||
domains = set(c.domain for c in catalogs)
|
||||
assert domains == set(['en_dom'])
|
||||
|
||||
|
||||
def test_format_date():
|
||||
date = datetime.date(2016, 2, 7)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user