merge with trunk

This commit is contained in:
Georg Brandl
2010-01-02 21:03:56 +01:00
67 changed files with 3903 additions and 2229 deletions

View File

@@ -1,4 +1,5 @@
{% extends "!layout.html" %}
{% block extrahead %}
{# html_context variable from conf.py #}
<meta name="hc" content="{{ hckey }}" />
@@ -6,3 +7,9 @@
<meta name="hc_co" content="{{ hckey_co }}" />
{{ super() }}
{% endblock %}
{% block sidebartoc %}
{# display global TOC in addition to local TOC #}
{{ super() }}
{{ toctree(collapse=False, maxdepth=-1) }}
{% endblock %}

View File

@@ -25,6 +25,7 @@ today_fmt = '%B %d, %Y'
exclude_trees = ['_build']
keep_warnings = True
pygments_style = 'sphinx'
show_authors = True
rst_epilog = '.. |subst| replace:: global substitution'
@@ -49,6 +50,7 @@ latex_additional_files = ['svgimg.svg']
value_from_conf_py = 84
coverage_c_path = ['special/*.h']
# XXX cfunction?
coverage_c_regexes = {'cfunction': r'^PyAPI_FUNC\(.*\)\s+([^_][\w_]+)'}
autosummary_generate = ['autosummary']
@@ -59,7 +61,12 @@ extlinks = {'issue': ('http://bugs.python.org/issue%s', 'issue '),
# modify tags from conf.py
tags.add('confpytag')
# -- extension API
from docutils import nodes
from sphinx import addnodes
from sphinx.util.compat import Directive
def userdesc_parse(env, sig, signode):
x, y = sig.split(':')
@@ -68,7 +75,18 @@ def userdesc_parse(env, sig, signode):
signode[-1] += addnodes.desc_parameter(y, y)
return x
def functional_directive(name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine):
return [nodes.strong(text='from function: %s' % options['opt'])]
class ClassDirective(Directive):
option_spec = {'opt': lambda x: x}
def run(self):
return [nodes.strong(text='from class: %s' % self.options['opt'])]
def setup(app):
app.add_config_value('value_from_conf_py', 42, False)
app.add_description_unit('userdesc', 'userdescrole', '%s (userdesc)',
userdesc_parse)
app.add_directive('funcdir', functional_directive, opt=lambda x: x)
app.add_directive('clsdir', ClassDirective)
app.add_object_type('userdesc', 'userdescrole', '%s (userdesc)',
userdesc_parse, objname='user desc')

View File

@@ -11,12 +11,13 @@ Contents:
:maxdepth: 2
:numbered:
extapi
images
subdir/images
subdir/includes
includes
markup
desc
objects
bom
math
autodoc

10
tests/root/extapi.txt Normal file
View File

@@ -0,0 +1,10 @@
Extension API tests
===================
Testing directives:
.. funcdir::
:opt: Foo
.. clsdir::
:opt: Bar

View File

@@ -5,7 +5,11 @@
Testing various markup
======================
Meta markup
-----------
.. sectionauthor:: Georg Brandl
.. moduleauthor:: Georg Brandl
.. contents:: TOC
@@ -13,7 +17,11 @@ Testing various markup
:author: Me
:keywords: docs, sphinx
A |subst|.
Generic reST
------------
A |subst| (the definition is in rst_epilog).
.. _label:
@@ -21,22 +29,14 @@ A |subst|.
some code
Admonitions
-----------
Option list:
.. note:: Note
Note text.
.. warning:: Warning
Warning text.
.. tip::
Tip text.
-h help
--help also help
Body directives
---------------
^^^^^^^^^^^^^^^
.. topic:: Title
@@ -69,7 +69,67 @@ Body directives
b
Admonitions
^^^^^^^^^^^
.. admonition:: My Admonition
Admonition text.
.. note::
Note text.
.. warning::
Warning text.
.. tip::
Tip text.
Inline markup
-------------
*Generic inline markup*
* :command:`command`
* :dfn:`dfn`
* :guilabel:`guilabel`
* :kbd:`kbd`
* :mailheader:`mailheader`
* :makevar:`makevar`
* :manpage:`manpage`
* :mimetype:`mimetype`
* :newsgroup:`newsgroup`
* :program:`program`
* :regexp:`regexp`
* :menuselection:`File --> Close`
* :file:`a/{varpart}/b`
* :samp:`print {i}`
*Linking inline markup*
* :pep:`8`
* :rfc:`1`
* :envvar:`HOME`
* :keyword:`with`
* :token:`try statement <try_stmt>`
* :doc:`subdir/includes`
* ``:download:`` is tested in includes.txt
* :option:`Python -c option <python -c>`
Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`.
.. _with:
With
----
(Empty section.)
Tables
------
@@ -96,6 +156,17 @@ Version markup
Boring stuff.
Code blocks
-----------
.. code-block:: ruby
:linenos:
def ruby?
false
end
Misc stuff
----------
@@ -124,11 +195,6 @@ This is a side note.
This tests :CLASS:`role names in uppercase`.
Option list:
-h help
--help also help
.. centered:: LICENSE AGREEMENT
.. acks::
@@ -146,7 +212,7 @@ Option list:
Particle with half-integer spin.
.. productionlist::
try_stmt: try1_stmt | try2_stmt
try_stmt: `try1_stmt` | `try2_stmt`
try1_stmt: "try" ":" `suite`
: ("except" [`expression` ["," `target`]] ":" `suite`)+
: ["else" ":" `suite`]
@@ -154,7 +220,6 @@ Option list:
try2_stmt: "try" ":" `suite`
: "finally" ":" `suite`
Test :abbr:`abbr (abbreviation)` and another :abbr:`abbr (abbreviation)`.
Index markup
------------
@@ -180,11 +245,6 @@ Invalid index markup...
Testing öäü...
Object markup
-------------
:cfunc:`CFunction`.
Only directive
--------------
@@ -208,3 +268,4 @@ Only directive
.. rubric:: Footnotes
.. [#] Like footnotes.

View File

@@ -1,5 +1,5 @@
Testing description units
=========================
Testing object descriptions
===========================
.. function:: func_without_module(a, b, *c[, d])
@@ -43,22 +43,42 @@ Testing description units
C items
=======
.. cfunction:: Sphinx_DoSomething()
.. c:function:: Sphinx_DoSomething()
.. cmember:: SphinxStruct.member
.. c:member:: SphinxStruct.member
.. cmacro:: SPHINX_USE_PYTHON
.. c:macro:: SPHINX_USE_PYTHON
.. ctype:: SphinxType
.. c:type:: SphinxType
.. cvar:: sphinx_global
.. c:var:: sphinx_global
Testing references
==================
References
==========
Referencing :class:`mod.Cls` or :Class:`mod.Cls` should be the same.
With target: :c:func:`Sphinx_DoSomething()` (parentheses are handled),
:c:member:`SphinxStruct.member`, :c:macro:`SPHINX_USE_PYTHON`,
:c:type:`SphinxType *` (pointer is handled), :c:data:`sphinx_global`.
Without target: :c:func:`CFunction`. :c:func:`!malloc`.
Others
======
.. envvar:: HOME
.. program:: python
.. cmdoption:: -c command
.. program:: perl
.. cmdoption:: -c
User markup
===========

View File

@@ -97,28 +97,28 @@ def test_parse_name():
verify('function', 'util.raises', ('util', ['raises'], None, None))
verify('function', 'util.raises(exc) -> None',
('util', ['raises'], 'exc', 'None'))
directive.env.autodoc_current_module = 'util'
directive.env.doc_read_data['autodoc_module'] = 'util'
verify('function', 'raises', ('util', ['raises'], None, None))
directive.env.autodoc_current_module = None
directive.env.currmodule = 'util'
del directive.env.doc_read_data['autodoc_module']
directive.env.doc_read_data['py_module'] = 'util'
verify('function', 'raises', ('util', ['raises'], None, None))
verify('class', 'TestApp', ('util', ['TestApp'], None, None))
# for members
directive.env.currmodule = 'foo'
directive.env.doc_read_data['py_module'] = 'foo'
verify('method', 'util.TestApp.cleanup',
('util', ['TestApp', 'cleanup'], None, None))
directive.env.currmodule = 'util'
directive.env.currclass = 'Foo'
directive.env.autodoc_current_class = 'TestApp'
directive.env.doc_read_data['py_module'] = 'util'
directive.env.doc_read_data['py_class'] = 'Foo'
directive.env.doc_read_data['autodoc_class'] = 'TestApp'
verify('method', 'cleanup', ('util', ['TestApp', 'cleanup'], None, None))
verify('method', 'TestApp.cleanup',
('util', ['TestApp', 'cleanup'], None, None))
# and clean up
directive.env.currmodule = None
directive.env.currclass = None
directive.env.autodoc_current_class = None
del directive.env.doc_read_data['py_module']
del directive.env.doc_read_data['py_class']
del directive.env.doc_read_data['autodoc_class']
def test_format_signature():
@@ -306,7 +306,7 @@ def test_new_documenter():
del directive.result[:]
options.members = ['integer']
assert_result_contains('.. data:: integer', 'module', 'test_autodoc')
assert_result_contains('.. py:data:: integer', 'module', 'test_autodoc')
def test_generate():
@@ -353,7 +353,7 @@ def test_generate():
'function', 'util.foobar', more_content=None)
# test auto and given content mixing
directive.env.currmodule = 'test_autodoc'
directive.env.doc_read_data['py_module'] = 'test_autodoc'
assert_result_contains(' Function.', 'method', 'Class.meth')
add_content = ViewList()
add_content.append('Content.', '', 0)
@@ -394,7 +394,8 @@ def test_generate():
options.members = []
# test module flags
assert_result_contains('.. module:: test_autodoc', 'module', 'test_autodoc')
assert_result_contains('.. py:module:: test_autodoc',
'module', 'test_autodoc')
options.synopsis = 'Synopsis'
assert_result_contains(' :synopsis: Synopsis', 'module', 'test_autodoc')
options.deprecated = True
@@ -403,9 +404,9 @@ def test_generate():
assert_result_contains(' :platform: Platform', 'module', 'test_autodoc')
# test if __all__ is respected for modules
options.members = ALL
assert_result_contains('.. class:: Class', 'module', 'test_autodoc')
assert_result_contains('.. py:class:: Class', 'module', 'test_autodoc')
try:
assert_result_contains('.. exception:: CustomEx',
assert_result_contains('.. py:exception:: CustomEx',
'module', 'test_autodoc')
except AssertionError:
pass
@@ -419,7 +420,7 @@ def test_generate():
assert_result_contains(' :noindex:', 'class', 'Base')
# okay, now let's get serious about mixing Python and C signature stuff
assert_result_contains('.. class:: CustomDict', 'class', 'CustomDict',
assert_result_contains('.. py:class:: CustomDict', 'class', 'CustomDict',
all_members=True)
# test inner class handling
@@ -433,7 +434,7 @@ def test_generate():
'attribute', 'test_autodoc.Class.descr')
# test generation for C modules (which have no source file)
directive.env.currmodule = 'time'
directive.env.doc_read_data['py_module'] = 'time'
assert_processes([('function', 'time.asctime')], 'function', 'asctime')
assert_processes([('function', 'time.asctime')], 'function', 'asctime')

View File

@@ -13,28 +13,19 @@ import os
import re
import sys
import difflib
import htmlentitydefs
from StringIO import StringIO
from subprocess import Popen, PIPE
from util import *
from etree13 import ElementTree as ET
try:
import pygments
except ImportError:
pygments = None
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.builders.latex import LaTeXBuilder
from sphinx.writers.latex import LaTeXTranslator
from util import *
def teardown_module():
(test_root / '_build').rmtree(True)
html_warnfile = StringIO()
latex_warnfile = StringIO()
ENV_WARNINGS = """\
@@ -46,164 +37,11 @@ included file u'wrongenc.inc' seems to be wrong, try giving an :encoding: option
%(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png
"""
HTML_WARNINGS = ENV_WARNINGS + """\
%(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.*'
%(root)s/markup.txt:: WARNING: invalid index entry u''
%(root)s/markup.txt:: WARNING: invalid pair index entry u''
%(root)s/markup.txt:: WARNING: invalid pair index entry u'keyword; '
"""
LATEX_WARNINGS = ENV_WARNINGS + """\
None:None: WARNING: no matching candidate for image URI u'foo.*'
WARNING: invalid pair index entry u''
"""
HTML_XPATH = {
'images.html': {
".//img[@src='_images/img.png']": '',
".//img[@src='_images/img1.png']": '',
".//img[@src='_images/simg.png']": '',
".//object[@data='_images/svgimg.svg']": '',
".//embed[@src='_images/svgimg.svg']": '',
},
'subdir/images.html': {
".//img[@src='../_images/img1.png']": '',
".//img[@src='../_images/rimg.png']": '',
},
'subdir/includes.html': {
".//a[@href='../_downloads/img.png']": '',
},
'includes.html': {
".//pre": u'Max Strauß',
".//a[@href='_downloads/img.png']": '',
".//a[@href='_downloads/img1.png']": '',
".//pre": u'"quotes"',
".//pre": u"'included'",
},
'autodoc.html': {
".//dt[@id='test_autodoc.Class']": '',
".//dt[@id='test_autodoc.function']/em": r'\*\*kwds',
".//dd": r'Return spam\.',
},
'markup.html': {
".//meta[@name='author'][@content='Me']": '',
".//meta[@name='keywords'][@content='docs, sphinx']": '',
".//a[@href='contents.html#ref1']": '',
".//div[@id='label']": '',
".//span[@class='option']": '--help',
".//p": 'A global substitution.',
".//p": 'In HTML.',
".//p": 'In both.',
".//p": 'Always present',
".//title": 'set by title directive',
".//span[@class='pre']": 'CFunction()',
},
'desc.html': {
".//dt[@id='mod.Cls.meth1']": '',
".//dt[@id='errmod.Error']": '',
".//a[@href='#mod.Cls']": '',
".//dl[@class='userdesc']": '',
".//dt[@id='userdescrole-myobj']": '',
".//a[@href='#userdescrole-myobj']": '',
},
'contents.html': {
".//meta[@name='hc'][@content='hcval']": '',
".//meta[@name='hc_co'][@content='hcval_co']": '',
".//meta[@name='testopt'][@content='testoverride']": '',
#".//td[@class='label']": r'\[Ref1\]', # docutils 0.5 only
".//td[@class='label']": '',
".//li[@class='toctree-l1']/a": 'Testing various markup',
".//li[@class='toctree-l2']/a": 'Admonitions',
".//title": 'Sphinx <Tests>',
".//div[@class='footer']": 'Georg Brandl & Team',
".//a[@href='http://python.org/']": '',
},
'bom.html': {
".//title": " File with UTF-8 BOM",
},
'extensions.html': {
".//a[@href='http://python.org/dev/']": "http://python.org/dev/",
".//a[@href='http://bugs.python.org/issue1000']": "issue 1000",
".//a[@href='http://bugs.python.org/issue1042']": "explicit caption",
},
'_static/statictmpl.html': {
".//project": 'Sphinx <Tests>',
},
}
if pygments:
HTML_XPATH['includes.html'].update({
".//pre/span[@class='s']": u'üöä',
".//div[@class='inc-pyobj1 highlight-text']/div/pre":
r'^class Foo:\n pass\n\s*$',
".//div[@class='inc-pyobj2 highlight-text']/div/pre":
r'^ def baz\(\):\n pass\n\s*$',
".//div[@class='inc-lines highlight-text']/div/pre":
r'^class Foo:\n pass\nclass Bar:\n$',
".//div[@class='inc-startend highlight-text']/div/pre":
ur'^foo = u"Including Unicode characters: üöä"\n$',
".//div[@class='inc-preappend highlight-text']/div/pre":
r'(?m)^START CODE$',
".//div[@class='inc-pyobj-dedent highlight-python']/div/pre/span":
r'def',
})
HTML_XPATH['subdir/includes.html'].update({
".//pre/span": 'line 1',
".//pre/span": 'line 2',
})
class NslessParser(ET.XMLParser):
"""XMLParser that throws away namespaces in tag names."""
def _fixname(self, key):
try:
return self._names[key]
except KeyError:
name = key
br = name.find('}')
if br > 0:
name = name[br+1:]
self._names[key] = name = self._fixtext(name)
return name
def check_xpath(etree, fname, path, check):
nodes = list(etree.findall(path))
assert nodes != [], ('did not find any node matching xpath '
'%r in file %s' % (path, fname))
if hasattr(check, '__call__'):
check(nodes)
elif not check:
# only check for node presence
pass
else:
rex = re.compile(check)
for node in nodes:
if node.text and rex.search(node.text):
break
else:
assert False, ('%r not found in any node matching '
'path %s in %s: %r' % (check, path, fname,
[node.text for node in nodes]))
@gen_with_app(buildername='html', warning=html_warnfile, cleanenv=True,
confoverrides={'html_context.hckey_co': 'hcval_co'},
tags=['testtag'])
def test_html(app):
app.builder.build_all()
html_warnings = html_warnfile.getvalue().replace(os.sep, '/')
html_warnings_exp = HTML_WARNINGS % {'root': app.srcdir}
assert html_warnings == html_warnings_exp, 'Warnings don\'t match:\n' + \
'\n'.join(difflib.ndiff(html_warnings_exp.splitlines(),
html_warnings.splitlines()))
for fname, paths in HTML_XPATH.iteritems():
parser = NslessParser()
parser.entity.update(htmlentitydefs.entitydefs)
etree = ET.parse(os.path.join(app.outdir, fname), parser)
for path, check in paths.iteritems():
yield check_xpath, etree, fname, path, check
@with_app(buildername='latex', warning=latex_warnfile, cleanenv=True)
def test_latex(app):

252
tests/test_build_html.py Normal file
View File

@@ -0,0 +1,252 @@
# -*- coding: utf-8 -*-
"""
test_build_html
~~~~~~~~~~~~~~~
Test the HTML builder and check output against XPath.
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import os
import re
import sys
import difflib
import htmlentitydefs
from StringIO import StringIO
try:
import pygments
except ImportError:
pygments = None
from sphinx.builders.html import StandaloneHTMLBuilder
from util import *
from test_build import ENV_WARNINGS
from etree13 import ElementTree as ET
def teardown_module():
(test_root / '_build').rmtree(True)
html_warnfile = StringIO()
HTML_WARNINGS = ENV_WARNINGS + """\
%(root)s/images.txt:20: WARNING: no matching candidate for image URI u'foo.*'
%(root)s/markup.txt:: WARNING: invalid index entry u''
%(root)s/markup.txt:: WARNING: invalid pair index entry u''
%(root)s/markup.txt:: WARNING: invalid pair index entry u'keyword; '
"""
HTML_XPATH = {
'images.html': {
".//img[@src='_images/img.png']": '',
".//img[@src='_images/img1.png']": '',
".//img[@src='_images/simg.png']": '',
".//object[@data='_images/svgimg.svg']": '',
".//embed[@src='_images/svgimg.svg']": '',
},
'subdir/images.html': {
".//img[@src='../_images/img1.png']": '',
".//img[@src='../_images/rimg.png']": '',
},
'subdir/includes.html': {
".//a[@href='../_downloads/img.png']": '',
},
'includes.html': {
".//pre": u'Max Strauß',
".//a[@href='_downloads/img.png']": '',
".//a[@href='_downloads/img1.png']": '',
".//pre": u'"quotes"',
".//pre": u"'included'",
},
'autodoc.html': {
".//dt[@id='test_autodoc.Class']": '',
".//dt[@id='test_autodoc.function']/em": r'\*\*kwds',
".//dd": r'Return spam\.',
},
'extapi.html': {
".//strong": 'from function: Foo',
".//strong": 'from class: Bar',
},
'markup.html': {
".//title": 'set by title directive',
".//p/em": 'Section author: Georg Brandl',
".//p/em": 'Module author: Georg Brandl',
# created by the meta directive
".//meta[@name='author'][@content='Me']": '',
".//meta[@name='keywords'][@content='docs, sphinx']": '',
# a label created by ``.. _label:``
".//div[@id='label']": '',
# code with standard code blocks
".//pre": '^some code$',
# an option list
".//span[@class='option']": '--help',
# admonitions
".//p[@class='first admonition-title']": 'My Admonition',
".//p[@class='last']": 'Note text.',
".//p[@class='last']": 'Warning text.',
# inline markup
".//li/strong": '^command$',
".//li/strong": '^program$',
".//li/em": '^dfn$',
".//li/tt/span[@class='pre']": '^kbd$',
".//li/em": u'File \N{TRIANGULAR BULLET} Close',
".//li/tt/span[@class='pre']": '^a/$',
".//li/tt/em/span[@class='pre']": '^varpart$',
".//li/tt/em/span[@class='pre']": '^i$',
".//a[@href='http://www.python.org/dev/peps/pep-0008']/strong": 'PEP 8',
".//a[@href='http://tools.ietf.org/html/rfc1.html']/strong": 'RFC 1',
".//a[@href='objects.html#envvar-HOME']/tt/span[@class='pre']": 'HOME',
".//a[@href='#with']/tt/span[@class='pre']": '^with$',
".//a[@href='#grammar-token-try_stmt']/tt/span": '^statement$',
".//a[@href='subdir/includes.html']/em": 'Including in subdir',
".//a[@href='objects.html#cmdoption-python-c']/em": 'Python -c option',
# abbreviations
".//abbr[@title='abbreviation']": '^abbr$',
# version stuff
".//span[@class='versionmodified']": 'New in version 0.6',
# footnote reference
".//a[@class='footnote-reference']": r'\[1\]',
# created by reference lookup
".//a[@href='contents.html#ref1']": '',
# ``seealso`` directive
".//div/p[@class='first admonition-title']": 'See also',
# a ``hlist`` directive
".//table[@class='hlist']/tr/td/ul/li": '^This$',
# a ``centered`` directive
".//p[@class='centered']/strong": 'LICENSE',
# a glossary
".//dl/dt[@id='term-boson']": 'boson',
# a production list
".//pre/strong": 'try_stmt',
".//pre/a[@href='#grammar-token-try1_stmt']/tt/span": 'try1_stmt',
# tests for ``only`` directive
".//p": 'A global substitution.',
".//p": 'In HTML.',
".//p": 'In both.',
".//p": 'Always present',
},
'objects.html': {
".//dt[@id='mod.Cls.meth1']": '',
".//dt[@id='errmod.Error']": '',
".//a[@href='#mod.Cls']": '',
".//dl[@class='userdesc']": '',
".//dt[@id='userdesc-myobj']": '',
".//a[@href='#userdesc-myobj']": '',
# C references
".//span[@class='pre']": 'CFunction()',
".//a[@href='#Sphinx_DoSomething']": '',
".//a[@href='#SphinxStruct.member']": '',
".//a[@href='#SPHINX_USE_PYTHON']": '',
".//a[@href='#SphinxType']": '',
".//a[@href='#sphinx_global']": '',
# test global TOC created by toctree()
".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='']":
'Testing object descriptions',
".//li[@class='toctree-l1']/a[@href='markup.html']":
'Testing various markup',
},
'contents.html': {
".//meta[@name='hc'][@content='hcval']": '',
".//meta[@name='hc_co'][@content='hcval_co']": '',
".//meta[@name='testopt'][@content='testoverride']": '',
#".//td[@class='label']": r'\[Ref1\]', # docutils 0.5 only
".//td[@class='label']": '',
".//li[@class='toctree-l1']/a": 'Testing various markup',
".//li[@class='toctree-l2']/a": 'Inline markup',
".//title": 'Sphinx <Tests>',
".//div[@class='footer']": 'Georg Brandl & Team',
".//a[@href='http://python.org/']": '',
".//li/a[@href='genindex.html']/em": 'Index',
".//li/a[@href='modindex.html']/em": 'Module Index',
".//li/a[@href='search.html']/em": 'Search Page',
},
'bom.html': {
".//title": " File with UTF-8 BOM",
},
'extensions.html': {
".//a[@href='http://python.org/dev/']": "http://python.org/dev/",
".//a[@href='http://bugs.python.org/issue1000']": "issue 1000",
".//a[@href='http://bugs.python.org/issue1042']": "explicit caption",
},
'_static/statictmpl.html': {
".//project": 'Sphinx <Tests>',
},
}
if pygments:
HTML_XPATH['includes.html'].update({
".//pre/span[@class='s']": u'üöä',
".//div[@class='inc-pyobj1 highlight-text']/div/pre":
r'^class Foo:\n pass\n\s*$',
".//div[@class='inc-pyobj2 highlight-text']/div/pre":
r'^ def baz\(\):\n pass\n\s*$',
".//div[@class='inc-lines highlight-text']/div/pre":
r'^class Foo:\n pass\nclass Bar:\n$',
".//div[@class='inc-startend highlight-text']/div/pre":
ur'^foo = u"Including Unicode characters: üöä"\n$',
".//div[@class='inc-preappend highlight-text']/div/pre":
r'(?m)^START CODE$',
".//div[@class='inc-pyobj-dedent highlight-python']/div/pre/span":
r'def',
})
HTML_XPATH['subdir/includes.html'].update({
".//pre/span": 'line 1',
".//pre/span": 'line 2',
})
class NslessParser(ET.XMLParser):
"""XMLParser that throws away namespaces in tag names."""
def _fixname(self, key):
try:
return self._names[key]
except KeyError:
name = key
br = name.find('}')
if br > 0:
name = name[br+1:]
self._names[key] = name = self._fixtext(name)
return name
def check_xpath(etree, fname, path, check):
nodes = list(etree.findall(path))
assert nodes != [], ('did not find any node matching xpath '
'%r in file %s' % (path, fname))
if hasattr(check, '__call__'):
check(nodes)
elif not check:
# only check for node presence
pass
else:
rex = re.compile(check)
for node in nodes:
if node.text and rex.search(node.text):
break
else:
assert False, ('%r not found in any node matching '
'path %s in %s: %r' % (check, path, fname,
[node.text for node in nodes]))
@gen_with_app(buildername='html', warning=html_warnfile, cleanenv=True,
confoverrides={'html_context.hckey_co': 'hcval_co'},
tags=['testtag'])
def test_html(app):
app.builder.build_all()
html_warnings = html_warnfile.getvalue().replace(os.sep, '/')
html_warnings_exp = HTML_WARNINGS % {'root': app.srcdir}
assert html_warnings == html_warnings_exp, 'Warnings don\'t match:\n' + \
'\n'.join(difflib.ndiff(html_warnings_exp.splitlines(),
html_warnings.splitlines()))
for fname, paths in HTML_XPATH.iteritems():
parser = NslessParser()
parser.entity.update(htmlentitydefs.entitydefs)
etree = ET.parse(os.path.join(app.outdir, fname), parser)
for path, check in paths.iteritems():
yield check_xpath, etree, fname, path, check

View File

@@ -32,7 +32,7 @@ def test_core_config(app):
# simple default values
assert 'exclude_dirs' not in cfg.__dict__
assert cfg.exclude_dirs == []
assert cfg.show_authors == False
assert cfg.trim_footnote_reference_space == False
# complex default values
assert 'html_title' not in cfg.__dict__

View File

@@ -36,6 +36,7 @@ def test_build(app):
undoc_py, undoc_c = pickle.loads((app.outdir / 'undoc.pickle').text())
assert len(undoc_c) == 1
# the key is the full path to the header file, which isn't testable
# XXX this should fail right now
assert undoc_c.values()[0] == [('cfunction', 'Py_SphinxTest')]
assert 'test_autodoc' in undoc_py

View File

@@ -20,8 +20,8 @@ warnings = []
def setup_module():
global app, env
app = TestApp(srcdir='(temp)')
env = BuildEnvironment(app.srcdir, app.doctreedir, app.config)
app = TestApp(srcdir='(temp)', freshenv=True)
env = app.env
env.set_warnfunc(lambda *args: warnings.append(args))
def teardown_module():
@@ -51,7 +51,7 @@ def test_images():
tree = env.get_doctree('images')
app._warning.reset()
htmlbuilder = StandaloneHTMLBuilder(app, env)
htmlbuilder = StandaloneHTMLBuilder(app)
htmlbuilder.post_process_images(tree)
assert "no matching candidate for image URI u'foo.*'" in \
app._warning.content[-1]
@@ -61,7 +61,7 @@ def test_images():
set(['img.png', 'img1.png', 'simg.png', 'svgimg.svg'])
app._warning.reset()
latexbuilder = LaTeXBuilder(app, env)
latexbuilder = LaTeXBuilder(app)
latexbuilder.post_process_images(tree)
assert "no matching candidate for image URI u'foo.*'" in \
app._warning.content[-1]
@@ -92,10 +92,10 @@ def test_second_update():
assert 'autodoc' not in env.found_docs
def test_object_inventory():
refs = env.descrefs
refs = env.domaindata['py']['objects']
assert 'func_without_module' in refs
assert refs['func_without_module'] == ('desc', 'function')
assert refs['func_without_module'] == ('objects', 'function')
assert 'func_without_module2' in refs
assert 'mod.func_in_module' in refs
assert 'mod.Cls' in refs
@@ -109,5 +109,8 @@ def test_object_inventory():
assert 'func_in_module' not in refs
assert 'func_noindex' not in refs
assert 'mod' in env.modules
assert env.modules['mod'] == ('desc', 'Module synopsis.', 'UNIX', False)
assert env.domaindata['py']['modules']['mod'] == \
('objects', 'Module synopsis.', 'UNIX', False)
assert env.domains['py'].data is env.domaindata['py']
assert env.domains['c'].data is env.domaindata['c']

112
tests/test_intersphinx.py Normal file
View File

@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
"""
test_intersphinx
~~~~~~~~~~~~~~~~
Test the intersphinx extension.
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import zlib
import posixpath
from cStringIO import StringIO
from docutils import nodes
from sphinx import addnodes
from sphinx.ext.intersphinx import read_inventory_v1, read_inventory_v2, \
fetch_inventory, load_mappings, missing_reference
from util import *
inventory_v1 = '''\
# Sphinx inventory version 1
# Project: foo
# Version: 1.0
module mod foo.html
module.cls class foo.html
'''
inventory_v2 = '''\
# Sphinx inventory version 2
# Project: foo
# Version: 2.0
# The remainder of this file is compressed with zlib.
''' + zlib.compress('''\
module1 py:module 0 foo.html#module-module1
module2 py:module 0 foo.html#module-$
module1.func py:function 1 sub/foo.html#$
CFunc c:function 2 cfunc.html#CFunc
''')
def test_read_inventory_v1():
f = StringIO(inventory_v1)
f.readline()
invdata = read_inventory_v1(f, '/util', posixpath.join)
assert invdata['py:module']['module'] == \
('foo', '1.0', '/util/foo.html#module-module')
assert invdata['py:class']['module.cls'] == \
('foo', '1.0', '/util/foo.html#module.cls')
def test_read_inventory_v2():
f = StringIO(inventory_v2)
f.readline()
invdata1 = read_inventory_v2(f, '/util', posixpath.join)
# try again with a small buffer size to test the chunking algorithm
f = StringIO(inventory_v2)
f.readline()
invdata2 = read_inventory_v2(f, '/util', posixpath.join, bufsize=5)
assert invdata1 == invdata2
assert len(invdata1['py:module']) == 2
assert invdata1['py:module']['module1'] == \
('foo', '2.0', '/util/foo.html#module-module1')
assert invdata1['py:module']['module2'] == \
('foo', '2.0', '/util/foo.html#module-module2')
assert invdata1['py:function']['module1.func'][2] == \
'/util/sub/foo.html#module1.func'
assert invdata1['c:function']['CFunc'][2] == '/util/cfunc.html#CFunc'
@with_app(confoverrides={'extensions': 'sphinx.ext.intersphinx'})
@with_tempdir
def test_missing_reference(tempdir, app):
inv_file = tempdir / 'inventory'
write_file(inv_file, inventory_v2)
app.config.intersphinx_mapping = {'http://docs.python.org/': inv_file}
app.config.intersphinx_cache_limit = 0
# load the inventory and check if it's done correctly
load_mappings(app)
inv = app.env.intersphinx_inventory
assert inv['py:module']['module2'] == \
('foo', '2.0', 'http://docs.python.org/foo.html#module-module2')
# create fake nodes and check referencing
contnode = nodes.emphasis('foo')
refnode = addnodes.pending_xref('')
refnode['reftarget'] = 'module1.func'
refnode['reftype'] = 'func'
refnode['refdomain'] = 'py'
rn = missing_reference(app, app.env, refnode, contnode)
assert isinstance(rn, nodes.reference)
assert rn['refuri'] == 'http://docs.python.org/sub/foo.html#module1.func'
assert rn['reftitle'] == '(in foo v2.0)'
assert rn[0] is contnode
# create unresolvable nodes and check None return value
refnode['reftype'] = 'foo'
assert missing_reference(app, app.env, refnode, contnode) is None
refnode['reftype'] = 'function'
refnode['reftarget'] = 'foo.func'
assert missing_reference(app, app.env, refnode, contnode) is None

View File

@@ -29,6 +29,7 @@ def setup_module():
components=(rst.Parser, HTMLWriter, LaTeXWriter))
settings = optparser.get_default_values()
settings.env = app.builder.env
settings.env.patch_lookup_functions()
parser = rst.Parser()
def teardown_module():
@@ -60,7 +61,7 @@ def verify_re(rst, html_expected, latex_expected):
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
assert re.match(html_expected, html_translated), 'from ' + rst
if latex_expected:
latex_translator = ForgivingLaTeXTranslator(document, app.builder)

View File

@@ -184,9 +184,9 @@ def gen_with_app(*args, **kwargs):
def with_tempdir(func):
def new_func():
def new_func(*args, **kwds):
tempdir = path(tempfile.mkdtemp())
func(tempdir)
func(tempdir, *args, **kwds)
tempdir.rmtree()
new_func.__name__ = func.__name__
return new_func