mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch 'stable'
This commit is contained in:
commit
8cbe1efe8d
1
CHANGES
1
CHANGES
@ -82,6 +82,7 @@ Bugs fixed
|
||||
* #3268: Sphinx crashes with requests package from Debian jessie
|
||||
* #3284: Sphinx crashes on parallel build with an extension which raises
|
||||
unserializable exception
|
||||
* #3315: Bibliography crashes on latex build with docclass 'memoir'
|
||||
|
||||
|
||||
Release 1.5.1 (released Dec 13, 2016)
|
||||
|
2
Makefile
2
Makefile
@ -6,7 +6,7 @@ PYTHON ?= python
|
||||
DONT_CHECK = -i build -i dist -i sphinx/style/jquery.js \
|
||||
-i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py \
|
||||
-i .ropeproject -i doc/_build -i tests/path.py \
|
||||
-i tests/coverage.py -i utils/convert.py \
|
||||
-i utils/convert.py \
|
||||
-i tests/typing_test_data.py \
|
||||
-i tests/test_autodoc_py35.py \
|
||||
-i tests/roots/test-warnings/undecodable.rst \
|
||||
|
@ -712,13 +712,13 @@ class StandardDomain(Domain):
|
||||
else:
|
||||
title = env.config.numfig_format.get(figtype, '')
|
||||
|
||||
if figname is None and '%{name}' in title:
|
||||
if figname is None and '{name}' in title:
|
||||
logger.warning('the link has no caption: %s', title, location=node)
|
||||
return contnode
|
||||
else:
|
||||
fignum = '.'.join(map(str, fignumber))
|
||||
if '{name}' in title or 'number' in title:
|
||||
# new style format (cf. "Fig.%{number}")
|
||||
# new style format (cf. "Fig.{number}")
|
||||
if figname:
|
||||
newtitle = title.format(name=figname, number=fignum)
|
||||
else:
|
||||
|
@ -1082,8 +1082,14 @@
|
||||
|
||||
% make commands known to non-Sphinx document classes
|
||||
\providecommand*{\sphinxtableofcontents}{\tableofcontents}
|
||||
\providecommand*{\sphinxthebibliography}{\thebibliography}
|
||||
\providecommand*{\sphinxtheindex}{\theindex}
|
||||
\spx@ifundefined{sphinxthebibliography}
|
||||
{\newenvironment
|
||||
{sphinxthebibliography}{\begin{thebibliography}}{\end{thebibliography}}%
|
||||
}
|
||||
{}% else clause of ifundefined
|
||||
\spx@ifundefined{sphinxtheindex}
|
||||
{\newenvironment{sphinxtheindex}{\begin{theindex}}{\end{theindex}}}%
|
||||
{}% else clause of ifundefined
|
||||
|
||||
% remove LaTeX's cap on nesting depth if 'maxlistdepth' key used.
|
||||
% This is a hack, which works with the standard classes: it assumes \@toodeep
|
||||
|
@ -3,7 +3,7 @@ pytest>=3.0
|
||||
pytest-cov
|
||||
mock
|
||||
six>=1.4
|
||||
Jinja2>=2.3,<2.9
|
||||
Jinja2>=2.3
|
||||
Pygments>=2.0
|
||||
docutils>=0.11
|
||||
snowballstemmer>=1.1
|
||||
|
@ -1,19 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
from collections import namedtuple
|
||||
|
||||
import pytest
|
||||
from six import StringIO
|
||||
from six import StringIO, string_types
|
||||
|
||||
from util import SphinxTestApp, path
|
||||
import util
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app_params(request):
|
||||
def app_params(request, test_params, shared_result):
|
||||
"""
|
||||
parameters that is specified by 'pytest.mark.sphinx' for
|
||||
sphinx.application.Sphinx initialization
|
||||
"""
|
||||
|
||||
# ##### process pytest.mark.sphinx
|
||||
|
||||
markers = request.node.get_marker("sphinx")
|
||||
pargs = {}
|
||||
kwargs = {}
|
||||
@ -26,17 +32,99 @@ def app_params(request):
|
||||
kwargs.update(info.kwargs)
|
||||
|
||||
args = [pargs[i] for i in sorted(pargs.keys())]
|
||||
return args, kwargs
|
||||
|
||||
# ##### process pytest.mark.test_params
|
||||
|
||||
if test_params['shared_result']:
|
||||
if 'srcdir' in kwargs:
|
||||
raise pytest.Exception('You can not spcify shared_result and '
|
||||
'srcdir in same time.')
|
||||
kwargs['srcdir'] = test_params['shared_result']
|
||||
restore = shared_result.restore(test_params['shared_result'])
|
||||
kwargs.update(restore)
|
||||
|
||||
# ##### prepare Application params
|
||||
|
||||
if 'srcdir' in kwargs:
|
||||
srcdir = util.tempdir / kwargs['srcdir']
|
||||
else:
|
||||
srcdir = util.tempdir / kwargs.get('testroot', 'root')
|
||||
kwargs['srcdir'] = srcdir
|
||||
|
||||
if kwargs.get('testroot') is None:
|
||||
testroot_path = util.rootdir / 'root'
|
||||
else:
|
||||
testroot_path = util.rootdir / 'roots' / ('test-' + kwargs['testroot'])
|
||||
|
||||
if not srcdir.exists():
|
||||
testroot_path.copytree(srcdir)
|
||||
|
||||
return namedtuple('app_params', 'args,kwargs')(args, kwargs)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_params(request):
|
||||
"""
|
||||
test parameters that is specified by 'pytest.mark.test_params'
|
||||
|
||||
:param Union[str] shared_result:
|
||||
If the value is provided, app._status and app._warning objects will be
|
||||
shared in the parametrized test functions and/or test functions that
|
||||
have same 'shared_result' value.
|
||||
**NOTE**: You can not specify shared_result and srcdir in same time.
|
||||
"""
|
||||
env = request.node.get_marker('test_params')
|
||||
kwargs = env.kwargs if env else {}
|
||||
result = {
|
||||
'shared_result': None,
|
||||
}
|
||||
result.update(kwargs)
|
||||
|
||||
if (result['shared_result'] and
|
||||
not isinstance(result['shared_result'], string_types)):
|
||||
raise pytest.Exception('You can only provide a string type of value '
|
||||
'for "shared_result" ')
|
||||
return result
|
||||
|
||||
|
||||
class SphinxTestAppWrapperForSkipBuilding(object):
|
||||
"""
|
||||
This class is a wrapper for SphinxTestApp to speed up the test by skipping
|
||||
`app.build` process if it is already built and there is even one output
|
||||
file.
|
||||
"""
|
||||
|
||||
def __init__(self, app_):
|
||||
self.app = app_
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.app, name)
|
||||
|
||||
def build(self, *args, **kw):
|
||||
if not self.app.outdir.listdir():
|
||||
# if listdir is empty, do build.
|
||||
self.app.build(*args, **kw)
|
||||
# otherwise, we can use built cache
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def app(app_params, make_app):
|
||||
def app(test_params, app_params, make_app, shared_result):
|
||||
"""
|
||||
provides sphinx.application.Sphinx object
|
||||
"""
|
||||
args, kwargs = app_params
|
||||
app_ = make_app(*args, **kwargs)
|
||||
return app_
|
||||
yield app_
|
||||
|
||||
print('# testroot:', kwargs.get('testroot', 'root'))
|
||||
print('# builder:', app_.buildername)
|
||||
print('# srcdir:', app_.srcdir)
|
||||
print('# outdir:', app_.outdir)
|
||||
print('# status:', '\n' + app_._status.getvalue())
|
||||
print('# warning:', '\n' + app_._warning.getvalue())
|
||||
|
||||
if test_params['shared_result']:
|
||||
shared_result.store(test_params['shared_result'], app_)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
@ -56,7 +144,7 @@ def warning(app):
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def make_app():
|
||||
def make_app(test_params):
|
||||
"""
|
||||
provides make_app function to initialize SphinxTestApp instance.
|
||||
if you want to initialize 'app' in your test function. please use this
|
||||
@ -69,8 +157,10 @@ def make_app():
|
||||
status, warning = StringIO(), StringIO()
|
||||
kwargs.setdefault('status', status)
|
||||
kwargs.setdefault('warning', warning)
|
||||
app_ = SphinxTestApp(*args, **kwargs)
|
||||
app_ = util.SphinxTestApp(*args, **kwargs)
|
||||
apps.append(app_)
|
||||
if test_params['shared_result']:
|
||||
app_ = SphinxTestAppWrapperForSkipBuilding(app_)
|
||||
return app_
|
||||
yield make
|
||||
|
||||
@ -79,6 +169,38 @@ def make_app():
|
||||
app_.cleanup()
|
||||
|
||||
|
||||
class SharedResult(object):
|
||||
cache = {}
|
||||
|
||||
def store(self, key, app_):
|
||||
if key in self.cache:
|
||||
return
|
||||
data = {
|
||||
'status': app_._status.getvalue(),
|
||||
'warning': app_._warning.getvalue(),
|
||||
}
|
||||
self.cache[key] = data
|
||||
|
||||
def restore(self, key):
|
||||
if key not in self.cache:
|
||||
return {}
|
||||
data = self.cache[key]
|
||||
return {
|
||||
'status': StringIO(data['status']),
|
||||
'warning': StringIO(data['warning']),
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def shared_result():
|
||||
return SharedResult()
|
||||
|
||||
|
||||
@pytest.fixture(scope='module', autouse=True)
|
||||
def _shared_result_cache():
|
||||
SharedResult.cache.clear()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def if_graphviz_found(app):
|
||||
"""
|
||||
@ -105,4 +227,4 @@ def tempdir(tmpdir):
|
||||
temporary directory that wrapped with `path` class.
|
||||
this fixture is for compat with old test implementation.
|
||||
"""
|
||||
return path(tmpdir)
|
||||
return util.path(tmpdir)
|
||||
|
@ -13,7 +13,7 @@
|
||||
# "raises" imported for usage by autodoc
|
||||
import six
|
||||
import sys
|
||||
from util import TestApp, Struct, raises, SkipTest
|
||||
from util import SphinxTestApp, Struct
|
||||
import pytest
|
||||
|
||||
from six import StringIO
|
||||
@ -27,7 +27,7 @@ app = None
|
||||
|
||||
def setup_module():
|
||||
global app
|
||||
app = TestApp()
|
||||
app = SphinxTestApp()
|
||||
app.builder.env.app = app
|
||||
app.builder.env.temp_data['docname'] = 'dummy'
|
||||
app.connect('autodoc-process-docstring', process_docstring)
|
||||
@ -185,7 +185,7 @@ def test_generate():
|
||||
'Class.meth', more_content=add_content)
|
||||
|
||||
# test check_module
|
||||
inst = FunctionDocumenter(directive, 'raises')
|
||||
inst = FunctionDocumenter(directive, 'add_documenter')
|
||||
inst.generate(check_module=True)
|
||||
assert len(directive.result) == 0
|
||||
|
||||
|
10
tests/run.py
10
tests/run.py
@ -17,11 +17,15 @@ import warnings
|
||||
import traceback
|
||||
|
||||
from path import path
|
||||
import pytest
|
||||
|
||||
testroot = os.path.dirname(__file__) or '.'
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(testroot, os.path.pardir)))
|
||||
|
||||
# filter warnings of test dependencies
|
||||
warnings.filterwarnings('ignore', category=DeprecationWarning, module='site') # virtualenv
|
||||
warnings.filterwarnings('ignore', category=ImportWarning, module='backports')
|
||||
warnings.filterwarnings('ignore', category=PendingDeprecationWarning, module=r'_pytest\..*')
|
||||
|
||||
# check dependencies before testing
|
||||
print('Checking dependencies...')
|
||||
for modname in ('pytest', 'mock', 'six', 'docutils', 'jinja2', 'pygments',
|
||||
@ -49,9 +53,6 @@ tempdir.makedirs()
|
||||
print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0])
|
||||
sys.stdout.flush()
|
||||
|
||||
# filter warnings of test dependencies
|
||||
warnings.filterwarnings('ignore', category=DeprecationWarning, module='site') # virtualenv
|
||||
|
||||
# exclude 'root' and 'roots' dirs for pytest test collector
|
||||
ignore_paths = [
|
||||
os.path.relpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), sub))
|
||||
@ -61,4 +62,5 @@ args = sys.argv[1:]
|
||||
for path in ignore_paths:
|
||||
args.extend(['--ignore', path])
|
||||
|
||||
import pytest
|
||||
sys.exit(pytest.main(args))
|
||||
|
@ -10,8 +10,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
# "raises" imported for usage by autodoc
|
||||
from util import TestApp, Struct, raises, SkipTest # NOQA
|
||||
from util import SphinxTestApp, Struct # NOQA
|
||||
import pytest
|
||||
|
||||
import enum
|
||||
@ -26,7 +25,7 @@ app = None
|
||||
|
||||
def setup_module():
|
||||
global app
|
||||
app = TestApp()
|
||||
app = SphinxTestApp()
|
||||
app.builder.env.app = app
|
||||
app.builder.env.temp_data['docname'] = 'dummy'
|
||||
app.connect('autodoc-process-docstring', process_docstring)
|
||||
@ -125,26 +124,27 @@ def test_parse_name():
|
||||
del _warnings[:]
|
||||
|
||||
# for functions/classes
|
||||
verify('function', 'util.raises', ('util', ['raises'], None, None))
|
||||
verify('function', 'util.raises(exc) -> None',
|
||||
('util', ['raises'], 'exc', 'None'))
|
||||
directive.env.temp_data['autodoc:module'] = 'util'
|
||||
verify('function', 'raises', ('util', ['raises'], None, None))
|
||||
verify('function', 'test_autodoc.raises',
|
||||
('test_autodoc', ['raises'], None, None))
|
||||
verify('function', 'test_autodoc.raises(exc) -> None',
|
||||
('test_autodoc', ['raises'], 'exc', 'None'))
|
||||
directive.env.temp_data['autodoc:module'] = 'test_autodoc'
|
||||
verify('function', 'raises', ('test_autodoc', ['raises'], None, None))
|
||||
del directive.env.temp_data['autodoc:module']
|
||||
directive.env.ref_context['py:module'] = 'util'
|
||||
verify('function', 'raises', ('util', ['raises'], None, None))
|
||||
verify('class', 'TestApp', ('util', ['TestApp'], None, None))
|
||||
directive.env.ref_context['py:module'] = 'test_autodoc'
|
||||
verify('function', 'raises', ('test_autodoc', ['raises'], None, None))
|
||||
verify('class', 'Base', ('test_autodoc', ['Base'], None, None))
|
||||
|
||||
# for members
|
||||
directive.env.ref_context['py:module'] = 'foo'
|
||||
verify('method', 'util.TestApp.cleanup',
|
||||
('util', ['TestApp', 'cleanup'], None, None))
|
||||
verify('method', 'util.SphinxTestApp.cleanup',
|
||||
('util', ['SphinxTestApp', 'cleanup'], None, None))
|
||||
directive.env.ref_context['py:module'] = 'util'
|
||||
directive.env.ref_context['py:class'] = 'Foo'
|
||||
directive.env.temp_data['autodoc:class'] = 'TestApp'
|
||||
verify('method', 'cleanup', ('util', ['TestApp', 'cleanup'], None, None))
|
||||
verify('method', 'TestApp.cleanup',
|
||||
('util', ['TestApp', 'cleanup'], None, None))
|
||||
directive.env.temp_data['autodoc:class'] = 'SphinxTestApp'
|
||||
verify('method', 'cleanup', ('util', ['SphinxTestApp', 'cleanup'], None, None))
|
||||
verify('method', 'SphinxTestApp.cleanup',
|
||||
('util', ['SphinxTestApp', 'cleanup'], None, None))
|
||||
|
||||
# and clean up
|
||||
del directive.env.ref_context['py:module']
|
||||
@ -658,7 +658,7 @@ def test_generate():
|
||||
'Class.meth', more_content=add_content)
|
||||
|
||||
# test check_module
|
||||
inst = FunctionDocumenter(directive, 'raises')
|
||||
inst = FunctionDocumenter(directive, 'add_documenter')
|
||||
inst.generate(check_module=True)
|
||||
assert len(directive.result) == 0
|
||||
|
||||
@ -878,6 +878,11 @@ __all__ = ['Class']
|
||||
integer = 1
|
||||
|
||||
|
||||
def raises(exc, func, *args, **kwds):
|
||||
"""Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*."""
|
||||
pass
|
||||
|
||||
|
||||
class CustomEx(Exception):
|
||||
"""My custom exception."""
|
||||
|
||||
@ -1086,7 +1091,7 @@ def test_type_hints():
|
||||
try:
|
||||
from typing_test_data import f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11
|
||||
except (ImportError, SyntaxError):
|
||||
raise SkipTest('Cannot import Python code with function annotations')
|
||||
pytest.skip('Cannot import Python code with function annotations')
|
||||
|
||||
def verify_arg_spec(f, expected):
|
||||
assert formatargspec(f, *getargspec(f)) == expected
|
||||
|
@ -15,14 +15,8 @@ import mock
|
||||
import pytest
|
||||
from textwrap import dedent
|
||||
from sphinx.errors import SphinxError
|
||||
import sphinx.builders.linkcheck
|
||||
|
||||
from util import rootdir, tempdir, SkipTest, TestApp, path
|
||||
|
||||
try:
|
||||
from docutils.writers.manpage import Writer as ManWriter
|
||||
except ImportError:
|
||||
ManWriter = None
|
||||
from util import rootdir, tempdir, path
|
||||
|
||||
|
||||
def request_session_head(url, **kwargs):
|
||||
@ -32,24 +26,17 @@ def request_session_head(url, **kwargs):
|
||||
return response
|
||||
|
||||
|
||||
def verify_build(buildername, srcdir):
|
||||
if buildername == 'man' and ManWriter is None:
|
||||
raise SkipTest('man writer is not available')
|
||||
app = TestApp(buildername=buildername, srcdir=srcdir)
|
||||
try:
|
||||
app.builder.build_all()
|
||||
finally:
|
||||
app.cleanup()
|
||||
|
||||
|
||||
def test_build_all():
|
||||
@pytest.fixture
|
||||
def nonascii_srcdir(request):
|
||||
# If supported, build in a non-ASCII source dir
|
||||
test_name = u'\u65e5\u672c\u8a9e'
|
||||
basedir = tempdir / request.node.originalname
|
||||
try:
|
||||
srcdir = tempdir / test_name
|
||||
(rootdir / 'root').copytree(tempdir / test_name)
|
||||
srcdir = basedir / test_name
|
||||
if not srcdir.exists():
|
||||
(rootdir / 'root').copytree(srcdir)
|
||||
except UnicodeEncodeError:
|
||||
srcdir = tempdir / 'all'
|
||||
srcdir = basedir / 'all'
|
||||
else:
|
||||
# add a doc with a non-ASCII file name to the source dir
|
||||
(srcdir / (test_name + '.txt')).write_text(dedent("""
|
||||
@ -63,31 +50,33 @@ def test_build_all():
|
||||
|
||||
%(test_name)s/%(test_name)s
|
||||
""" % {'test_name': test_name})
|
||||
)
|
||||
)
|
||||
return srcdir
|
||||
|
||||
with mock.patch('sphinx.builders.linkcheck.requests') as requests:
|
||||
requests.head = request_session_head
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"buildername",
|
||||
[
|
||||
# note: no 'html' - if it's ok with dirhtml it's ok with html
|
||||
for buildername in ['dirhtml', 'singlehtml', 'latex', 'texinfo', 'pickle',
|
||||
'json', 'text', 'htmlhelp', 'qthelp', 'epub2', 'epub',
|
||||
'applehelp', 'changes', 'xml', 'pseudoxml', 'man',
|
||||
'linkcheck']:
|
||||
yield verify_build, buildername, srcdir
|
||||
'dirhtml', 'singlehtml', 'latex', 'texinfo', 'pickle', 'json', 'text',
|
||||
'htmlhelp', 'qthelp', 'epub2', 'epub', 'applehelp', 'changes', 'xml',
|
||||
'pseudoxml', 'man', 'linkcheck',
|
||||
],
|
||||
)
|
||||
@mock.patch('sphinx.builders.linkcheck.requests.head',
|
||||
side_effect=request_session_head)
|
||||
def test_build_all(requests_head, make_app, nonascii_srcdir, buildername):
|
||||
app = make_app(buildername, srcdir=nonascii_srcdir)
|
||||
app.build()
|
||||
|
||||
|
||||
def test_master_doc_not_found(tempdir):
|
||||
def test_master_doc_not_found(tempdir, make_app):
|
||||
(tempdir / 'conf.py').write_text('master_doc = "index"')
|
||||
assert tempdir.listdir() == ['conf.py']
|
||||
|
||||
try:
|
||||
app = TestApp(buildername='dummy', srcdir=tempdir)
|
||||
app = make_app('dummy', srcdir=tempdir)
|
||||
with pytest.raises(SphinxError):
|
||||
app.builder.build_all()
|
||||
assert False # SphinxError not raised
|
||||
except Exception as exc:
|
||||
assert isinstance(exc, SphinxError)
|
||||
finally:
|
||||
app.cleanup()
|
||||
|
||||
|
||||
@pytest.mark.sphinx(buildername='text', testroot='circular')
|
||||
|
@ -17,36 +17,36 @@ from subprocess import Popen, PIPE
|
||||
|
||||
import pytest
|
||||
|
||||
from util import (
|
||||
gen_with_app, SkipTest, assert_in, assert_true, assert_equal
|
||||
)
|
||||
from sphinx.util.osutil import cd
|
||||
|
||||
|
||||
@gen_with_app('gettext', srcdir='root-gettext')
|
||||
def test_all(app, status, warning):
|
||||
@pytest.mark.sphinx('gettext', srcdir='root-gettext')
|
||||
def test_build_gettext(app):
|
||||
# Generic build; should fail only when the builder is horribly broken.
|
||||
app.builder.build_all()
|
||||
|
||||
# Do messages end up in the correct location?
|
||||
# top-level documents end up in a message catalog
|
||||
yield assert_true, (app.outdir / 'extapi.pot').isfile()
|
||||
assert (app.outdir / 'extapi.pot').isfile()
|
||||
# directory items are grouped into sections
|
||||
yield assert_true, (app.outdir / 'subdir.pot').isfile()
|
||||
assert (app.outdir / 'subdir.pot').isfile()
|
||||
|
||||
# regression test for issue #960
|
||||
catalog = (app.outdir / 'markup.pot').text(encoding='utf-8')
|
||||
yield assert_in, 'msgid "something, something else, something more"', catalog
|
||||
assert 'msgid "something, something else, something more"' in catalog
|
||||
|
||||
|
||||
@pytest.mark.sphinx('gettext', srcdir='root-gettext')
|
||||
def test_msgfmt(app):
|
||||
app.builder.build_all()
|
||||
(app.outdir / 'en' / 'LC_MESSAGES').makedirs()
|
||||
cwd = os.getcwd()
|
||||
os.chdir(app.outdir)
|
||||
try:
|
||||
with cd(app.outdir):
|
||||
try:
|
||||
p = Popen(['msginit', '--no-translator', '-i', 'markup.pot',
|
||||
'--locale', 'en_US'],
|
||||
stdout=PIPE, stderr=PIPE)
|
||||
except OSError:
|
||||
raise SkipTest # most likely msginit was not found
|
||||
pytest.skip() # most likely msginit was not found
|
||||
else:
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
@ -54,13 +54,13 @@ def test_all(app, status, warning):
|
||||
print(stderr)
|
||||
assert False, 'msginit exited with return code %s' % \
|
||||
p.returncode
|
||||
yield assert_true, (app.outdir / 'en_US.po').isfile(), 'msginit failed'
|
||||
assert (app.outdir / 'en_US.po').isfile(), 'msginit failed'
|
||||
try:
|
||||
p = Popen(['msgfmt', 'en_US.po', '-o',
|
||||
os.path.join('en', 'LC_MESSAGES', 'test_root.mo')],
|
||||
stdout=PIPE, stderr=PIPE)
|
||||
except OSError:
|
||||
raise SkipTest # most likely msgfmt was not found
|
||||
pytest.skip() # most likely msgfmt was not found
|
||||
else:
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
@ -68,20 +68,17 @@ def test_all(app, status, warning):
|
||||
print(stderr)
|
||||
assert False, 'msgfmt exited with return code %s' % \
|
||||
p.returncode
|
||||
yield (assert_true,
|
||||
(app.outdir / 'en' / 'LC_MESSAGES' / 'test_root.mo').isfile(),
|
||||
'msgfmt failed')
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
mo = app.outdir / 'en' / 'LC_MESSAGES' / 'test_root.mo'
|
||||
assert mo.isfile(), 'msgfmt failed'
|
||||
|
||||
_ = gettext.translation('test_root', app.outdir, languages=['en']).gettext
|
||||
yield assert_equal, _("Testing various markup"), u"Testing various markup"
|
||||
assert _("Testing various markup") == u"Testing various markup"
|
||||
|
||||
|
||||
@pytest.mark.sphinx(
|
||||
'gettext', testroot='intl', srcdir='gettext',
|
||||
confoverrides={'gettext_compact': False})
|
||||
def test_gettext_index_entries(app, status, warning):
|
||||
def test_gettext_index_entries(app):
|
||||
# regression test for #976
|
||||
app.builder.build(['index_entries'])
|
||||
|
||||
@ -128,8 +125,9 @@ def test_gettext_index_entries(app, status, warning):
|
||||
|
||||
@pytest.mark.sphinx(
|
||||
'gettext', testroot='intl', srcdir='gettext',
|
||||
confoverrides={'gettext_compact': False, 'gettext_additional_targets': []})
|
||||
def test_gettext_disable_index_entries(app, status, warning):
|
||||
confoverrides={'gettext_compact': False,
|
||||
'gettext_additional_targets': []})
|
||||
def test_gettext_disable_index_entries(app):
|
||||
# regression test for #976
|
||||
app.builder.build(['index_entries'])
|
||||
|
||||
@ -160,7 +158,7 @@ def test_gettext_disable_index_entries(app, status, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx('gettext', testroot='intl', srcdir='gettext')
|
||||
def test_gettext_template(app, status, warning):
|
||||
def test_gettext_template(app):
|
||||
app.builder.build_all()
|
||||
assert (app.outdir / 'sphinx.pot').isfile()
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,9 +13,6 @@ from six import PY3, iteritems
|
||||
import pytest
|
||||
import mock
|
||||
|
||||
from util import TestApp, gen_with_app, \
|
||||
assert_in, assert_not_in
|
||||
|
||||
import sphinx
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import ExtensionError, ConfigError, VersionRequirementError
|
||||
@ -76,7 +73,6 @@ def test_core_config(app, status, warning):
|
||||
assert cfg['project'] == cfg.project == 'Sphinx Tests'
|
||||
|
||||
|
||||
@pytest.mark.sphinx()
|
||||
def test_extension_values(app, status, warning):
|
||||
cfg = app.config
|
||||
|
||||
@ -125,39 +121,39 @@ def test_errors_warnings(logger, tempdir):
|
||||
assert logger.warning.called is True
|
||||
|
||||
|
||||
def test_errors_if_setup_is_not_callable(tempdir):
|
||||
def test_errors_if_setup_is_not_callable(tempdir, make_app):
|
||||
# test the error to call setup() in the config file
|
||||
(tempdir / 'conf.py').write_text(u'setup = 1')
|
||||
with pytest.raises(ConfigError) as excinfo:
|
||||
TestApp(srcdir=tempdir)
|
||||
make_app(srcdir=tempdir)
|
||||
assert 'callable' in str(excinfo.value)
|
||||
|
||||
|
||||
@mock.patch.object(sphinx, '__display_version__', '1.3.4')
|
||||
def test_needs_sphinx():
|
||||
def test_needs_sphinx(make_app):
|
||||
# micro version
|
||||
app = TestApp(confoverrides={'needs_sphinx': '1.3.3'}) # OK: less
|
||||
app = make_app(confoverrides={'needs_sphinx': '1.3.3'}) # OK: less
|
||||
app.cleanup()
|
||||
app = TestApp(confoverrides={'needs_sphinx': '1.3.4'}) # OK: equals
|
||||
app = make_app(confoverrides={'needs_sphinx': '1.3.4'}) # OK: equals
|
||||
app.cleanup()
|
||||
with pytest.raises(VersionRequirementError):
|
||||
TestApp(confoverrides={'needs_sphinx': '1.3.5'}) # NG: greater
|
||||
make_app(confoverrides={'needs_sphinx': '1.3.5'}) # NG: greater
|
||||
|
||||
# minor version
|
||||
app = TestApp(confoverrides={'needs_sphinx': '1.2'}) # OK: less
|
||||
app = make_app(confoverrides={'needs_sphinx': '1.2'}) # OK: less
|
||||
app.cleanup()
|
||||
app = TestApp(confoverrides={'needs_sphinx': '1.3'}) # OK: equals
|
||||
app = make_app(confoverrides={'needs_sphinx': '1.3'}) # OK: equals
|
||||
app.cleanup()
|
||||
with pytest.raises(VersionRequirementError):
|
||||
TestApp(confoverrides={'needs_sphinx': '1.4'}) # NG: greater
|
||||
make_app(confoverrides={'needs_sphinx': '1.4'}) # NG: greater
|
||||
|
||||
# major version
|
||||
app = TestApp(confoverrides={'needs_sphinx': '0'}) # OK: less
|
||||
app = make_app(confoverrides={'needs_sphinx': '0'}) # OK: less
|
||||
app.cleanup()
|
||||
app = TestApp(confoverrides={'needs_sphinx': '1'}) # OK: equals
|
||||
app = make_app(confoverrides={'needs_sphinx': '1'}) # OK: equals
|
||||
app.cleanup()
|
||||
with pytest.raises(VersionRequirementError):
|
||||
TestApp(confoverrides={'needs_sphinx': '2'}) # NG: greater
|
||||
make_app(confoverrides={'needs_sphinx': '2'}) # NG: greater
|
||||
|
||||
|
||||
@mock.patch("sphinx.config.logger")
|
||||
@ -177,12 +173,14 @@ def test_config_eol(logger, tempdir):
|
||||
'primary_domain': None})
|
||||
def test_builtin_conf(app, status, warning):
|
||||
warnings = warning.getvalue()
|
||||
assert_in('master_doc', warnings,
|
||||
'override on builtin "master_doc" should raise a type warning')
|
||||
assert_not_in('language', warnings, 'explicitly permitted '
|
||||
'override on builtin "language" should NOT raise a type warning')
|
||||
assert_not_in('primary_domain', warnings, 'override to None on builtin '
|
||||
'"primary_domain" should NOT raise a type warning')
|
||||
assert 'master_doc' in warnings, (
|
||||
'override on builtin "master_doc" should raise a type warning')
|
||||
assert 'language' not in warnings, (
|
||||
'explicitly permitted override on builtin "language" should NOT raise '
|
||||
'a type warning')
|
||||
assert 'primary_domain' not in warnings, (
|
||||
'override to None on builtin "primary_domain" should NOT raise a type '
|
||||
'warning')
|
||||
|
||||
|
||||
# See roots/test-config/conf.py.
|
||||
@ -197,7 +195,7 @@ TYPECHECK_WARNINGS = {
|
||||
'value8': False,
|
||||
'value9': False,
|
||||
'value10': False,
|
||||
'value11': True,
|
||||
'value11': False if PY3 else True,
|
||||
'value12': False,
|
||||
'value13': False,
|
||||
'value14': False,
|
||||
@ -206,15 +204,17 @@ TYPECHECK_WARNINGS = {
|
||||
}
|
||||
|
||||
|
||||
@gen_with_app(testroot='config')
|
||||
def test_gen_check_types(app, status, warning):
|
||||
if PY3:
|
||||
TYPECHECK_WARNINGS['value11'] = False
|
||||
|
||||
for key, should in iteritems(TYPECHECK_WARNINGS):
|
||||
yield assert_in if should else assert_not_in, key, warning.getvalue(), (
|
||||
'override on "%s" should%s raise a type warning' %
|
||||
(key, '' if should else ' NOT')
|
||||
@pytest.mark.parametrize("key,should", iteritems(TYPECHECK_WARNINGS))
|
||||
@pytest.mark.sphinx(testroot='config')
|
||||
def test_check_types(warning, key, should):
|
||||
warn = warning.getvalue()
|
||||
if should:
|
||||
assert key in warn, (
|
||||
'override on "%s" should raise a type warning' % key
|
||||
)
|
||||
else:
|
||||
assert key not in warn, (
|
||||
'override on "%s" should NOT raise a type warning' % key
|
||||
)
|
||||
|
||||
|
||||
|
@ -8,42 +8,30 @@
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import os
|
||||
|
||||
from util import TestApp
|
||||
import pytest
|
||||
|
||||
|
||||
def test_correct_year():
|
||||
try:
|
||||
# save current value of SOURCE_DATE_EPOCH
|
||||
sde = os.environ.pop('SOURCE_DATE_EPOCH', None)
|
||||
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
# test with SOURCE_DATE_EPOCH unset: no modification
|
||||
app = TestApp(buildername='html', testroot='correct-year')
|
||||
app.builder.build_all()
|
||||
content = (app.outdir / 'contents.html').text()
|
||||
app.cleanup()
|
||||
assert '2006-2009' in content
|
||||
(None, '2006-2009'),
|
||||
# test with SOURCE_DATE_EPOCH set: copyright year should be updated
|
||||
('1293840000', '2006-2011'),
|
||||
('1293839999', '2006-2010'),
|
||||
],
|
||||
|
||||
# test with SOURCE_DATE_EPOCH set: copyright year should be
|
||||
# updated
|
||||
os.environ['SOURCE_DATE_EPOCH'] = "1293840000"
|
||||
app = TestApp(buildername='html', testroot='correct-year')
|
||||
app.builder.build_all()
|
||||
content = (app.outdir / 'contents.html').text()
|
||||
app.cleanup()
|
||||
assert '2006-2011' in content
|
||||
)
|
||||
def expect_date(request, monkeypatch):
|
||||
sde, expect = request.param
|
||||
if sde:
|
||||
monkeypatch.setenv('SOURCE_DATE_EPOCH', sde)
|
||||
else:
|
||||
monkeypatch.delenv('SOURCE_DATE_EPOCH', raising=False)
|
||||
yield expect
|
||||
|
||||
os.environ['SOURCE_DATE_EPOCH'] = "1293839999"
|
||||
app = TestApp(buildername='html', testroot='correct-year')
|
||||
app.builder.build_all()
|
||||
content = (app.outdir / 'contents.html').text()
|
||||
app.cleanup()
|
||||
assert '2006-2010' in content
|
||||
|
||||
finally:
|
||||
# Restores SOURCE_DATE_EPOCH
|
||||
if sde is None:
|
||||
os.environ.pop('SOURCE_DATE_EPOCH', None)
|
||||
else:
|
||||
os.environ['SOURCE_DATE_EPOCH'] = sde
|
||||
@pytest.mark.sphinx('html', testroot='correct-year')
|
||||
def test_correct_year(expect_date, app):
|
||||
app.build()
|
||||
content = (app.outdir / 'contents.html').text()
|
||||
assert expect_date in content
|
||||
|
@ -9,9 +9,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from six import StringIO
|
||||
|
||||
from util import TestApp, path
|
||||
from util import SphinxTestApp, path
|
||||
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.builders.latex import LaTeXBuilder
|
||||
@ -21,7 +19,7 @@ app = env = None
|
||||
|
||||
def setup_module():
|
||||
global app, env
|
||||
app = TestApp(srcdir='root-envtest', warning=StringIO())
|
||||
app = SphinxTestApp(srcdir='root-envtest')
|
||||
env = app.env
|
||||
|
||||
|
||||
|
@ -16,23 +16,13 @@ from sphinx.addnodes import compact_paragraph, only
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
import pytest
|
||||
|
||||
from util import gen_with_app, assert_node
|
||||
from util import assert_node
|
||||
|
||||
|
||||
@gen_with_app('xml', testroot='toctree')
|
||||
def test_basic(app, status, warning):
|
||||
@pytest.mark.sphinx('xml', testroot='toctree')
|
||||
@pytest.mark.test_params(shared_result='test_environment_toctree_basic')
|
||||
def test_process_doc(app):
|
||||
app.build()
|
||||
yield _test_process_doc, app
|
||||
yield _test_get_toc_for, app
|
||||
yield _test_get_toc_for_only, app
|
||||
yield _test_get_toc_for_tocdepth, app
|
||||
yield _test_get_toctree_for, app
|
||||
yield _test_get_toctree_for_collapse, app
|
||||
yield _test_get_toctree_for_maxdepth, app
|
||||
yield _test_get_toctree_for_includehidden, app
|
||||
|
||||
|
||||
def _test_process_doc(app):
|
||||
# tocs
|
||||
toctree = app.env.tocs['index']
|
||||
assert_node(toctree,
|
||||
@ -99,7 +89,7 @@ def _test_process_doc(app):
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='toctree-glob')
|
||||
def test_glob(app, status, warning):
|
||||
def test_glob(app):
|
||||
includefiles = ['foo', 'bar/index', 'bar/bar_1', 'bar/bar_2',
|
||||
'bar/bar_3', 'baz', 'qux/index']
|
||||
|
||||
@ -144,7 +134,10 @@ def test_glob(app, status, warning):
|
||||
assert app.env.numbered_toctrees == set()
|
||||
|
||||
|
||||
def _test_get_toc_for(app):
|
||||
@pytest.mark.sphinx('xml', testroot='toctree')
|
||||
@pytest.mark.test_params(shared_result='test_environment_toctree_basic')
|
||||
def test_get_toc_for(app):
|
||||
app.build()
|
||||
toctree = app.env.get_toc_for('index', app.builder)
|
||||
|
||||
assert_node(toctree,
|
||||
@ -167,7 +160,10 @@ def _test_get_toc_for(app):
|
||||
[compact_paragraph, reference, "Indices and tables"])
|
||||
|
||||
|
||||
def _test_get_toc_for_only(app):
|
||||
@pytest.mark.sphinx('xml', testroot='toctree')
|
||||
@pytest.mark.test_params(shared_result='test_environment_toctree_basic')
|
||||
def test_get_toc_for_only(app):
|
||||
app.build()
|
||||
builder = StandaloneHTMLBuilder(app)
|
||||
toctree = app.env.get_toc_for('index', builder)
|
||||
|
||||
@ -194,7 +190,10 @@ def _test_get_toc_for_only(app):
|
||||
[compact_paragraph, reference, "Indices and tables"])
|
||||
|
||||
|
||||
def _test_get_toc_for_tocdepth(app):
|
||||
@pytest.mark.sphinx('xml', testroot='toctree')
|
||||
@pytest.mark.test_params(shared_result='test_environment_toctree_basic')
|
||||
def test_get_toc_for_tocdepth(app):
|
||||
app.build()
|
||||
toctree = app.env.get_toc_for('tocdepth', app.builder)
|
||||
|
||||
assert_node(toctree,
|
||||
@ -206,7 +205,10 @@ def _test_get_toc_for_tocdepth(app):
|
||||
[bullet_list, list_item, compact_paragraph, reference, "level 2"])
|
||||
|
||||
|
||||
def _test_get_toctree_for(app):
|
||||
@pytest.mark.sphinx('xml', testroot='toctree')
|
||||
@pytest.mark.test_params(shared_result='test_environment_toctree_basic')
|
||||
def test_get_toctree_for(app):
|
||||
app.build()
|
||||
toctree = app.env.get_toctree_for('index', app.builder, collapse=False)
|
||||
assert_node(toctree,
|
||||
[compact_paragraph, ([caption, "Table of Contents"],
|
||||
@ -240,7 +242,10 @@ def _test_get_toctree_for(app):
|
||||
assert_node(toctree[3][1][0][0], reference, refuri="http://python.org/")
|
||||
|
||||
|
||||
def _test_get_toctree_for_collapse(app):
|
||||
@pytest.mark.sphinx('xml', testroot='toctree')
|
||||
@pytest.mark.test_params(shared_result='test_environment_toctree_basic')
|
||||
def test_get_toctree_for_collapse(app):
|
||||
app.build()
|
||||
toctree = app.env.get_toctree_for('index', app.builder, collapse=True)
|
||||
assert_node(toctree,
|
||||
[compact_paragraph, ([caption, "Table of Contents"],
|
||||
@ -265,7 +270,10 @@ def _test_get_toctree_for_collapse(app):
|
||||
assert_node(toctree[3][1][0][0], reference, refuri="http://python.org/")
|
||||
|
||||
|
||||
def _test_get_toctree_for_maxdepth(app):
|
||||
@pytest.mark.sphinx('xml', testroot='toctree')
|
||||
@pytest.mark.test_params(shared_result='test_environment_toctree_basic')
|
||||
def test_get_toctree_for_maxdepth(app):
|
||||
app.build()
|
||||
toctree = app.env.get_toctree_for('index', app.builder, collapse=False, maxdepth=3)
|
||||
assert_node(toctree,
|
||||
[compact_paragraph, ([caption, "Table of Contents"],
|
||||
@ -304,7 +312,10 @@ def _test_get_toctree_for_maxdepth(app):
|
||||
assert_node(toctree[3][1][0][0], reference, refuri="http://python.org/")
|
||||
|
||||
|
||||
def _test_get_toctree_for_includehidden(app):
|
||||
@pytest.mark.sphinx('xml', testroot='toctree')
|
||||
@pytest.mark.test_params(shared_result='test_environment_toctree_basic')
|
||||
def test_get_toctree_for_includehidden(app):
|
||||
app.build()
|
||||
toctree = app.env.get_toctree_for('index', app.builder, collapse=False,
|
||||
includehidden=False)
|
||||
assert_node(toctree,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ import re
|
||||
import pickle
|
||||
|
||||
from docutils import frontend, utils, nodes
|
||||
from docutils.parsers import rst
|
||||
from docutils.parsers.rst import Parser as RstParser
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util import texescape
|
||||
@ -22,31 +22,37 @@ from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator
|
||||
from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator
|
||||
import pytest
|
||||
|
||||
from util import TestApp, assert_node
|
||||
from util import assert_node
|
||||
|
||||
|
||||
app = settings = parser = domain_context = None
|
||||
|
||||
|
||||
def setup_module():
|
||||
global app, settings, parser, domain_context
|
||||
@pytest.fixture
|
||||
def settings(app):
|
||||
texescape.init() # otherwise done by the latex builder
|
||||
app = TestApp()
|
||||
optparser = frontend.OptionParser(
|
||||
components=(rst.Parser, HTMLWriter, LaTeXWriter))
|
||||
components=(RstParser, HTMLWriter, LaTeXWriter))
|
||||
settings = optparser.get_default_values()
|
||||
settings.env = app.builder.env
|
||||
settings.env.temp_data['docname'] = 'dummy'
|
||||
parser = rst.Parser()
|
||||
domain_context = sphinx_domains(settings.env)
|
||||
domain_context.enable()
|
||||
|
||||
|
||||
def teardown_module():
|
||||
app.cleanup()
|
||||
yield settings
|
||||
domain_context.disable()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def parse(settings):
|
||||
def parse_(rst):
|
||||
document = utils.new_document(b'test data', settings)
|
||||
document['file'] = 'dummy'
|
||||
parser = RstParser()
|
||||
parser.parse(rst, document)
|
||||
for msg in document.traverse(nodes.system_message):
|
||||
if msg['level'] == 1:
|
||||
msg.replace_self([])
|
||||
return document
|
||||
return parse_
|
||||
|
||||
|
||||
# since we're not resolving the markup afterwards, these nodes may remain
|
||||
class ForgivingTranslator:
|
||||
def visit_pending_xref(self, node):
|
||||
@ -64,93 +70,158 @@ class ForgivingLaTeXTranslator(LaTeXTranslator, ForgivingTranslator):
|
||||
pass
|
||||
|
||||
|
||||
def verify_re(rst, html_expected, latex_expected):
|
||||
document = utils.new_document(b'test data', settings)
|
||||
document['file'] = 'dummy'
|
||||
parser.parse(rst, document)
|
||||
for msg in document.traverse(nodes.system_message):
|
||||
if msg['level'] == 1:
|
||||
msg.replace_self([])
|
||||
|
||||
if html_expected:
|
||||
@pytest.fixture
|
||||
def verify_re_html(app, parse):
|
||||
def verify(rst, html_expected):
|
||||
document = parse(rst)
|
||||
html_translator = ForgivingHTMLTranslator(app.builder, document)
|
||||
document.walkabout(html_translator)
|
||||
html_translated = ''.join(html_translator.fragment).strip()
|
||||
assert re.match(html_expected, html_translated), 'from ' + rst
|
||||
return verify
|
||||
|
||||
if latex_expected:
|
||||
|
||||
@pytest.fixture
|
||||
def verify_re_latex(app, parse):
|
||||
def verify(rst, latex_expected):
|
||||
document = parse(rst)
|
||||
latex_translator = ForgivingLaTeXTranslator(document, app.builder)
|
||||
latex_translator.first_document = -1 # don't write \begin{document}
|
||||
document.walkabout(latex_translator)
|
||||
latex_translated = ''.join(latex_translator.body).strip()
|
||||
assert re.match(latex_expected, latex_translated), 'from ' + repr(rst)
|
||||
return verify
|
||||
|
||||
|
||||
def verify(rst, html_expected, latex_expected):
|
||||
if html_expected:
|
||||
html_expected = re.escape(html_expected) + '$'
|
||||
if latex_expected:
|
||||
latex_expected = re.escape(latex_expected) + '$'
|
||||
verify_re(rst, html_expected, latex_expected)
|
||||
@pytest.fixture
|
||||
def verify_re(verify_re_html, verify_re_latex):
|
||||
def verify_re_(rst, html_expected, latex_expected):
|
||||
if html_expected:
|
||||
return verify_re_html(rst, html_expected)
|
||||
if latex_expected:
|
||||
return verify_re_latex(rst, latex_expected)
|
||||
return verify_re_
|
||||
|
||||
|
||||
def test_inline():
|
||||
# correct interpretation of code with whitespace
|
||||
_html = ('<p><code class="(samp )?docutils literal"><span class="pre">'
|
||||
'code</span>   <span class="pre">sample</span></code></p>')
|
||||
yield verify_re, '``code sample``', _html, r'\\sphinxcode{code sample}'
|
||||
yield verify_re, ':samp:`code sample`', _html, r'\\sphinxcode{code sample}'
|
||||
|
||||
# interpolation of braces in samp and file roles (HTML only)
|
||||
yield (verify, ':samp:`a{b}c`',
|
||||
'<p><code class="samp docutils literal"><span class="pre">a</span>'
|
||||
'<em><span class="pre">b</span></em>'
|
||||
'<span class="pre">c</span></code></p>',
|
||||
'\\sphinxcode{a\\sphinxstyleemphasis{b}c}')
|
||||
|
||||
# interpolation of arrows in menuselection
|
||||
yield (verify, ':menuselection:`a --> b`',
|
||||
u'<p><span class="menuselection">a \N{TRIANGULAR BULLET} b</span></p>',
|
||||
'\\sphinxmenuselection{a \\(\\rightarrow\\) b}')
|
||||
|
||||
# interpolation of ampersands in guilabel/menuselection
|
||||
yield (verify, ':guilabel:`&Foo -&&- &Bar`',
|
||||
u'<p><span class="guilabel"><span class="accelerator">F</span>oo '
|
||||
'-&- <span class="accelerator">B</span>ar</span></p>',
|
||||
r'\sphinxmenuselection{\sphinxaccelerator{F}oo -\&- \sphinxaccelerator{B}ar}')
|
||||
|
||||
# non-interpolation of dashes in option role
|
||||
yield (verify_re, ':option:`--with-option`',
|
||||
'<p><code( class="xref std std-option docutils literal")?>'
|
||||
'<span class="pre">--with-option</span></code></p>$',
|
||||
r'\\sphinxcode{-{-}with-option}$')
|
||||
|
||||
# verify smarty-pants quotes
|
||||
yield verify, '"John"', '<p>“John”</p>', "``John''"
|
||||
# ... but not in literal text
|
||||
yield (verify, '``"John"``',
|
||||
'<p><code class="docutils literal"><span class="pre">'
|
||||
'"John"</span></code></p>',
|
||||
'\\sphinxcode{"John"}')
|
||||
|
||||
# verify classes for inline roles
|
||||
yield (verify, ':manpage:`mp(1)`',
|
||||
'<p><em class="manpage">mp(1)</em></p>',
|
||||
'\\sphinxstyleliteralemphasis{mp(1)}')
|
||||
@pytest.fixture
|
||||
def verify(verify_re_html, verify_re_latex):
|
||||
def verify_(rst, html_expected, latex_expected):
|
||||
if html_expected:
|
||||
return verify_re_html(rst, re.escape(html_expected) + '$')
|
||||
if latex_expected:
|
||||
return verify_re_latex(rst, re.escape(latex_expected) + '$')
|
||||
return verify_
|
||||
|
||||
|
||||
def test_latex_escaping():
|
||||
# correct escaping in normal mode
|
||||
yield (verify, u'Γ\\\\∞$', None,
|
||||
r'\(\Gamma\)\textbackslash{}\(\infty\)\$')
|
||||
# in verbatim code fragments
|
||||
yield (verify, u'::\n\n @Γ\\∞${}', None,
|
||||
u'\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]\n'
|
||||
u'@\\(\\Gamma\\)\\PYGZbs{}\\(\\infty\\)\\PYGZdl{}\\PYGZob{}\\PYGZcb{}\n'
|
||||
u'\\end{sphinxVerbatim}')
|
||||
# in URIs
|
||||
yield (verify_re, u'`test <http://example.com/~me/>`_', None,
|
||||
r'\\href{http://example.com/~me/}{test}.*')
|
||||
@pytest.fixture
|
||||
def get_verifier(verify, verify_re):
|
||||
v = {
|
||||
'verify': verify,
|
||||
'verify_re': verify_re,
|
||||
}
|
||||
def get(name):
|
||||
return v[name]
|
||||
return get
|
||||
|
||||
|
||||
@pytest.mark.parametrize('type,rst,html_expected,latex_expected', [
|
||||
(
|
||||
# correct interpretation of code with whitespace
|
||||
'verify_re',
|
||||
'``code sample``',
|
||||
('<p><code class="(samp )?docutils literal"><span class="pre">'
|
||||
'code</span>   <span class="pre">sample</span></code></p>'),
|
||||
r'\\sphinxcode{code sample}',
|
||||
),
|
||||
(
|
||||
# correct interpretation of code with whitespace
|
||||
'verify_re',
|
||||
':samp:`code sample`',
|
||||
('<p><code class="(samp )?docutils literal"><span class="pre">'
|
||||
'code</span>   <span class="pre">sample</span></code></p>'),
|
||||
r'\\sphinxcode{code sample}',
|
||||
),
|
||||
(
|
||||
# interpolation of braces in samp and file roles (HTML only)
|
||||
'verify',
|
||||
':samp:`a{b}c`',
|
||||
('<p><code class="samp docutils literal"><span class="pre">a</span>'
|
||||
'<em><span class="pre">b</span></em>'
|
||||
'<span class="pre">c</span></code></p>'),
|
||||
'\\sphinxcode{a\\sphinxstyleemphasis{b}c}',
|
||||
),
|
||||
(
|
||||
# interpolation of arrows in menuselection
|
||||
'verify',
|
||||
':menuselection:`a --> b`',
|
||||
(u'<p><span class="menuselection">a \N{TRIANGULAR BULLET} b</span></p>'),
|
||||
'\\sphinxmenuselection{a \\(\\rightarrow\\) b}',
|
||||
),
|
||||
(
|
||||
# interpolation of ampersands in guilabel/menuselection
|
||||
'verify',
|
||||
':guilabel:`&Foo -&&- &Bar`',
|
||||
(u'<p><span class="guilabel"><span class="accelerator">F</span>oo '
|
||||
'-&- <span class="accelerator">B</span>ar</span></p>'),
|
||||
r'\sphinxmenuselection{\sphinxaccelerator{F}oo -\&- \sphinxaccelerator{B}ar}',
|
||||
),
|
||||
(
|
||||
# non-interpolation of dashes in option role
|
||||
'verify_re',
|
||||
':option:`--with-option`',
|
||||
('<p><code( class="xref std std-option docutils literal")?>'
|
||||
'<span class="pre">--with-option</span></code></p>$'),
|
||||
r'\\sphinxcode{-{-}with-option}$',
|
||||
),
|
||||
(
|
||||
# verify smarty-pants quotes
|
||||
'verify',
|
||||
'"John"',
|
||||
'<p>“John”</p>',
|
||||
"``John''",
|
||||
),
|
||||
(
|
||||
# ... but not in literal text
|
||||
'verify',
|
||||
'``"John"``',
|
||||
('<p><code class="docutils literal"><span class="pre">'
|
||||
'"John"</span></code></p>'),
|
||||
'\\sphinxcode{"John"}',
|
||||
),
|
||||
(
|
||||
# verify classes for inline roles
|
||||
'verify',
|
||||
':manpage:`mp(1)`',
|
||||
'<p><em class="manpage">mp(1)</em></p>',
|
||||
'\\sphinxstyleliteralemphasis{mp(1)}',
|
||||
),
|
||||
(
|
||||
# correct escaping in normal mode
|
||||
'verify',
|
||||
u'Γ\\\\∞$',
|
||||
None,
|
||||
r'\(\Gamma\)\textbackslash{}\(\infty\)\$',
|
||||
),
|
||||
(
|
||||
# in verbatim code fragments
|
||||
'verify',
|
||||
u'::\n\n @Γ\\∞${}',
|
||||
None,
|
||||
(u'\\begin{sphinxVerbatim}[commandchars=\\\\\\{\\}]\n'
|
||||
u'@\\(\\Gamma\\)\\PYGZbs{}\\(\\infty\\)\\PYGZdl{}\\PYGZob{}\\PYGZcb{}\n'
|
||||
u'\\end{sphinxVerbatim}'),
|
||||
),
|
||||
(
|
||||
# in URIs
|
||||
'verify_re',
|
||||
u'`test <http://example.com/~me/>`_',
|
||||
None,
|
||||
r'\\href{http://example.com/~me/}{test}.*',
|
||||
),
|
||||
])
|
||||
def test_inline(get_verifier, type, rst, html_expected, latex_expected):
|
||||
verifier = get_verifier(type)
|
||||
verifier(rst, html_expected, latex_expected)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='prolog')
|
||||
|
@ -12,30 +12,27 @@ from __future__ import print_function
|
||||
|
||||
import os
|
||||
import datetime
|
||||
from os import path
|
||||
|
||||
import pytest
|
||||
from babel.messages.mofile import read_mo
|
||||
from sphinx.util import i18n
|
||||
from sphinx.errors import SphinxError
|
||||
import pytest
|
||||
|
||||
from util import TestApp
|
||||
|
||||
|
||||
def test_catalog_info_for_file_and_path():
|
||||
cat = i18n.CatalogInfo('path', 'domain', 'utf-8')
|
||||
assert cat.po_file == 'domain.po'
|
||||
assert cat.mo_file == 'domain.mo'
|
||||
assert cat.po_path == path.join('path', 'domain.po')
|
||||
assert cat.mo_path == path.join('path', 'domain.mo')
|
||||
assert cat.po_path == os.path.join('path', 'domain.po')
|
||||
assert cat.mo_path == os.path.join('path', 'domain.mo')
|
||||
|
||||
|
||||
def test_catalog_info_for_sub_domain_file_and_path():
|
||||
cat = i18n.CatalogInfo('path', 'sub/domain', 'utf-8')
|
||||
assert cat.po_file == 'sub/domain.po'
|
||||
assert cat.mo_file == 'sub/domain.mo'
|
||||
assert cat.po_path == path.join('path', 'sub/domain.po')
|
||||
assert cat.mo_path == path.join('path', 'sub/domain.mo')
|
||||
assert cat.po_path == os.path.join('path', 'sub/domain.po')
|
||||
assert cat.mo_path == os.path.join('path', 'sub/domain.mo')
|
||||
|
||||
|
||||
def test_catalog_outdated(tempdir):
|
||||
@ -55,7 +52,7 @@ def test_catalog_write_mo(tempdir):
|
||||
(tempdir / 'test.po').write_text('#')
|
||||
cat = i18n.CatalogInfo(tempdir, 'test', 'utf-8')
|
||||
cat.write_mo('en')
|
||||
assert path.exists(cat.mo_path)
|
||||
assert os.path.exists(cat.mo_path)
|
||||
with open(cat.mo_path, 'rb') as f:
|
||||
assert read_mo(f) is not None
|
||||
|
||||
@ -189,9 +186,7 @@ def test_format_date():
|
||||
assert i18n.format_date(format, date=date) == 'Feb 7, 2016'
|
||||
|
||||
|
||||
def test_get_filename_for_language():
|
||||
app = TestApp()
|
||||
|
||||
def test_get_filename_for_language(app):
|
||||
# language is None
|
||||
app.env.config.language = None
|
||||
assert app.env.config.language is None
|
||||
|
@ -17,6 +17,7 @@ from docutils import frontend
|
||||
|
||||
from sphinx.util.nodes import extract_messages, clean_astext
|
||||
from sphinx.transforms import ApplySourceWorkaround
|
||||
import pytest
|
||||
|
||||
|
||||
def _transform(doctree):
|
||||
@ -49,84 +50,63 @@ def assert_node_count(messages, node_type, expect_count):
|
||||
% (node_type, node_list, count, expect_count))
|
||||
|
||||
|
||||
def test_extract_messages():
|
||||
text = dedent(
|
||||
"""
|
||||
.. admonition:: admonition title
|
||||
@pytest.mark.parametrize(
|
||||
'rst,node_cls,count',
|
||||
[
|
||||
(
|
||||
"""
|
||||
.. admonition:: admonition title
|
||||
|
||||
admonition body
|
||||
"""
|
||||
)
|
||||
yield (
|
||||
assert_node_count,
|
||||
extract_messages(_get_doctree(text)),
|
||||
nodes.title, 1,
|
||||
)
|
||||
admonition body
|
||||
""",
|
||||
nodes.title, 1
|
||||
),
|
||||
(
|
||||
"""
|
||||
.. figure:: foo.jpg
|
||||
|
||||
text = dedent(
|
||||
"""
|
||||
.. figure:: foo.jpg
|
||||
this is title
|
||||
""",
|
||||
nodes.caption, 1,
|
||||
),
|
||||
(
|
||||
"""
|
||||
.. rubric:: spam
|
||||
""",
|
||||
nodes.rubric, 1,
|
||||
),
|
||||
(
|
||||
"""
|
||||
| spam
|
||||
| egg
|
||||
""",
|
||||
nodes.line, 2,
|
||||
),
|
||||
(
|
||||
"""
|
||||
section
|
||||
=======
|
||||
|
||||
this is title
|
||||
"""
|
||||
)
|
||||
yield (
|
||||
assert_node_count,
|
||||
extract_messages(_get_doctree(text)),
|
||||
nodes.caption, 1,
|
||||
)
|
||||
+----------------+
|
||||
| | **Title 1** |
|
||||
| | Message 1 |
|
||||
+----------------+
|
||||
""",
|
||||
nodes.line, 2,
|
||||
),
|
||||
(
|
||||
"""
|
||||
* | **Title 1**
|
||||
| Message 1
|
||||
""",
|
||||
nodes.line, 2,
|
||||
|
||||
text = dedent(
|
||||
"""
|
||||
.. rubric:: spam
|
||||
"""
|
||||
)
|
||||
yield (
|
||||
assert_node_count,
|
||||
extract_messages(_get_doctree(text)),
|
||||
nodes.rubric, 1,
|
||||
)
|
||||
|
||||
text = dedent(
|
||||
"""
|
||||
| spam
|
||||
| egg
|
||||
"""
|
||||
)
|
||||
yield (
|
||||
assert_node_count,
|
||||
extract_messages(_get_doctree(text)),
|
||||
nodes.line, 2,
|
||||
)
|
||||
|
||||
text = dedent(
|
||||
"""
|
||||
section
|
||||
=======
|
||||
|
||||
+----------------+
|
||||
| | **Title 1** |
|
||||
| | Message 1 |
|
||||
+----------------+
|
||||
"""
|
||||
)
|
||||
yield (
|
||||
assert_node_count,
|
||||
extract_messages(_get_doctree(text)),
|
||||
nodes.line, 2,
|
||||
)
|
||||
|
||||
text = dedent(
|
||||
"""
|
||||
* | **Title 1**
|
||||
| Message 1
|
||||
"""
|
||||
)
|
||||
yield (
|
||||
assert_node_count,
|
||||
extract_messages(_get_doctree(text)),
|
||||
nodes.line, 2,
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
def test_extract_messages(rst, node_cls, count):
|
||||
msg = extract_messages(_get_doctree(dedent(rst)))
|
||||
assert_node_count(msg, node_cls, count)
|
||||
|
||||
|
||||
def test_extract_messages_without_rawsource():
|
||||
|
@ -16,7 +16,7 @@ from docutils.parsers.rst.directives.html import MetaBody
|
||||
from sphinx import addnodes
|
||||
from sphinx.versioning import add_uids, merge_doctrees, get_ratio
|
||||
|
||||
from util import TestApp
|
||||
from util import SphinxTestApp
|
||||
|
||||
|
||||
app = original = original_uids = None
|
||||
@ -24,7 +24,7 @@ app = original = original_uids = None
|
||||
|
||||
def setup_module():
|
||||
global app, original, original_uids
|
||||
app = TestApp(testroot='versioning')
|
||||
app = SphinxTestApp(testroot='versioning')
|
||||
app.builder.env.app = app
|
||||
app.connect('doctree-resolved', on_doctree_resolved)
|
||||
app.build()
|
||||
|
@ -23,7 +23,7 @@ except ImportError:
|
||||
sqlalchemy_missing = True
|
||||
|
||||
import pytest
|
||||
from util import rootdir, tempdir, skip_if
|
||||
from util import rootdir, tempdir
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -57,13 +57,13 @@ def test_no_srcdir(support):
|
||||
support.build()
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
|
||||
@with_support()
|
||||
def test_build(support):
|
||||
support.build()
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
|
||||
@with_support()
|
||||
def test_get_document(support):
|
||||
with pytest.raises(DocumentNotFoundError):
|
||||
@ -74,7 +74,7 @@ def test_get_document(support):
|
||||
and contents['sidebar'] and contents['relbar']
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
|
||||
@with_support()
|
||||
def test_comments(support):
|
||||
session = Session()
|
||||
@ -123,7 +123,7 @@ def test_comments(support):
|
||||
assert children[0]['text'] == '<p>Child test comment</p>\n'
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
|
||||
@with_support()
|
||||
def test_user_delete_comments(support):
|
||||
def get_comment():
|
||||
@ -152,7 +152,7 @@ def moderation_callback(comment):
|
||||
called = True
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
|
||||
@with_support(moderation_callback=moderation_callback)
|
||||
def test_moderation(support):
|
||||
session = Session()
|
||||
@ -178,7 +178,7 @@ def test_moderation(support):
|
||||
assert len(comments) == 1
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
|
||||
@with_support()
|
||||
def test_moderator_delete_comments(support):
|
||||
def get_comment():
|
||||
@ -194,7 +194,7 @@ def test_moderator_delete_comments(support):
|
||||
get_comment()
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
|
||||
@with_support()
|
||||
def test_update_username(support):
|
||||
support.update_username('user_two', 'new_user_two')
|
||||
@ -213,7 +213,7 @@ def test_update_username(support):
|
||||
assert len(votes) == 0
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
|
||||
@with_support()
|
||||
def test_proposals(support):
|
||||
session = Session()
|
||||
@ -229,7 +229,7 @@ def test_proposals(support):
|
||||
proposal=proposal)
|
||||
|
||||
|
||||
@skip_if(sqlalchemy_missing, 'needs sqlalchemy')
|
||||
@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
|
||||
@with_support()
|
||||
def test_voting(support):
|
||||
session = Session()
|
||||
|
@ -207,7 +207,6 @@ def strip_escseq(text):
|
||||
# #############################################
|
||||
# DEPRECATED implementations
|
||||
|
||||
import tempfile
|
||||
from six import StringIO
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user