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
3e57ea0a52
23
CHANGES
23
CHANGES
@ -181,7 +181,7 @@ Documentation
|
|||||||
* #5083: Fix wrong make.bat option for internationalization.
|
* #5083: Fix wrong make.bat option for internationalization.
|
||||||
* #5115: napoleon: add admonitions added by #4613 to the docs.
|
* #5115: napoleon: add admonitions added by #4613 to the docs.
|
||||||
|
|
||||||
Release 1.7.6 (in development)
|
Release 1.7.7 (in development)
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
Dependencies
|
Dependencies
|
||||||
@ -199,6 +199,15 @@ Features added
|
|||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
Testing
|
||||||
|
--------
|
||||||
|
|
||||||
|
Release 1.7.6 (released Jul 17, 2018)
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Bugs fixed
|
||||||
|
----------
|
||||||
|
|
||||||
* #5037: LaTeX ``\sphinxupquote{}`` breaks in Russian
|
* #5037: LaTeX ``\sphinxupquote{}`` breaks in Russian
|
||||||
* sphinx.testing uses deprecated pytest API; ``Node.get_marker(name)``
|
* sphinx.testing uses deprecated pytest API; ``Node.get_marker(name)``
|
||||||
* #5016: crashed when recommonmark.AutoStrictify is enabled
|
* #5016: crashed when recommonmark.AutoStrictify is enabled
|
||||||
@ -216,6 +225,7 @@ Bugs fixed
|
|||||||
* #5091: latex: curly braces in index entries are not handled correctly
|
* #5091: latex: curly braces in index entries are not handled correctly
|
||||||
* #5070: epub: Wrong internal href fragment links
|
* #5070: epub: Wrong internal href fragment links
|
||||||
* #5104: apidoc: Interface of ``sphinx.apidoc:main()`` has changed
|
* #5104: apidoc: Interface of ``sphinx.apidoc:main()`` has changed
|
||||||
|
* #4272: PDF builds of French projects have issues with XeTeX
|
||||||
* #5076: napoleon raises RuntimeError with python 3.7
|
* #5076: napoleon raises RuntimeError with python 3.7
|
||||||
* #5125: sphinx-build: Interface of ``sphinx:main()`` has changed
|
* #5125: sphinx-build: Interface of ``sphinx:main()`` has changed
|
||||||
* sphinx-build: ``sphinx.cmd.build.main()`` refers ``sys.argv`` instead of given
|
* sphinx-build: ``sphinx.cmd.build.main()`` refers ``sys.argv`` instead of given
|
||||||
@ -225,9 +235,14 @@ Bugs fixed
|
|||||||
* autosummary: warnings of autosummary indicates wrong location (refs: #5146)
|
* autosummary: warnings of autosummary indicates wrong location (refs: #5146)
|
||||||
* #5143: autodoc: crashed on inspecting dict like object which does not support
|
* #5143: autodoc: crashed on inspecting dict like object which does not support
|
||||||
sorting
|
sorting
|
||||||
|
* #5139: autodoc: Enum argument missing if it shares value with another
|
||||||
Testing
|
* #4946: py domain: rtype field could not handle "None" as a type
|
||||||
--------
|
* #5176: LaTeX: indexing of terms containing ``@``, ``!``, or ``"`` fails
|
||||||
|
* #5161: html: crashes if copying static files are failed
|
||||||
|
* #5167: autodoc: Fix formatting type annotations for tuples with more than two
|
||||||
|
arguments
|
||||||
|
* #3329: i18n: crashed by auto-symbol footnote references
|
||||||
|
* #5158: autosummary: module summary has been broken when it starts with heading
|
||||||
|
|
||||||
Release 1.7.5 (released May 29, 2018)
|
Release 1.7.5 (released May 29, 2018)
|
||||||
=====================================
|
=====================================
|
||||||
|
@ -31,7 +31,7 @@ directory = sphinx/locale/
|
|||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 95
|
max-line-length = 95
|
||||||
ignore = E116,E241,E251,E741,I101
|
ignore = E116,E241,E251,E741,W504,I101
|
||||||
exclude = .git,.tox,.venv,tests/*,build/*,doc/_build/*,sphinx/search/*,doc/usage/extensions/example*.py
|
exclude = .git,.tox,.venv,tests/*,build/*,doc/_build/*,sphinx/search/*,doc/usage/extensions/example*.py
|
||||||
application-import-names = sphinx
|
application-import-names = sphinx
|
||||||
import-order-style = smarkets
|
import-order-style = smarkets
|
||||||
|
@ -848,85 +848,94 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
try:
|
try:
|
||||||
copyfile(path.join(self.srcdir, src),
|
copyfile(path.join(self.srcdir, src),
|
||||||
path.join(self.outdir, '_downloads', dest))
|
path.join(self.outdir, '_downloads', dest))
|
||||||
except Exception as err:
|
except EnvironmentError as err:
|
||||||
logger.warning(__('cannot copy downloadable file %r: %s'),
|
logger.warning(__('cannot copy downloadable file %r: %s'),
|
||||||
path.join(self.srcdir, src), err)
|
path.join(self.srcdir, src), err)
|
||||||
|
|
||||||
def copy_static_files(self):
|
def copy_static_files(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
# copy static files
|
try:
|
||||||
logger.info(bold(__('copying static files... ')), nonl=True)
|
# copy static files
|
||||||
ensuredir(path.join(self.outdir, '_static'))
|
logger.info(bold(__('copying static files... ')), nonl=True)
|
||||||
# first, create pygments style file
|
ensuredir(path.join(self.outdir, '_static'))
|
||||||
with open(path.join(self.outdir, '_static', 'pygments.css'), 'w') as f:
|
# first, create pygments style file
|
||||||
f.write(self.highlighter.get_stylesheet()) # type: ignore
|
with open(path.join(self.outdir, '_static', 'pygments.css'), 'w') as f:
|
||||||
# then, copy translations JavaScript file
|
f.write(self.highlighter.get_stylesheet()) # type: ignore
|
||||||
if self.config.language is not None:
|
# then, copy translations JavaScript file
|
||||||
jsfile = self._get_translations_js()
|
if self.config.language is not None:
|
||||||
if jsfile:
|
jsfile = self._get_translations_js()
|
||||||
copyfile(jsfile, path.join(self.outdir, '_static',
|
if jsfile:
|
||||||
'translations.js'))
|
copyfile(jsfile, path.join(self.outdir, '_static',
|
||||||
|
'translations.js'))
|
||||||
|
|
||||||
# copy non-minified stemmer JavaScript file
|
# copy non-minified stemmer JavaScript file
|
||||||
if self.indexer is not None:
|
if self.indexer is not None:
|
||||||
jsfile = self.indexer.get_js_stemmer_rawcode()
|
jsfile = self.indexer.get_js_stemmer_rawcode()
|
||||||
if jsfile:
|
if jsfile:
|
||||||
copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js'))
|
copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js'))
|
||||||
|
|
||||||
ctx = self.globalcontext.copy()
|
ctx = self.globalcontext.copy()
|
||||||
|
|
||||||
# add context items for search function used in searchtools.js_t
|
# add context items for search function used in searchtools.js_t
|
||||||
if self.indexer is not None:
|
if self.indexer is not None:
|
||||||
ctx.update(self.indexer.context_for_searchtool())
|
ctx.update(self.indexer.context_for_searchtool())
|
||||||
|
|
||||||
# then, copy over theme-supplied static files
|
# then, copy over theme-supplied static files
|
||||||
if self.theme:
|
if self.theme:
|
||||||
for theme_path in self.theme.get_theme_dirs()[::-1]:
|
for theme_path in self.theme.get_theme_dirs()[::-1]:
|
||||||
entry = path.join(theme_path, 'static')
|
entry = path.join(theme_path, 'static')
|
||||||
copy_asset(entry, path.join(self.outdir, '_static'), excluded=DOTFILES,
|
copy_asset(entry, path.join(self.outdir, '_static'), excluded=DOTFILES,
|
||||||
|
context=ctx, renderer=self.templates)
|
||||||
|
# then, copy over all user-supplied static files
|
||||||
|
excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
|
||||||
|
for static_path in self.config.html_static_path:
|
||||||
|
entry = path.join(self.confdir, static_path)
|
||||||
|
if not path.exists(entry):
|
||||||
|
logger.warning(__('html_static_path entry %r does not exist'), entry)
|
||||||
|
continue
|
||||||
|
copy_asset(entry, path.join(self.outdir, '_static'), excluded,
|
||||||
context=ctx, renderer=self.templates)
|
context=ctx, renderer=self.templates)
|
||||||
# then, copy over all user-supplied static files
|
# copy logo and favicon files if not already in static path
|
||||||
excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
|
if self.config.html_logo:
|
||||||
for static_path in self.config.html_static_path:
|
logobase = path.basename(self.config.html_logo)
|
||||||
entry = path.join(self.confdir, static_path)
|
logotarget = path.join(self.outdir, '_static', logobase)
|
||||||
if not path.exists(entry):
|
if not path.isfile(path.join(self.confdir, self.config.html_logo)):
|
||||||
logger.warning(__('html_static_path entry %r does not exist'), entry)
|
logger.warning(__('logo file %r does not exist'), self.config.html_logo)
|
||||||
continue
|
elif not path.isfile(logotarget):
|
||||||
copy_asset(entry, path.join(self.outdir, '_static'), excluded,
|
copyfile(path.join(self.confdir, self.config.html_logo),
|
||||||
context=ctx, renderer=self.templates)
|
logotarget)
|
||||||
# copy logo and favicon files if not already in static path
|
if self.config.html_favicon:
|
||||||
if self.config.html_logo:
|
iconbase = path.basename(self.config.html_favicon)
|
||||||
logobase = path.basename(self.config.html_logo)
|
icontarget = path.join(self.outdir, '_static', iconbase)
|
||||||
logotarget = path.join(self.outdir, '_static', logobase)
|
if not path.isfile(path.join(self.confdir, self.config.html_favicon)):
|
||||||
if not path.isfile(path.join(self.confdir, self.config.html_logo)):
|
logger.warning(__('favicon file %r does not exist'),
|
||||||
logger.warning(__('logo file %r does not exist'), self.config.html_logo)
|
self.config.html_favicon)
|
||||||
elif not path.isfile(logotarget):
|
elif not path.isfile(icontarget):
|
||||||
copyfile(path.join(self.confdir, self.config.html_logo),
|
copyfile(path.join(self.confdir, self.config.html_favicon),
|
||||||
logotarget)
|
icontarget)
|
||||||
if self.config.html_favicon:
|
logger.info('done')
|
||||||
iconbase = path.basename(self.config.html_favicon)
|
except EnvironmentError as err:
|
||||||
icontarget = path.join(self.outdir, '_static', iconbase)
|
# TODO: In py3, EnvironmentError (and IOError) was merged into OSError.
|
||||||
if not path.isfile(path.join(self.confdir, self.config.html_favicon)):
|
# So it should be replaced by IOError on dropping py2 support
|
||||||
logger.warning(__('favicon file %r does not exist'), self.config.html_favicon)
|
logger.warning(__('cannot copy static file %r'), err)
|
||||||
elif not path.isfile(icontarget):
|
|
||||||
copyfile(path.join(self.confdir, self.config.html_favicon),
|
|
||||||
icontarget)
|
|
||||||
logger.info('done')
|
|
||||||
|
|
||||||
def copy_extra_files(self):
|
def copy_extra_files(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
# copy html_extra_path files
|
try:
|
||||||
logger.info(bold(__('copying extra files... ')), nonl=True)
|
# copy html_extra_path files
|
||||||
excluded = Matcher(self.config.exclude_patterns)
|
logger.info(bold(__('copying extra files... ')), nonl=True)
|
||||||
|
excluded = Matcher(self.config.exclude_patterns)
|
||||||
|
|
||||||
for extra_path in self.config.html_extra_path:
|
for extra_path in self.config.html_extra_path:
|
||||||
entry = path.join(self.confdir, extra_path)
|
entry = path.join(self.confdir, extra_path)
|
||||||
if not path.exists(entry):
|
if not path.exists(entry):
|
||||||
logger.warning(__('html_extra_path entry %r does not exist'), entry)
|
logger.warning(__('html_extra_path entry %r does not exist'), entry)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
copy_asset(entry, self.outdir, excluded)
|
copy_asset(entry, self.outdir, excluded)
|
||||||
logger.info(__('done'))
|
logger.info(__('done'))
|
||||||
|
except EnvironmentError as err:
|
||||||
|
logger.warning(__('cannot copy extra file %r'), err)
|
||||||
|
|
||||||
def write_buildinfo(self):
|
def write_buildinfo(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
|
@ -160,7 +160,7 @@ class CheckExternalLinksBuilder(Builder):
|
|||||||
# the server and the network
|
# the server and the network
|
||||||
response = requests.head(req_url, config=self.app.config, **kwargs)
|
response = requests.head(req_url, config=self.app.config, **kwargs)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
except HTTPError as err:
|
except HTTPError:
|
||||||
# retry with GET request if that fails, some servers
|
# retry with GET request if that fails, some servers
|
||||||
# don't like HEAD requests.
|
# don't like HEAD requests.
|
||||||
response = requests.get(req_url, stream=True, config=self.app.config,
|
response = requests.get(req_url, stream=True, config=self.app.config,
|
||||||
|
@ -168,7 +168,15 @@ class PyXrefMixin(object):
|
|||||||
|
|
||||||
|
|
||||||
class PyField(PyXrefMixin, Field):
|
class PyField(PyXrefMixin, Field):
|
||||||
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(PyField, self).make_xref(rolename, domain, target,
|
||||||
|
innernode, contnode, env)
|
||||||
|
|
||||||
|
|
||||||
class PyGroupedField(PyXrefMixin, GroupedField):
|
class PyGroupedField(PyXrefMixin, GroupedField):
|
||||||
|
@ -221,12 +221,21 @@ def get_object_members(subject, objpath, attrgetter, analyzer=None):
|
|||||||
for name, value in subject.__members__.items():
|
for name, value in subject.__members__.items():
|
||||||
obj_dict[name] = value
|
obj_dict[name] = value
|
||||||
|
|
||||||
members = {}
|
members = {} # type: Dict[str, Attribute]
|
||||||
|
|
||||||
|
# enum members
|
||||||
|
if isenumclass(subject):
|
||||||
|
for name, value in subject.__members__.items():
|
||||||
|
if name not in members:
|
||||||
|
members[name] = Attribute(name, True, value)
|
||||||
|
|
||||||
|
# other members
|
||||||
for name in dir(subject):
|
for name in dir(subject):
|
||||||
try:
|
try:
|
||||||
value = attrgetter(subject, name)
|
value = attrgetter(subject, name)
|
||||||
directly_defined = name in obj_dict
|
directly_defined = name in obj_dict
|
||||||
members[name] = Attribute(name, directly_defined, value)
|
if name not in members:
|
||||||
|
members[name] = Attribute(name, directly_defined, value)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -473,21 +473,32 @@ def extract_summary(doc, document):
|
|||||||
doc = doc[:i]
|
doc = doc[:i]
|
||||||
break
|
break
|
||||||
|
|
||||||
# Try to find the "first sentence", which may span multiple lines
|
if doc == []:
|
||||||
sentences = periods_re.split(" ".join(doc)) # type: ignore
|
return ''
|
||||||
if len(sentences) == 1:
|
|
||||||
summary = sentences[0].strip()
|
# parse the docstring
|
||||||
|
state_machine = RSTStateMachine(state_classes, 'Body')
|
||||||
|
node = new_document('', document.settings)
|
||||||
|
node.reporter = NullReporter()
|
||||||
|
state_machine.run(doc, node)
|
||||||
|
|
||||||
|
if not isinstance(node[0], nodes.paragraph):
|
||||||
|
# document starts with non-paragraph: pick up the first line
|
||||||
|
summary = doc[0].strip()
|
||||||
else:
|
else:
|
||||||
summary = ''
|
# Try to find the "first sentence", which may span multiple lines
|
||||||
state_machine = RSTStateMachine(state_classes, 'Body')
|
sentences = periods_re.split(" ".join(doc)) # type: ignore
|
||||||
while sentences:
|
if len(sentences) == 1:
|
||||||
summary += sentences.pop(0) + '.'
|
summary = sentences[0].strip()
|
||||||
node = new_document('', document.settings)
|
else:
|
||||||
node.reporter = NullReporter()
|
summary = ''
|
||||||
state_machine.run([summary], node)
|
while sentences:
|
||||||
if not node.traverse(nodes.system_message):
|
summary += sentences.pop(0) + '.'
|
||||||
# considered as that splitting by period does not break inline markups
|
node[:] = []
|
||||||
break
|
state_machine.run([summary], node)
|
||||||
|
if not node.traverse(nodes.system_message):
|
||||||
|
# considered as that splitting by period does not break inline markups
|
||||||
|
break
|
||||||
|
|
||||||
# strip literal notation mark ``::`` from tail of summary
|
# strip literal notation mark ``::`` from tail of summary
|
||||||
summary = literal_re.sub('.', summary)
|
summary = literal_re.sub('.', summary)
|
||||||
|
@ -269,7 +269,7 @@ def find_autosummary_in_docstring(name, module=None, filename=None):
|
|||||||
pass
|
pass
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print("Failed to import '%s': %s" % (name, e))
|
print("Failed to import '%s': %s" % (name, e))
|
||||||
except SystemExit as e:
|
except SystemExit:
|
||||||
print("Failed to import '%s'; the module executes module level "
|
print("Failed to import '%s'; the module executes module level "
|
||||||
"statement and it might call sys.exit()." % name)
|
"statement and it might call sys.exit()." % name)
|
||||||
return []
|
return []
|
||||||
|
@ -276,10 +276,9 @@ class Locale(SphinxTransform):
|
|||||||
continue # skip
|
continue # skip
|
||||||
|
|
||||||
# auto-numbered foot note reference should use original 'ids'.
|
# auto-numbered foot note reference should use original 'ids'.
|
||||||
def is_autonumber_footnote_ref(node):
|
def is_autofootnote_ref(node):
|
||||||
# type: (nodes.Node) -> bool
|
# type: (nodes.Node) -> bool
|
||||||
return isinstance(node, nodes.footnote_reference) and \
|
return isinstance(node, nodes.footnote_reference) and node.get('auto')
|
||||||
node.get('auto') == 1
|
|
||||||
|
|
||||||
def list_replace_or_append(lst, old, new):
|
def list_replace_or_append(lst, old, new):
|
||||||
# type: (List, Any, Any) -> None
|
# type: (List, Any, Any) -> None
|
||||||
@ -287,8 +286,8 @@ class Locale(SphinxTransform):
|
|||||||
lst[lst.index(old)] = new
|
lst[lst.index(old)] = new
|
||||||
else:
|
else:
|
||||||
lst.append(new)
|
lst.append(new)
|
||||||
old_foot_refs = node.traverse(is_autonumber_footnote_ref)
|
old_foot_refs = node.traverse(is_autofootnote_ref)
|
||||||
new_foot_refs = patch.traverse(is_autonumber_footnote_ref)
|
new_foot_refs = patch.traverse(is_autofootnote_ref)
|
||||||
if len(old_foot_refs) != len(new_foot_refs):
|
if len(old_foot_refs) != len(new_foot_refs):
|
||||||
old_foot_ref_rawsources = [ref.rawsource for ref in old_foot_refs]
|
old_foot_ref_rawsources = [ref.rawsource for ref in old_foot_refs]
|
||||||
new_foot_ref_rawsources = [ref.rawsource for ref in new_foot_refs]
|
new_foot_ref_rawsources = [ref.rawsource for ref in new_foot_refs]
|
||||||
@ -309,8 +308,14 @@ class Locale(SphinxTransform):
|
|||||||
new['ids'] = old['ids']
|
new['ids'] = old['ids']
|
||||||
for id in new['ids']:
|
for id in new['ids']:
|
||||||
self.document.ids[id] = new
|
self.document.ids[id] = new
|
||||||
list_replace_or_append(
|
|
||||||
self.document.autofootnote_refs, old, new)
|
if new['auto'] == 1:
|
||||||
|
# autofootnote_refs
|
||||||
|
list_replace_or_append(self.document.autofootnote_refs, old, new)
|
||||||
|
else:
|
||||||
|
# symbol_footnote_refs
|
||||||
|
list_replace_or_append(self.document.symbol_footnote_refs, old, new)
|
||||||
|
|
||||||
if refname:
|
if refname:
|
||||||
list_replace_or_append(
|
list_replace_or_append(
|
||||||
self.document.footnote_refs.setdefault(refname, []),
|
self.document.footnote_refs.setdefault(refname, []),
|
||||||
|
@ -532,6 +532,13 @@ class Signature(object):
|
|||||||
|
|
||||||
if annotation.__module__ == 'builtins':
|
if annotation.__module__ == 'builtins':
|
||||||
return annotation.__qualname__ # type: ignore
|
return annotation.__qualname__ # type: ignore
|
||||||
|
elif (hasattr(typing, 'TupleMeta') and
|
||||||
|
isinstance(annotation, typing.TupleMeta) and # type: ignore
|
||||||
|
not hasattr(annotation, '__tuple_params__')):
|
||||||
|
# This is for Python 3.6+, 3.5 case is handled below
|
||||||
|
params = annotation.__args__
|
||||||
|
param_str = ', '.join(self.format_annotation(p) for p in params)
|
||||||
|
return '%s[%s]' % (qualified_name, param_str)
|
||||||
elif (hasattr(typing, 'GenericMeta') and # for py36 or below
|
elif (hasattr(typing, 'GenericMeta') and # for py36 or below
|
||||||
isinstance(annotation, typing.GenericMeta)):
|
isinstance(annotation, typing.GenericMeta)):
|
||||||
# In Python 3.5.2+, all arguments are stored in __args__,
|
# In Python 3.5.2+, all arguments are stored in __args__,
|
||||||
|
@ -485,6 +485,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
# sort out some elements
|
# sort out some elements
|
||||||
self.elements = DEFAULT_SETTINGS.copy()
|
self.elements = DEFAULT_SETTINGS.copy()
|
||||||
self.elements.update(ADDITIONAL_SETTINGS.get(builder.config.latex_engine, {}))
|
self.elements.update(ADDITIONAL_SETTINGS.get(builder.config.latex_engine, {}))
|
||||||
|
# for xelatex+French, don't use polyglossia
|
||||||
|
if self.elements['latex_engine'] == 'xelatex':
|
||||||
|
if builder.config.language:
|
||||||
|
if builder.config.language[:2] == 'fr':
|
||||||
|
self.elements.update({
|
||||||
|
'polyglossia': '',
|
||||||
|
'babel': '\\usepackage{babel}',
|
||||||
|
})
|
||||||
# allow the user to override them all
|
# allow the user to override them all
|
||||||
self.check_latex_elements()
|
self.check_latex_elements()
|
||||||
self.elements.update(builder.config.latex_elements)
|
self.elements.update(builder.config.latex_elements)
|
||||||
|
@ -233,3 +233,4 @@ class EnumCls(enum.Enum):
|
|||||||
val2 = 23 #: doc for val2
|
val2 = 23 #: doc for val2
|
||||||
val3 = 34
|
val3 = 34
|
||||||
"""doc for val3"""
|
"""doc for val3"""
|
||||||
|
val4 = 34
|
||||||
|
@ -19,8 +19,8 @@ msgstr ""
|
|||||||
msgid "i18n with Footnote"
|
msgid "i18n with Footnote"
|
||||||
msgstr "I18N WITH FOOTNOTE"
|
msgstr "I18N WITH FOOTNOTE"
|
||||||
|
|
||||||
msgid "[100]_ Contents [#]_ for `i18n with Footnote`_ [ref]_ [#named]_."
|
msgid "[100]_ Contents [#]_ for `i18n with Footnote`_ [ref]_ [#named]_ [*]_."
|
||||||
msgstr "`I18N WITH FOOTNOTE`_ INCLUDE THIS CONTENTS [#named]_ [ref]_ [#]_ [100]_."
|
msgstr "`I18N WITH FOOTNOTE`_ INCLUDE THIS CONTENTS [#named]_ [ref]_ [#]_ [100]_ [*]_."
|
||||||
|
|
||||||
msgid "This is a auto numbered footnote."
|
msgid "This is a auto numbered footnote."
|
||||||
msgstr "THIS IS A AUTO NUMBERED FOOTNOTE."
|
msgstr "THIS IS A AUTO NUMBERED FOOTNOTE."
|
||||||
@ -34,3 +34,5 @@ msgstr "THIS IS A NUMBERED FOOTNOTE."
|
|||||||
msgid "This is a auto numbered named footnote."
|
msgid "This is a auto numbered named footnote."
|
||||||
msgstr "THIS IS A AUTO NUMBERED NAMED FOOTNOTE."
|
msgstr "THIS IS A AUTO NUMBERED NAMED FOOTNOTE."
|
||||||
|
|
||||||
|
msgid "This is a auto symbol footnote."
|
||||||
|
msgstr "THIS IS A AUTO SYMBOL FOOTNOTE."
|
||||||
|
@ -4,9 +4,10 @@ i18n with Footnote
|
|||||||
==================
|
==================
|
||||||
.. #955 cant-build-html-with-footnotes-when-using
|
.. #955 cant-build-html-with-footnotes-when-using
|
||||||
|
|
||||||
[100]_ Contents [#]_ for `i18n with Footnote`_ [ref]_ [#named]_.
|
[100]_ Contents [#]_ for `i18n with Footnote`_ [ref]_ [#named]_ [*]_.
|
||||||
|
|
||||||
.. [#] This is a auto numbered footnote.
|
.. [#] This is a auto numbered footnote.
|
||||||
.. [ref] This is a named footnote.
|
.. [ref] This is a named footnote.
|
||||||
.. [100] This is a numbered footnote.
|
.. [100] This is a numbered footnote.
|
||||||
.. [#named] This is a auto numbered named footnote.
|
.. [#named] This is a auto numbered named footnote.
|
||||||
|
.. [*] This is a auto symbol footnote.
|
||||||
|
@ -873,13 +873,14 @@ def test_generate():
|
|||||||
# test members with enum attributes
|
# test members with enum attributes
|
||||||
directive.env.ref_context['py:module'] = 'target'
|
directive.env.ref_context['py:module'] = 'target'
|
||||||
options.inherited_members = False
|
options.inherited_members = False
|
||||||
options.undoc_members = False
|
options.undoc_members = True
|
||||||
options.members = ALL
|
options.members = ALL
|
||||||
assert_processes([
|
assert_processes([
|
||||||
('class', 'target.EnumCls'),
|
('class', 'target.EnumCls'),
|
||||||
('attribute', 'target.EnumCls.val1'),
|
('attribute', 'target.EnumCls.val1'),
|
||||||
('attribute', 'target.EnumCls.val2'),
|
('attribute', 'target.EnumCls.val2'),
|
||||||
('attribute', 'target.EnumCls.val3'),
|
('attribute', 'target.EnumCls.val3'),
|
||||||
|
('attribute', 'target.EnumCls.val4'),
|
||||||
], 'class', 'EnumCls')
|
], 'class', 'EnumCls')
|
||||||
assert_result_contains(
|
assert_result_contains(
|
||||||
' :annotation: = 12', 'attribute', 'EnumCls.val1')
|
' :annotation: = 12', 'attribute', 'EnumCls.val1')
|
||||||
|
@ -85,6 +85,11 @@ def test_extract_summary(capsys):
|
|||||||
doc = ['blah blah::']
|
doc = ['blah blah::']
|
||||||
assert extract_summary(doc, document) == 'blah blah.'
|
assert extract_summary(doc, document) == 'blah blah.'
|
||||||
|
|
||||||
|
# heading
|
||||||
|
doc = ['blah blah',
|
||||||
|
'=========']
|
||||||
|
assert extract_summary(doc, document) == 'blah blah'
|
||||||
|
|
||||||
_, err = capsys.readouterr()
|
_, err = capsys.readouterr()
|
||||||
assert err == ''
|
assert err == ''
|
||||||
|
|
||||||
|
@ -794,7 +794,7 @@ def test_xml_footnotes(app, warning):
|
|||||||
assert_elem(
|
assert_elem(
|
||||||
para0[0],
|
para0[0],
|
||||||
['I18N WITH FOOTNOTE', 'INCLUDE THIS CONTENTS',
|
['I18N WITH FOOTNOTE', 'INCLUDE THIS CONTENTS',
|
||||||
'2', '[ref]', '1', '100', '.'],
|
'2', '[ref]', '1', '100', '*', '.'],
|
||||||
['i18n-with-footnote', 'ref'])
|
['i18n-with-footnote', 'ref'])
|
||||||
|
|
||||||
footnote0 = secs[0].findall('footnote')
|
footnote0 = secs[0].findall('footnote')
|
||||||
@ -813,6 +813,11 @@ def test_xml_footnotes(app, warning):
|
|||||||
['2', 'THIS IS A AUTO NUMBERED NAMED FOOTNOTE.'],
|
['2', 'THIS IS A AUTO NUMBERED NAMED FOOTNOTE.'],
|
||||||
None,
|
None,
|
||||||
['named'])
|
['named'])
|
||||||
|
assert_elem(
|
||||||
|
footnote0[3],
|
||||||
|
['*', 'THIS IS A AUTO SYMBOL FOOTNOTE.'],
|
||||||
|
None,
|
||||||
|
None)
|
||||||
|
|
||||||
citation0 = secs[0].findall('citation')
|
citation0 = secs[0].findall('citation')
|
||||||
assert_elem(
|
assert_elem(
|
||||||
|
@ -231,7 +231,7 @@ def test_Signature_partialmethod():
|
|||||||
@pytest.mark.skipif(sys.version_info < (3, 5),
|
@pytest.mark.skipif(sys.version_info < (3, 5),
|
||||||
reason='type annotation test is available on py35 or above')
|
reason='type annotation test is available on py35 or above')
|
||||||
def test_Signature_annotations():
|
def test_Signature_annotations():
|
||||||
from typing_test_data import f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11
|
from typing_test_data import f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12
|
||||||
|
|
||||||
# Class annotations
|
# Class annotations
|
||||||
sig = inspect.Signature(f0).format_args()
|
sig = inspect.Signature(f0).format_args()
|
||||||
@ -284,6 +284,10 @@ def test_Signature_annotations():
|
|||||||
sig = inspect.Signature(f11, has_retval=False).format_args()
|
sig = inspect.Signature(f11, has_retval=False).format_args()
|
||||||
assert sig == '(x: CustomAnnotation, y: 123)'
|
assert sig == '(x: CustomAnnotation, y: 123)'
|
||||||
|
|
||||||
|
# tuple with more than two items
|
||||||
|
sig = inspect.Signature(f12).format_args()
|
||||||
|
assert sig == '() -> Tuple[int, str, int]'
|
||||||
|
|
||||||
|
|
||||||
def test_safe_getattr_with_default():
|
def test_safe_getattr_with_default():
|
||||||
class Foo(object):
|
class Foo(object):
|
||||||
|
@ -62,3 +62,7 @@ class CustomAnnotation:
|
|||||||
|
|
||||||
def f11(x: CustomAnnotation(), y: 123) -> None:
|
def f11(x: CustomAnnotation(), y: 123) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def f12() -> Tuple[int, str, int]:
|
||||||
|
pass
|
||||||
|
Loading…
Reference in New Issue
Block a user