mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merged revisions 65283,65303,65316-65317,65372-65375,65377,65380,65483-65485,65494 via svnmerge from
svn+ssh://pythondev@svn.python.org/doctools/branches/0.4.x ........ r65283 | georg.brandl | 2008-07-29 10:07:26 +0000 (Tue, 29 Jul 2008) | 2 lines Update ez_setup.py. ........ r65303 | benjamin.peterson | 2008-07-30 12:35:34 +0000 (Wed, 30 Jul 2008) | 1 line add a with_testapp decorator for test functions that passes the TestApp instance in a cleans up after it ........ r65316 | benjamin.peterson | 2008-07-30 23:12:07 +0000 (Wed, 30 Jul 2008) | 1 line make the app for test_markup global to the module ........ r65317 | benjamin.peterson | 2008-07-30 23:31:29 +0000 (Wed, 30 Jul 2008) | 1 line make TestApp.cleanup more aggressive ........ r65372 | georg.brandl | 2008-08-01 19:11:22 +0000 (Fri, 01 Aug 2008) | 2 lines Add more tests, fix a few bugs in image handling. ........ r65373 | georg.brandl | 2008-08-01 19:28:33 +0000 (Fri, 01 Aug 2008) | 2 lines Fix oversight. ........ r65374 | benjamin.peterson | 2008-08-01 19:36:32 +0000 (Fri, 01 Aug 2008) | 1 line fix one broken test ........ r65375 | georg.brandl | 2008-08-01 19:41:11 +0000 (Fri, 01 Aug 2008) | 2 lines Fix the handling of non-ASCII input in quickstart. ........ r65377 | georg.brandl | 2008-08-01 19:48:24 +0000 (Fri, 01 Aug 2008) | 2 lines Allow REs in markup checks. ........ r65380 | georg.brandl | 2008-08-01 20:31:18 +0000 (Fri, 01 Aug 2008) | 2 lines Don't rely on mtimes being different for changed files. ........ r65483 | georg.brandl | 2008-08-04 09:01:40 +0000 (Mon, 04 Aug 2008) | 4 lines Add an "encoding" option to literalinclude. Add tests for include directives. ........ r65484 | georg.brandl | 2008-08-04 09:11:17 +0000 (Mon, 04 Aug 2008) | 2 lines Add changelog entry. ........ r65485 | georg.brandl | 2008-08-04 09:21:58 +0000 (Mon, 04 Aug 2008) | 2 lines Fix markup. ........ r65494 | georg.brandl | 2008-08-04 16:34:59 +0000 (Mon, 04 Aug 2008) | 2 lines Correctly use HTML file suffix in templates. ........
This commit is contained in:
1
EXAMPLES
1
EXAMPLES
@@ -20,6 +20,7 @@ to be included, please mail to sphinx-dev@googlegroups.com.
|
|||||||
* Py on Windows: http://timgolden.me.uk/python-on-windows/
|
* Py on Windows: http://timgolden.me.uk/python-on-windows/
|
||||||
* mpmath: http://mpmath.googlecode.com/svn/trunk/doc/build/index.html
|
* mpmath: http://mpmath.googlecode.com/svn/trunk/doc/build/index.html
|
||||||
* Zope 3: e.g. http://docs.carduner.net/z3c-tutorial/
|
* Zope 3: e.g. http://docs.carduner.net/z3c-tutorial/
|
||||||
|
* Glashammer: http://glashammer.welterde.de/
|
||||||
* SymPy: http://docs.sympy.org/
|
* SymPy: http://docs.sympy.org/
|
||||||
* Grok (upcoming)
|
* Grok (upcoming)
|
||||||
* Django (upcoming)
|
* Django (upcoming)
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -27,4 +27,4 @@ reindent:
|
|||||||
@$(PYTHON) utils/reindent.py -r -B .
|
@$(PYTHON) utils/reindent.py -r -B .
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@cd tests; $(PYTHON) run.py -d
|
@cd tests; $(PYTHON) run.py -d -m '^[tT]est' $(TEST)
|
||||||
|
|||||||
@@ -100,6 +100,15 @@ Includes
|
|||||||
:language: ruby
|
:language: ruby
|
||||||
:linenos:
|
:linenos:
|
||||||
|
|
||||||
|
Include files are assumed to be encoded in UTF-8. If the file has a different
|
||||||
|
encoding, you can specify it with the ``encoding`` option::
|
||||||
|
|
||||||
|
.. literalinclude:: example.py
|
||||||
|
:encoding: latin-1
|
||||||
|
|
||||||
|
.. versionadded:: 0.4.3
|
||||||
|
The ``encoding`` option.
|
||||||
|
|
||||||
|
|
||||||
.. rubric:: Footnotes
|
.. rubric:: Footnotes
|
||||||
|
|
||||||
|
|||||||
99
ez_setup.py
99
ez_setup.py
@@ -14,8 +14,8 @@ the appropriate options to ``use_setuptools()``.
|
|||||||
This file can also be run as a script to install or upgrade setuptools.
|
This file can also be run as a script to install or upgrade setuptools.
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
DEFAULT_VERSION = "0.6c5"
|
DEFAULT_VERSION = "0.6c8"
|
||||||
DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3]
|
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
|
||||||
|
|
||||||
md5_data = {
|
md5_data = {
|
||||||
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
|
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
|
||||||
@@ -39,6 +39,15 @@ md5_data = {
|
|||||||
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
|
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
|
||||||
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
|
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
|
||||||
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
|
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
|
||||||
|
'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
|
||||||
|
'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
|
||||||
|
'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
|
||||||
|
'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
|
||||||
|
'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
|
||||||
|
'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
|
||||||
|
'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
|
||||||
|
'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
|
||||||
|
'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
|
||||||
}
|
}
|
||||||
|
|
||||||
import sys, os
|
import sys, os
|
||||||
@@ -71,31 +80,31 @@ def use_setuptools(
|
|||||||
this routine will print a message to ``sys.stderr`` and raise SystemExit in
|
this routine will print a message to ``sys.stderr`` and raise SystemExit in
|
||||||
an attempt to abort the calling script.
|
an attempt to abort the calling script.
|
||||||
"""
|
"""
|
||||||
try:
|
was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
|
||||||
import setuptools
|
def do_download():
|
||||||
if setuptools.__version__ == '0.0.1':
|
|
||||||
print >>sys.stderr, (
|
|
||||||
"You have an obsolete version of setuptools installed. Please\n"
|
|
||||||
"remove it from your system entirely before rerunning this script."
|
|
||||||
)
|
|
||||||
sys.exit(2)
|
|
||||||
except ImportError:
|
|
||||||
egg = download_setuptools(version, download_base, to_dir, download_delay)
|
egg = download_setuptools(version, download_base, to_dir, download_delay)
|
||||||
sys.path.insert(0, egg)
|
sys.path.insert(0, egg)
|
||||||
import setuptools; setuptools.bootstrap_install_from = egg
|
import setuptools; setuptools.bootstrap_install_from = egg
|
||||||
|
|
||||||
import pkg_resources
|
|
||||||
try:
|
try:
|
||||||
pkg_resources.require("setuptools>="+version)
|
import pkg_resources
|
||||||
|
except ImportError:
|
||||||
|
return do_download()
|
||||||
|
try:
|
||||||
|
pkg_resources.require("setuptools>="+version); return
|
||||||
except pkg_resources.VersionConflict, e:
|
except pkg_resources.VersionConflict, e:
|
||||||
# XXX could we install in a subprocess here?
|
if was_imported:
|
||||||
print >>sys.stderr, (
|
print >>sys.stderr, (
|
||||||
"The required version of setuptools (>=%s) is not available, and\n"
|
"The required version of setuptools (>=%s) is not available, and\n"
|
||||||
"can't be installed while this script is running. Please install\n"
|
"can't be installed while this script is running. Please install\n"
|
||||||
" a more recent version first.\n\n(Currently using %r)"
|
" a more recent version first, using 'easy_install -U setuptools'."
|
||||||
) % (version, e.args[0])
|
"\n\n(Currently using %r)"
|
||||||
sys.exit(2)
|
) % (version, e.args[0])
|
||||||
|
sys.exit(2)
|
||||||
|
else:
|
||||||
|
del pkg_resources, sys.modules['pkg_resources'] # reload ok
|
||||||
|
return do_download()
|
||||||
|
except pkg_resources.DistributionNotFound:
|
||||||
|
return do_download()
|
||||||
|
|
||||||
def download_setuptools(
|
def download_setuptools(
|
||||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
|
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
|
||||||
@@ -144,9 +153,43 @@ and place it in this directory before rerunning this script.)
|
|||||||
if dst: dst.close()
|
if dst: dst.close()
|
||||||
return os.path.realpath(saveto)
|
return os.path.realpath(saveto)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv, version=DEFAULT_VERSION):
|
def main(argv, version=DEFAULT_VERSION):
|
||||||
"""Install or upgrade setuptools and EasyInstall"""
|
"""Install or upgrade setuptools and EasyInstall"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import setuptools
|
import setuptools
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -161,8 +204,11 @@ def main(argv, version=DEFAULT_VERSION):
|
|||||||
os.unlink(egg)
|
os.unlink(egg)
|
||||||
else:
|
else:
|
||||||
if setuptools.__version__ == '0.0.1':
|
if setuptools.__version__ == '0.0.1':
|
||||||
# tell the user to uninstall obsolete version
|
print >>sys.stderr, (
|
||||||
use_setuptools(version)
|
"You have an obsolete version of setuptools installed. Please\n"
|
||||||
|
"remove it from your system entirely before rerunning this script."
|
||||||
|
)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
req = "setuptools>="+version
|
req = "setuptools>="+version
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
@@ -183,8 +229,6 @@ def main(argv, version=DEFAULT_VERSION):
|
|||||||
print "Setuptools version",version,"or greater has been installed."
|
print "Setuptools version",version,"or greater has been installed."
|
||||||
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
|
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def update_md5(filenames):
|
def update_md5(filenames):
|
||||||
"""Update our built-in md5 registry"""
|
"""Update our built-in md5 registry"""
|
||||||
|
|
||||||
@@ -221,3 +265,8 @@ if __name__=='__main__':
|
|||||||
update_md5(sys.argv[2:])
|
update_md5(sys.argv[2:])
|
||||||
else:
|
else:
|
||||||
main(sys.argv[1:])
|
main(sys.argv[1:])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,9 @@ class Builder(object):
|
|||||||
node['uri'] = candidate
|
node['uri'] = candidate
|
||||||
else:
|
else:
|
||||||
candidate = node['uri']
|
candidate = node['uri']
|
||||||
|
if candidate not in self.env.images:
|
||||||
|
# non-existing URI; let it alone
|
||||||
|
continue
|
||||||
self.images[candidate] = self.env.images[candidate][1]
|
self.images[candidate] = self.env.images[candidate][1]
|
||||||
|
|
||||||
# build methods
|
# build methods
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import codecs
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
@@ -67,13 +68,19 @@ def literalinclude_directive(name, arguments, options, content, lineno,
|
|||||||
lineno - state_machine.input_offset - 1)))
|
lineno - state_machine.input_offset - 1)))
|
||||||
fn = path.normpath(path.join(source_dir, rel_fn))
|
fn = path.normpath(path.join(source_dir, rel_fn))
|
||||||
|
|
||||||
|
encoding = options.get('encoding', 'utf-8')
|
||||||
try:
|
try:
|
||||||
f = open(fn)
|
f = codecs.open(fn, 'r', encoding)
|
||||||
text = f.read()
|
text = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
retnode = state.document.reporter.warning(
|
retnode = state.document.reporter.warning(
|
||||||
'Include file %r not found or reading it failed' % arguments[0], line=lineno)
|
'Include file %r not found or reading it failed' % arguments[0], line=lineno)
|
||||||
|
except UnicodeError:
|
||||||
|
retnode = state.document.reporter.warning(
|
||||||
|
'Encoding %r used for reading included file %r seems to '
|
||||||
|
'be wrong, try giving an :encoding: option' %
|
||||||
|
(encoding, arguments[0]))
|
||||||
else:
|
else:
|
||||||
retnode = nodes.literal_block(text, text, source=fn)
|
retnode = nodes.literal_block(text, text, source=fn)
|
||||||
retnode.line = 1
|
retnode.line = 1
|
||||||
@@ -85,7 +92,8 @@ def literalinclude_directive(name, arguments, options, content, lineno,
|
|||||||
return [retnode]
|
return [retnode]
|
||||||
|
|
||||||
literalinclude_directive.options = {'linenos': directives.flag,
|
literalinclude_directive.options = {'linenos': directives.flag,
|
||||||
'language': directives.unchanged}
|
'language': directives.unchanged,
|
||||||
|
'encoding': directives.encoding}
|
||||||
literalinclude_directive.content = 0
|
literalinclude_directive.content = 0
|
||||||
literalinclude_directive.arguments = (1, 0, 0)
|
literalinclude_directive.arguments = (1, 0, 0)
|
||||||
directives.register_directive('literalinclude', literalinclude_directive)
|
directives.register_directive('literalinclude', literalinclude_directive)
|
||||||
|
|||||||
@@ -559,12 +559,12 @@ class BuildEnvironment:
|
|||||||
imgpath = path.normpath(path.join(docdir, imguri))
|
imgpath = path.normpath(path.join(docdir, imguri))
|
||||||
node['uri'] = imgpath
|
node['uri'] = imgpath
|
||||||
if imgpath.endswith(os.extsep + '*'):
|
if imgpath.endswith(os.extsep + '*'):
|
||||||
for filename in glob(imgpath):
|
for filename in glob(path.join(self.srcdir, imgpath)):
|
||||||
basename, ext = os.path.splitext(filename)
|
dir, base = path.split(filename)
|
||||||
if ext == '.pdf':
|
if base.lower().endswith('.pdf'):
|
||||||
candidates['application/pdf'] = filename
|
candidates['application/pdf'] = path.join(docdir, base)
|
||||||
elif ext == '.svg':
|
elif base.lower().endswith('.svg'):
|
||||||
candidates['image/svg+xml'] = filename
|
candidates['image/svg+xml'] = path.join(docdir, base)
|
||||||
else:
|
else:
|
||||||
f = open(filename, 'rb')
|
f = open(filename, 'rb')
|
||||||
try:
|
try:
|
||||||
@@ -572,23 +572,23 @@ class BuildEnvironment:
|
|||||||
finally:
|
finally:
|
||||||
f.close()
|
f.close()
|
||||||
if imgtype:
|
if imgtype:
|
||||||
candidates['image/' + imgtype] = filename
|
candidates['image/' + imgtype] = path.join(docdir, base)
|
||||||
else:
|
else:
|
||||||
candidates['*'] = imgpath
|
candidates['*'] = imgpath
|
||||||
for img in candidates.itervalues():
|
for imgpath in candidates.itervalues():
|
||||||
self.dependencies.setdefault(docname, set()).add(img)
|
self.dependencies.setdefault(docname, set()).add(imgpath)
|
||||||
if not os.access(path.join(self.srcdir, img), os.R_OK):
|
if not os.access(path.join(self.srcdir, imgpath), os.R_OK):
|
||||||
self.warn(docname, 'Image file not readable: %s' % img, node.line)
|
self.warn(docname, 'Image file not readable: %s' % imgpath, node.line)
|
||||||
if img in self.images:
|
if imgpath in self.images:
|
||||||
self.images[img][0].add(docname)
|
self.images[imgpath][0].add(docname)
|
||||||
continue
|
continue
|
||||||
uniquename = path.basename(img)
|
uniquename = path.basename(imgpath)
|
||||||
base, ext = path.splitext(uniquename)
|
base, ext = path.splitext(uniquename)
|
||||||
i = 0
|
i = 0
|
||||||
while uniquename in existing_names:
|
while uniquename in existing_names:
|
||||||
i += 1
|
i += 1
|
||||||
uniquename = '%s%s%s' % (base, i, ext)
|
uniquename = '%s%s%s' % (base, i, ext)
|
||||||
self.images[img] = (set([docname]), uniquename)
|
self.images[imgpath] = (set([docname]), uniquename)
|
||||||
existing_names.add(uniquename)
|
existing_names.add(uniquename)
|
||||||
|
|
||||||
def process_metadata(self, docname, doctree):
|
def process_metadata(self, docname, doctree):
|
||||||
|
|||||||
@@ -128,6 +128,13 @@ class PygmentsBridge(object):
|
|||||||
if sys.version_info >= (2, 5):
|
if sys.version_info >= (2, 5):
|
||||||
src = 'from __future__ import with_statement\n' + src
|
src = 'from __future__ import with_statement\n' + src
|
||||||
|
|
||||||
|
if isinstance(src, unicode):
|
||||||
|
# Non-ASCII chars will only occur in string literals
|
||||||
|
# and comments. If we wanted to give them to the parser
|
||||||
|
# correctly, we'd have to find out the correct source
|
||||||
|
# encoding. Since it may not even be given in a snippet,
|
||||||
|
# just replace all non-ASCII characters.
|
||||||
|
src = src.encode('ascii', 'replace')
|
||||||
try:
|
try:
|
||||||
parser.suite(src)
|
parser.suite(src)
|
||||||
except parsing_exceptions:
|
except parsing_exceptions:
|
||||||
|
|||||||
@@ -12,8 +12,10 @@
|
|||||||
import sys, os, time
|
import sys, os, time
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
|
TERM_ENCODING = getattr(sys.stdin, 'encoding', None)
|
||||||
|
|
||||||
from sphinx.util import make_filename
|
from sphinx.util import make_filename
|
||||||
from sphinx.util.console import purple, bold, red, nocolor
|
from sphinx.util.console import purple, bold, red, turquoise, nocolor
|
||||||
|
|
||||||
|
|
||||||
PROMPT_PREFIX = '> '
|
PROMPT_PREFIX = '> '
|
||||||
@@ -56,8 +58,8 @@ source_suffix = '%(suffix)s'
|
|||||||
master_doc = '%(master)s'
|
master_doc = '%(master)s'
|
||||||
|
|
||||||
# General substitutions.
|
# General substitutions.
|
||||||
project = %(project)r
|
project = u'%(project)s'
|
||||||
copyright = '%(year)s, %(author)s'
|
copyright = u'%(copyright)s'
|
||||||
|
|
||||||
# The default replacements for |version| and |release|, also used in various
|
# The default replacements for |version| and |release|, also used in various
|
||||||
# other places throughout the built documents.
|
# other places throughout the built documents.
|
||||||
@@ -178,8 +180,8 @@ htmlhelp_basename = '%(project_fn)sdoc'
|
|||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title, author, document class [howto/manual]).
|
# (source start file, target name, title, author, document class [howto/manual]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('%(master)s', '%(project_fn)s.tex', '%(project)s Documentation',
|
('%(master)s', '%(project_fn)s.tex', u'%(project_doc)s',
|
||||||
'%(author)s', 'manual'),
|
u'%(author)s', 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
@@ -343,8 +345,18 @@ def do_prompt(d, key, text, default=None, validator=nonempty):
|
|||||||
x = raw_input(prompt)
|
x = raw_input(prompt)
|
||||||
if default and not x:
|
if default and not x:
|
||||||
x = default
|
x = default
|
||||||
|
if x.decode('ascii', 'replace').encode('ascii', 'replace') != x:
|
||||||
|
if TERM_ENCODING:
|
||||||
|
x = x.decode(TERM_ENCODING)
|
||||||
|
else:
|
||||||
|
print turquoise('* Note: non-ASCII characters entered and terminal '
|
||||||
|
'encoding unknown -- assuming UTF-8 or Latin-1.')
|
||||||
|
try:
|
||||||
|
x = x.decode('utf-8')
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
x = x.decode('latin1')
|
||||||
if validator and not validator(x):
|
if validator and not validator(x):
|
||||||
print red(" * " + validator.__doc__)
|
print red('* ' + validator.__doc__)
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
d[key] = x
|
d[key] = x
|
||||||
@@ -414,12 +426,13 @@ directly.'''
|
|||||||
os.name == 'posix' and 'y' or 'n', boolean)
|
os.name == 'posix' and 'y' or 'n', boolean)
|
||||||
|
|
||||||
d['project_fn'] = make_filename(d['project'])
|
d['project_fn'] = make_filename(d['project'])
|
||||||
d['year'] = time.strftime('%Y')
|
|
||||||
d['now'] = time.asctime()
|
d['now'] = time.asctime()
|
||||||
d['underline'] = len(d['project']) * '='
|
d['underline'] = len(d['project']) * '='
|
||||||
d['extensions'] = ', '.join(
|
d['extensions'] = ', '.join(
|
||||||
repr('sphinx.ext.' + name) for name in ('autodoc', 'doctest')
|
repr('sphinx.ext.' + name) for name in ('autodoc', 'doctest')
|
||||||
if d['ext_' + name].upper() in ('Y', 'YES'))
|
if d['ext_' + name].upper() in ('Y', 'YES'))
|
||||||
|
d['copyright'] = time.strftime('%Y') + ', ' + d['author']
|
||||||
|
d['project_doc'] = d['project'] + ' Documentation'
|
||||||
|
|
||||||
if not path.isdir(d['path']):
|
if not path.isdir(d['path']):
|
||||||
mkdir_p(d['path'])
|
mkdir_p(d['path'])
|
||||||
@@ -437,12 +450,12 @@ directly.'''
|
|||||||
mkdir_p(path.join(srcdir, d['dot'] + 'static'))
|
mkdir_p(path.join(srcdir, d['dot'] + 'static'))
|
||||||
|
|
||||||
f = open(path.join(srcdir, 'conf.py'), 'w')
|
f = open(path.join(srcdir, 'conf.py'), 'w')
|
||||||
f.write(QUICKSTART_CONF % d)
|
f.write((QUICKSTART_CONF % d).encode('utf-8'))
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
masterfile = path.join(srcdir, d['master'] + d['suffix'])
|
masterfile = path.join(srcdir, d['master'] + d['suffix'])
|
||||||
f = open(masterfile, 'w')
|
f = open(masterfile, 'w')
|
||||||
f.write(MASTER_FILE % d)
|
f.write((MASTER_FILE % d).encode('utf-8'))
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
create_makefile = d['makefile'].upper() in ('Y', 'YES')
|
create_makefile = d['makefile'].upper() in ('Y', 'YES')
|
||||||
@@ -450,7 +463,7 @@ directly.'''
|
|||||||
d['rsrcdir'] = separate and 'source' or '.'
|
d['rsrcdir'] = separate and 'source' or '.'
|
||||||
d['rbuilddir'] = separate and 'build' or d['dot'] + 'build'
|
d['rbuilddir'] = separate and 'build' or d['dot'] + 'build'
|
||||||
f = open(path.join(d['path'], 'Makefile'), 'w')
|
f = open(path.join(d['path'], 'Makefile'), 'w')
|
||||||
f.write(MAKEFILE % d)
|
f.write((MAKEFILE % d).encode('utf-8'))
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
print
|
print
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ def patfilter(names, pat):
|
|||||||
return filter(match, names)
|
return filter(match, names)
|
||||||
|
|
||||||
|
|
||||||
no_fn_re = re.compile(r'[:/\\?*%|"\'<>. \t]')
|
no_fn_re = re.compile(r'[^a-zA-Z0-9_-]')
|
||||||
|
|
||||||
def make_filename(string):
|
def make_filename(string):
|
||||||
return no_fn_re.sub('', string)
|
return no_fn_re.sub('', string)
|
||||||
|
|||||||
226
tests/etree13/ElementPath.py
Normal file
226
tests/etree13/ElementPath.py
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
#
|
||||||
|
# ElementTree
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
# limited xpath support for element trees
|
||||||
|
#
|
||||||
|
# history:
|
||||||
|
# 2003-05-23 fl created
|
||||||
|
# 2003-05-28 fl added support for // etc
|
||||||
|
# 2003-08-27 fl fixed parsing of periods in element names
|
||||||
|
# 2007-09-10 fl new selection engine
|
||||||
|
#
|
||||||
|
# Copyright (c) 2003-2007 by Fredrik Lundh. All rights reserved.
|
||||||
|
#
|
||||||
|
# fredrik@pythonware.com
|
||||||
|
# http://www.pythonware.com
|
||||||
|
#
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# The ElementTree toolkit is
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999-2007 by Fredrik Lundh
|
||||||
|
#
|
||||||
|
# By obtaining, using, and/or copying this software and/or its
|
||||||
|
# associated documentation, you agree that you have read, understood,
|
||||||
|
# and will comply with the following terms and conditions:
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software and
|
||||||
|
# its associated documentation for any purpose and without fee is
|
||||||
|
# hereby granted, provided that the above copyright notice appears in
|
||||||
|
# all copies, and that both that copyright notice and this permission
|
||||||
|
# notice appear in supporting documentation, and that the name of
|
||||||
|
# Secret Labs AB or the author not be used in advertising or publicity
|
||||||
|
# pertaining to distribution of the software without specific, written
|
||||||
|
# prior permission.
|
||||||
|
#
|
||||||
|
# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
|
||||||
|
# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
|
||||||
|
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
||||||
|
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||||
|
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||||
|
# OF THIS SOFTWARE.
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
##
|
||||||
|
# Implementation module for XPath support. There's usually no reason
|
||||||
|
# to import this module directly; the <b>ElementTree</b> does this for
|
||||||
|
# you, if needed.
|
||||||
|
##
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
xpath_tokenizer = re.compile(
|
||||||
|
"("
|
||||||
|
"'[^']*'|\"[^\"]*\"|"
|
||||||
|
"::|"
|
||||||
|
"//?|"
|
||||||
|
"\.\.|"
|
||||||
|
"\(\)|"
|
||||||
|
"[/.*:\[\]\(\)@=])|"
|
||||||
|
"((?:\{[^}]+\})?[^/:\[\]\(\)@=\s]+)|"
|
||||||
|
"\s+"
|
||||||
|
).findall
|
||||||
|
|
||||||
|
def prepare_tag(next, token):
|
||||||
|
tag = token[1]
|
||||||
|
def select(context, result):
|
||||||
|
for elem in result:
|
||||||
|
for e in elem:
|
||||||
|
if e.tag == tag:
|
||||||
|
yield e
|
||||||
|
return select
|
||||||
|
|
||||||
|
def prepare_star(next, token):
|
||||||
|
def select(context, result):
|
||||||
|
for elem in result:
|
||||||
|
for e in elem:
|
||||||
|
yield e
|
||||||
|
return select
|
||||||
|
|
||||||
|
def prepare_dot(next, token):
|
||||||
|
def select(context, result):
|
||||||
|
for elem in result:
|
||||||
|
yield elem
|
||||||
|
return select
|
||||||
|
|
||||||
|
def prepare_iter(next, token):
|
||||||
|
token = next()
|
||||||
|
if token[0] == "*":
|
||||||
|
tag = "*"
|
||||||
|
elif not token[0]:
|
||||||
|
tag = token[1]
|
||||||
|
else:
|
||||||
|
raise SyntaxError
|
||||||
|
def select(context, result):
|
||||||
|
for elem in result:
|
||||||
|
for e in elem.iter(tag):
|
||||||
|
if e is not elem:
|
||||||
|
yield e
|
||||||
|
return select
|
||||||
|
|
||||||
|
def prepare_dot_dot(next, token):
|
||||||
|
def select(context, result):
|
||||||
|
parent_map = context.parent_map
|
||||||
|
if parent_map is None:
|
||||||
|
context.parent_map = parent_map = {}
|
||||||
|
for p in context.root.iter():
|
||||||
|
for e in p:
|
||||||
|
parent_map[e] = p
|
||||||
|
for elem in result:
|
||||||
|
if elem in parent_map:
|
||||||
|
yield parent_map[elem]
|
||||||
|
return select
|
||||||
|
|
||||||
|
def prepare_predicate(next, token):
|
||||||
|
# this one should probably be refactored...
|
||||||
|
token = next()
|
||||||
|
if token[0] == "@":
|
||||||
|
# attribute
|
||||||
|
token = next()
|
||||||
|
if token[0]:
|
||||||
|
raise SyntaxError("invalid attribute predicate")
|
||||||
|
key = token[1]
|
||||||
|
token = next()
|
||||||
|
if token[0] == "]":
|
||||||
|
def select(context, result):
|
||||||
|
for elem in result:
|
||||||
|
if elem.get(key) is not None:
|
||||||
|
yield elem
|
||||||
|
elif token[0] == "=":
|
||||||
|
value = next()[0]
|
||||||
|
if value[:1] == "'" or value[:1] == '"':
|
||||||
|
value = value[1:-1]
|
||||||
|
else:
|
||||||
|
raise SyntaxError("invalid comparision target")
|
||||||
|
token = next()
|
||||||
|
def select(context, result):
|
||||||
|
for elem in result:
|
||||||
|
if elem.get(key) == value:
|
||||||
|
yield elem
|
||||||
|
if token[0] != "]":
|
||||||
|
raise SyntaxError("invalid attribute predicate")
|
||||||
|
elif not token[0]:
|
||||||
|
tag = token[1]
|
||||||
|
token = next()
|
||||||
|
if token[0] != "]":
|
||||||
|
raise SyntaxError("invalid node predicate")
|
||||||
|
def select(context, result):
|
||||||
|
for elem in result:
|
||||||
|
if elem.find(tag) is not None:
|
||||||
|
yield elem
|
||||||
|
else:
|
||||||
|
raise SyntaxError("invalid predicate")
|
||||||
|
return select
|
||||||
|
|
||||||
|
ops = {
|
||||||
|
"": prepare_tag,
|
||||||
|
"*": prepare_star,
|
||||||
|
".": prepare_dot,
|
||||||
|
"..": prepare_dot_dot,
|
||||||
|
"//": prepare_iter,
|
||||||
|
"[": prepare_predicate,
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache = {}
|
||||||
|
|
||||||
|
class _SelectorContext:
|
||||||
|
parent_map = None
|
||||||
|
def __init__(self, root):
|
||||||
|
self.root = root
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
##
|
||||||
|
# Find first matching object.
|
||||||
|
|
||||||
|
def find(elem, path):
|
||||||
|
try:
|
||||||
|
return findall(elem, path).next()
|
||||||
|
except StopIteration:
|
||||||
|
return None
|
||||||
|
|
||||||
|
##
|
||||||
|
# Find all matching objects.
|
||||||
|
|
||||||
|
def findall(elem, path):
|
||||||
|
# compile selector pattern
|
||||||
|
try:
|
||||||
|
selector = _cache[path]
|
||||||
|
except KeyError:
|
||||||
|
if len(_cache) > 100:
|
||||||
|
_cache.clear()
|
||||||
|
if path[:1] == "/":
|
||||||
|
raise SyntaxError("cannot use absolute path on element")
|
||||||
|
stream = iter(xpath_tokenizer(path))
|
||||||
|
next = stream.next; token = next()
|
||||||
|
selector = []
|
||||||
|
while 1:
|
||||||
|
try:
|
||||||
|
selector.append(ops[token[0]](next, token))
|
||||||
|
except StopIteration:
|
||||||
|
raise SyntaxError("invalid path")
|
||||||
|
try:
|
||||||
|
token = next()
|
||||||
|
if token[0] == "/":
|
||||||
|
token = next()
|
||||||
|
except StopIteration:
|
||||||
|
break
|
||||||
|
_cache[path] = selector
|
||||||
|
# execute selector pattern
|
||||||
|
result = [elem]
|
||||||
|
context = _SelectorContext(elem)
|
||||||
|
for select in selector:
|
||||||
|
result = select(context, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
##
|
||||||
|
# Find text for first matching object.
|
||||||
|
|
||||||
|
def findtext(elem, path, default=None):
|
||||||
|
try:
|
||||||
|
elem = findall(elem, path).next()
|
||||||
|
return elem.text
|
||||||
|
except StopIteration:
|
||||||
|
return default
|
||||||
1542
tests/etree13/ElementTree.py
Normal file
1542
tests/etree13/ElementTree.py
Normal file
File diff suppressed because it is too large
Load Diff
230
tests/etree13/HTMLTreeBuilder.py
Normal file
230
tests/etree13/HTMLTreeBuilder.py
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
#
|
||||||
|
# ElementTree
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
# a simple tree builder, for HTML input
|
||||||
|
#
|
||||||
|
# history:
|
||||||
|
# 2002-04-06 fl created
|
||||||
|
# 2002-04-07 fl ignore IMG and HR end tags
|
||||||
|
# 2002-04-07 fl added support for 1.5.2 and later
|
||||||
|
# 2003-04-13 fl added HTMLTreeBuilder alias
|
||||||
|
# 2004-12-02 fl don't feed non-ASCII charrefs/entities as 8-bit strings
|
||||||
|
# 2004-12-05 fl don't feed non-ASCII CDATA as 8-bit strings
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999-2004 by Fredrik Lundh. All rights reserved.
|
||||||
|
#
|
||||||
|
# fredrik@pythonware.com
|
||||||
|
# http://www.pythonware.com
|
||||||
|
#
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# The ElementTree toolkit is
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999-2007 by Fredrik Lundh
|
||||||
|
#
|
||||||
|
# By obtaining, using, and/or copying this software and/or its
|
||||||
|
# associated documentation, you agree that you have read, understood,
|
||||||
|
# and will comply with the following terms and conditions:
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software and
|
||||||
|
# its associated documentation for any purpose and without fee is
|
||||||
|
# hereby granted, provided that the above copyright notice appears in
|
||||||
|
# all copies, and that both that copyright notice and this permission
|
||||||
|
# notice appear in supporting documentation, and that the name of
|
||||||
|
# Secret Labs AB or the author not be used in advertising or publicity
|
||||||
|
# pertaining to distribution of the software without specific, written
|
||||||
|
# prior permission.
|
||||||
|
#
|
||||||
|
# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
|
||||||
|
# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
|
||||||
|
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
||||||
|
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||||
|
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||||
|
# OF THIS SOFTWARE.
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
##
|
||||||
|
# Tools to build element trees from HTML files.
|
||||||
|
##
|
||||||
|
|
||||||
|
import htmlentitydefs
|
||||||
|
import re, string, sys
|
||||||
|
import mimetools, StringIO
|
||||||
|
|
||||||
|
import ElementTree
|
||||||
|
|
||||||
|
AUTOCLOSE = "p", "li", "tr", "th", "td", "head", "body"
|
||||||
|
IGNOREEND = "img", "hr", "meta", "link", "br"
|
||||||
|
|
||||||
|
if sys.version[:3] == "1.5":
|
||||||
|
is_not_ascii = re.compile(r"[\x80-\xff]").search # 1.5.2
|
||||||
|
else:
|
||||||
|
is_not_ascii = re.compile(eval(r'u"[\u0080-\uffff]"')).search
|
||||||
|
|
||||||
|
try:
|
||||||
|
from HTMLParser import HTMLParser
|
||||||
|
except ImportError:
|
||||||
|
from sgmllib import SGMLParser
|
||||||
|
# hack to use sgmllib's SGMLParser to emulate 2.2's HTMLParser
|
||||||
|
class HTMLParser(SGMLParser):
|
||||||
|
# the following only works as long as this class doesn't
|
||||||
|
# provide any do, start, or end handlers
|
||||||
|
def unknown_starttag(self, tag, attrs):
|
||||||
|
self.handle_starttag(tag, attrs)
|
||||||
|
def unknown_endtag(self, tag):
|
||||||
|
self.handle_endtag(tag)
|
||||||
|
|
||||||
|
##
|
||||||
|
# ElementTree builder for HTML source code. This builder converts an
|
||||||
|
# HTML document or fragment to an ElementTree.
|
||||||
|
# <p>
|
||||||
|
# The parser is relatively picky, and requires balanced tags for most
|
||||||
|
# elements. However, elements belonging to the following group are
|
||||||
|
# automatically closed: P, LI, TR, TH, and TD. In addition, the
|
||||||
|
# parser automatically inserts end tags immediately after the start
|
||||||
|
# tag, and ignores any end tags for the following group: IMG, HR,
|
||||||
|
# META, and LINK.
|
||||||
|
#
|
||||||
|
# @keyparam builder Optional builder object. If omitted, the parser
|
||||||
|
# uses the standard <b>elementtree</b> builder.
|
||||||
|
# @keyparam encoding Optional character encoding, if known. If omitted,
|
||||||
|
# the parser looks for META tags inside the document. If no tags
|
||||||
|
# are found, the parser defaults to ISO-8859-1. Note that if your
|
||||||
|
# document uses a non-ASCII compatible encoding, you must decode
|
||||||
|
# the document before parsing.
|
||||||
|
#
|
||||||
|
# @see elementtree.ElementTree
|
||||||
|
|
||||||
|
class HTMLTreeBuilder(HTMLParser):
|
||||||
|
|
||||||
|
# FIXME: shouldn't this class be named Parser, not Builder?
|
||||||
|
|
||||||
|
def __init__(self, builder=None, encoding=None):
|
||||||
|
self.__stack = []
|
||||||
|
if builder is None:
|
||||||
|
builder = ElementTree.TreeBuilder()
|
||||||
|
self.__builder = builder
|
||||||
|
self.encoding = encoding or "iso-8859-1"
|
||||||
|
HTMLParser.__init__(self)
|
||||||
|
|
||||||
|
##
|
||||||
|
# Flushes parser buffers, and return the root element.
|
||||||
|
#
|
||||||
|
# @return An Element instance.
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
HTMLParser.close(self)
|
||||||
|
return self.__builder.close()
|
||||||
|
|
||||||
|
##
|
||||||
|
# (Internal) Handles start tags.
|
||||||
|
|
||||||
|
def handle_starttag(self, tag, attrs):
|
||||||
|
if tag == "meta":
|
||||||
|
# look for encoding directives
|
||||||
|
http_equiv = content = None
|
||||||
|
for k, v in attrs:
|
||||||
|
if k == "http-equiv":
|
||||||
|
http_equiv = string.lower(v)
|
||||||
|
elif k == "content":
|
||||||
|
content = v
|
||||||
|
if http_equiv == "content-type" and content:
|
||||||
|
# use mimetools to parse the http header
|
||||||
|
header = mimetools.Message(
|
||||||
|
StringIO.StringIO("%s: %s\n\n" % (http_equiv, content))
|
||||||
|
)
|
||||||
|
encoding = header.getparam("charset")
|
||||||
|
if encoding:
|
||||||
|
self.encoding = encoding
|
||||||
|
if tag in AUTOCLOSE:
|
||||||
|
if self.__stack and self.__stack[-1] == tag:
|
||||||
|
self.handle_endtag(tag)
|
||||||
|
self.__stack.append(tag)
|
||||||
|
attrib = {}
|
||||||
|
if attrs:
|
||||||
|
for k, v in attrs:
|
||||||
|
attrib[string.lower(k)] = v
|
||||||
|
self.__builder.start(tag, attrib)
|
||||||
|
if tag in IGNOREEND:
|
||||||
|
self.__stack.pop()
|
||||||
|
self.__builder.end(tag)
|
||||||
|
|
||||||
|
##
|
||||||
|
# (Internal) Handles end tags.
|
||||||
|
|
||||||
|
def handle_endtag(self, tag):
|
||||||
|
if tag in IGNOREEND:
|
||||||
|
return
|
||||||
|
lasttag = self.__stack.pop()
|
||||||
|
if tag != lasttag and lasttag in AUTOCLOSE:
|
||||||
|
self.handle_endtag(lasttag)
|
||||||
|
self.__builder.end(tag)
|
||||||
|
|
||||||
|
##
|
||||||
|
# (Internal) Handles character references.
|
||||||
|
|
||||||
|
def handle_charref(self, char):
|
||||||
|
if char[:1] == "x":
|
||||||
|
char = int(char[1:], 16)
|
||||||
|
else:
|
||||||
|
char = int(char)
|
||||||
|
if 0 <= char < 128:
|
||||||
|
self.__builder.data(chr(char))
|
||||||
|
else:
|
||||||
|
self.__builder.data(unichr(char))
|
||||||
|
|
||||||
|
##
|
||||||
|
# (Internal) Handles entity references.
|
||||||
|
|
||||||
|
def handle_entityref(self, name):
|
||||||
|
entity = htmlentitydefs.entitydefs.get(name)
|
||||||
|
if entity:
|
||||||
|
if len(entity) == 1:
|
||||||
|
entity = ord(entity)
|
||||||
|
else:
|
||||||
|
entity = int(entity[2:-1])
|
||||||
|
if 0 <= entity < 128:
|
||||||
|
self.__builder.data(chr(entity))
|
||||||
|
else:
|
||||||
|
self.__builder.data(unichr(entity))
|
||||||
|
else:
|
||||||
|
self.unknown_entityref(name)
|
||||||
|
|
||||||
|
##
|
||||||
|
# (Internal) Handles character data.
|
||||||
|
|
||||||
|
def handle_data(self, data):
|
||||||
|
if isinstance(data, type('')) and is_not_ascii(data):
|
||||||
|
# convert to unicode, but only if necessary
|
||||||
|
data = unicode(data, self.encoding, "ignore")
|
||||||
|
self.__builder.data(data)
|
||||||
|
|
||||||
|
##
|
||||||
|
# (Hook) Handles unknown entity references. The default action
|
||||||
|
# is to ignore unknown entities.
|
||||||
|
|
||||||
|
def unknown_entityref(self, name):
|
||||||
|
pass # ignore by default; override if necessary
|
||||||
|
|
||||||
|
##
|
||||||
|
# An alias for the <b>HTMLTreeBuilder</b> class.
|
||||||
|
|
||||||
|
TreeBuilder = HTMLTreeBuilder
|
||||||
|
|
||||||
|
##
|
||||||
|
# Parse an HTML document or document fragment.
|
||||||
|
#
|
||||||
|
# @param source A filename or file object containing HTML data.
|
||||||
|
# @param encoding Optional character encoding, if known. If omitted,
|
||||||
|
# the parser looks for META tags inside the document. If no tags
|
||||||
|
# are found, the parser defaults to ISO-8859-1.
|
||||||
|
# @return An ElementTree instance
|
||||||
|
|
||||||
|
def parse(source, encoding=None):
|
||||||
|
return ElementTree.parse(source, HTMLTreeBuilder(encoding=encoding))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
ElementTree.dump(parse(open(sys.argv[1])))
|
||||||
30
tests/etree13/__init__.py
Normal file
30
tests/etree13/__init__.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# $Id$
|
||||||
|
# elementtree package
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# The ElementTree toolkit is
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999-2007 by Fredrik Lundh
|
||||||
|
#
|
||||||
|
# By obtaining, using, and/or copying this software and/or its
|
||||||
|
# associated documentation, you agree that you have read, understood,
|
||||||
|
# and will comply with the following terms and conditions:
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software and
|
||||||
|
# its associated documentation for any purpose and without fee is
|
||||||
|
# hereby granted, provided that the above copyright notice appears in
|
||||||
|
# all copies, and that both that copyright notice and this permission
|
||||||
|
# notice appear in supporting documentation, and that the name of
|
||||||
|
# Secret Labs AB or the author not be used in advertising or publicity
|
||||||
|
# pertaining to distribution of the software without specific, written
|
||||||
|
# prior permission.
|
||||||
|
#
|
||||||
|
# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
|
||||||
|
# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
|
||||||
|
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
||||||
|
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||||
|
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||||
|
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||||
|
# OF THIS SOFTWARE.
|
||||||
|
# --------------------------------------------------------------------
|
||||||
@@ -32,7 +32,7 @@ templates_path = ['_templates']
|
|||||||
source_suffix = '.txt'
|
source_suffix = '.txt'
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = 'contents'
|
||||||
|
|
||||||
# General substitutions.
|
# General substitutions.
|
||||||
project = 'Sphinx Tests'
|
project = 'Sphinx Tests'
|
||||||
|
|||||||
@@ -10,10 +10,12 @@ Contents:
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
images
|
||||||
|
includes
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
==================
|
||||||
|
|
||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
* :ref:`modindex`
|
* :ref:`modindex`
|
||||||
* :ref:`search`
|
* :ref:`search`
|
||||||
|
|
||||||
|
|||||||
20
tests/root/images.txt
Normal file
20
tests/root/images.txt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
Sphinx image handling
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. first, a simple test with direct filename
|
||||||
|
.. image:: img.png
|
||||||
|
|
||||||
|
.. a non-existing image with direct filename
|
||||||
|
.. image:: foo.png
|
||||||
|
|
||||||
|
.. an image with path name (relative to this directory!)
|
||||||
|
.. image:: subdir/img.png
|
||||||
|
|
||||||
|
.. an image with unspecified extension
|
||||||
|
.. image:: img.*
|
||||||
|
|
||||||
|
.. a non-existing image with .*
|
||||||
|
.. image:: foo.*
|
||||||
|
|
||||||
|
.. a non-local image URI
|
||||||
|
.. image:: http://www.python.org/logo.png
|
||||||
BIN
tests/root/img.gif
Normal file
BIN
tests/root/img.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
tests/root/img.pdf
Normal file
BIN
tests/root/img.pdf
Normal file
Binary file not shown.
BIN
tests/root/img.png
Normal file
BIN
tests/root/img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
16
tests/root/includes.txt
Normal file
16
tests/root/includes.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
Test file and literal inclusion
|
||||||
|
===============================
|
||||||
|
|
||||||
|
.. include:: subdir/include.inc
|
||||||
|
|
||||||
|
.. literalinclude:: literal.inc
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
.. should give a warning
|
||||||
|
.. literalinclude:: wrongenc.inc
|
||||||
|
|
||||||
|
.. should succeed
|
||||||
|
.. literalinclude:: wrongenc.inc
|
||||||
|
:encoding: latin-1
|
||||||
|
.. include:: wrongenc.inc
|
||||||
|
:encoding: latin-1
|
||||||
4
tests/root/literal.inc
Normal file
4
tests/root/literal.inc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Literally included file using Python highlighting
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
foo = u"Including Unicode characters: üöä"
|
||||||
BIN
tests/root/subdir/img.png
Normal file
BIN
tests/root/subdir/img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
5
tests/root/subdir/include.inc
Normal file
5
tests/root/subdir/include.inc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.. This file is included by contents.txt.
|
||||||
|
|
||||||
|
.. Paths in included files are relative to the file that
|
||||||
|
includes them
|
||||||
|
.. image:: ../root/img.png
|
||||||
3
tests/root/wrongenc.inc
Normal file
3
tests/root/wrongenc.inc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
This file is encoded in latin-1 but at first read as utf-8.
|
||||||
|
|
||||||
|
Max Strau<EFBFBD> a<EFBFBD> in M<EFBFBD>nchen eine Leberk<EFBFBD>ssemmel.
|
||||||
95
tests/test_build.py
Normal file
95
tests/test_build.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_build
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
Test the entire build process with the test root.
|
||||||
|
|
||||||
|
:copyright: 2008 by Georg Brandl.
|
||||||
|
:license: BSD.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import htmlentitydefs
|
||||||
|
from StringIO import StringIO
|
||||||
|
from etree13 import ElementTree as ET
|
||||||
|
|
||||||
|
from util import *
|
||||||
|
|
||||||
|
from sphinx.builder import StandaloneHTMLBuilder, LaTeXBuilder
|
||||||
|
|
||||||
|
|
||||||
|
html_warnfile = StringIO()
|
||||||
|
latex_warnfile = StringIO()
|
||||||
|
|
||||||
|
ENV_WARNINGS = """\
|
||||||
|
WARNING: %(root)s/images.txt:9: Image file not readable: foo.png
|
||||||
|
WARNING: %(root)s/images.txt:20: Nonlocal image URI found: http://www.python.org/logo.png
|
||||||
|
WARNING: %(root)s/includes.txt:: (WARNING/2) Encoding 'utf-8' used for reading included file u'wrongenc.inc' seems to be wrong, try giving an :encoding: option
|
||||||
|
"""
|
||||||
|
|
||||||
|
HTML_WARNINGS = ENV_WARNINGS + """\
|
||||||
|
WARNING: %(root)s/images.txt:: no matching candidate for image URI u'foo.*'
|
||||||
|
"""
|
||||||
|
|
||||||
|
LATEX_WARNINGS = ENV_WARNINGS + """\
|
||||||
|
WARNING: None:: no matching candidate for image URI u'foo.*'
|
||||||
|
"""
|
||||||
|
|
||||||
|
HTML_XPATH = {
|
||||||
|
'images.html': {
|
||||||
|
".//img[@src='_images/img.png']": '',
|
||||||
|
".//img[@src='_images/img1.png']": '',
|
||||||
|
},
|
||||||
|
'includes.html': {
|
||||||
|
".//pre/span[@class='s']": u'üöä',
|
||||||
|
".//pre": u'Max Strauß',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
@with_testapp(buildername='html', warning=html_warnfile)
|
||||||
|
def test_html(app):
|
||||||
|
app.builder.build_all()
|
||||||
|
html_warnings = html_warnfile.getvalue().replace(os.sep, '/')
|
||||||
|
assert html_warnings == HTML_WARNINGS % {'root': app.srcdir}
|
||||||
|
|
||||||
|
if not ET:
|
||||||
|
return
|
||||||
|
for fname, paths in HTML_XPATH.iteritems():
|
||||||
|
parser = NslessParser()
|
||||||
|
parser.entity.update(htmlentitydefs.entitydefs)
|
||||||
|
etree = ET.parse(app.outdir / fname, parser)
|
||||||
|
for path, text in paths.iteritems():
|
||||||
|
nodes = list(etree.findall(path))
|
||||||
|
assert nodes != []
|
||||||
|
if not text:
|
||||||
|
# only check for node presence
|
||||||
|
continue
|
||||||
|
for node in nodes:
|
||||||
|
if node.text and text in node.text:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
assert False, ('%r not found in any node matching '
|
||||||
|
'path %s in %s' % (text, path, fname))
|
||||||
|
|
||||||
|
|
||||||
|
@with_testapp(buildername='latex', warning=latex_warnfile)
|
||||||
|
def test_latex(app):
|
||||||
|
app.builder.build_all()
|
||||||
|
latex_warnings = latex_warnfile.getvalue().replace(os.sep, '/')
|
||||||
|
assert latex_warnings == LATEX_WARNINGS % {'root': app.srcdir}
|
||||||
@@ -15,9 +15,9 @@ from util import *
|
|||||||
from sphinx.application import ExtensionError
|
from sphinx.application import ExtensionError
|
||||||
|
|
||||||
|
|
||||||
def test_core_config():
|
@with_testapp(confoverrides={'master_doc': 'master', 'nonexisting_value': 'True'})
|
||||||
overrides = {'master_doc': 'master', 'nonexisting_value': 'True'}
|
def test_core_config(app):
|
||||||
cfg = TestApp(confoverrides=overrides).config
|
cfg = app.config
|
||||||
|
|
||||||
# simple values
|
# simple values
|
||||||
assert 'project' in cfg.__dict__
|
assert 'project' in cfg.__dict__
|
||||||
@@ -61,8 +61,8 @@ def test_core_config():
|
|||||||
assert cfg['project'] == cfg.project == 'Sphinx Tests'
|
assert cfg['project'] == cfg.project == 'Sphinx Tests'
|
||||||
|
|
||||||
|
|
||||||
def test_extension_values():
|
@with_testapp()
|
||||||
app = TestApp()
|
def test_extension_values(app):
|
||||||
cfg = app.config
|
cfg = app.config
|
||||||
|
|
||||||
# default value
|
# default value
|
||||||
|
|||||||
81
tests/test_env.py
Normal file
81
tests/test_env.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_env
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Test the BuildEnvironment class.
|
||||||
|
|
||||||
|
:copyright: 2008 by Georg Brandl.
|
||||||
|
:license: BSD.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from util import *
|
||||||
|
|
||||||
|
from sphinx.environment import BuildEnvironment
|
||||||
|
from sphinx.builder import StandaloneHTMLBuilder, LaTeXBuilder
|
||||||
|
|
||||||
|
app = env = None
|
||||||
|
warnings = []
|
||||||
|
|
||||||
|
def setup_module():
|
||||||
|
global app, env
|
||||||
|
app = TestApp(srcdir='(temp)')
|
||||||
|
env = BuildEnvironment(app.srcdir, app.doctreedir, app.config)
|
||||||
|
env.set_warnfunc(warnings.append)
|
||||||
|
|
||||||
|
def teardown_module():
|
||||||
|
app.cleanup()
|
||||||
|
|
||||||
|
def warning_emitted(file, text):
|
||||||
|
for warning in warnings:
|
||||||
|
if file+':' in warning and text in warning:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Tests are run in the order they appear in the file, therefore we can
|
||||||
|
# afford to not run update() in the setup but in its own test
|
||||||
|
|
||||||
|
def test_first_update():
|
||||||
|
it = env.update(app.config, app.srcdir, app.doctreedir, app)
|
||||||
|
msg = it.next()
|
||||||
|
assert msg.endswith('%d added, 0 changed, 0 removed' % len(env.found_docs))
|
||||||
|
docnames = set()
|
||||||
|
for docname in it: # the generator does all the work
|
||||||
|
docnames.add(docname)
|
||||||
|
assert docnames == env.found_docs == set(env.all_docs)
|
||||||
|
|
||||||
|
def test_images():
|
||||||
|
assert warning_emitted('images.txt', 'Image file not readable: foo.png')
|
||||||
|
assert warning_emitted('images.txt', 'Nonlocal image URI found: '
|
||||||
|
'http://www.python.org/logo.png')
|
||||||
|
|
||||||
|
tree = env.get_doctree('images')
|
||||||
|
app._warning.reset()
|
||||||
|
htmlbuilder = StandaloneHTMLBuilder(app, env)
|
||||||
|
htmlbuilder.post_process_images(tree)
|
||||||
|
assert "no matching candidate for image URI u'foo.*'" in app._warning.content[-1]
|
||||||
|
assert set(htmlbuilder.images.keys()) == set(['subdir/img.png', 'img.png'])
|
||||||
|
assert set(htmlbuilder.images.values()) == set(['img.png', 'img1.png'])
|
||||||
|
|
||||||
|
app._warning.reset()
|
||||||
|
latexbuilder = LaTeXBuilder(app, env)
|
||||||
|
latexbuilder.post_process_images(tree)
|
||||||
|
assert "no matching candidate for image URI u'foo.*'" in app._warning.content[-1]
|
||||||
|
assert set(latexbuilder.images.keys()) == set(['subdir/img.png', 'img.png', 'img.pdf'])
|
||||||
|
assert set(latexbuilder.images.values()) == set(['img.pdf', 'img.png', 'img1.png'])
|
||||||
|
|
||||||
|
def test_second_update():
|
||||||
|
# delete, add and "edit" (change saved mtime) some files and update again
|
||||||
|
env.all_docs['contents'] = 0
|
||||||
|
root = path(app.srcdir)
|
||||||
|
(root / 'images.txt').unlink()
|
||||||
|
(root / 'new.txt').write_text('New file\n========\n')
|
||||||
|
it = env.update(app.config, app.srcdir, app.doctreedir, app)
|
||||||
|
msg = it.next()
|
||||||
|
assert '1 added, 1 changed, 1 removed' in msg
|
||||||
|
docnames = set()
|
||||||
|
for docname in it:
|
||||||
|
docnames.add(docname)
|
||||||
|
assert docnames == set(['contents', 'new'])
|
||||||
|
assert 'images' not in env.all_docs
|
||||||
|
assert 'images' not in env.found_docs
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
:license: BSD.
|
:license: BSD.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from util import *
|
from util import *
|
||||||
|
|
||||||
from docutils import frontend, utils, nodes
|
from docutils import frontend, utils, nodes
|
||||||
@@ -18,11 +20,16 @@ from sphinx import addnodes
|
|||||||
from sphinx.htmlwriter import HTMLWriter, SmartyPantsHTMLTranslator
|
from sphinx.htmlwriter import HTMLWriter, SmartyPantsHTMLTranslator
|
||||||
from sphinx.latexwriter import LaTeXWriter, LaTeXTranslator
|
from sphinx.latexwriter import LaTeXWriter, LaTeXTranslator
|
||||||
|
|
||||||
app = TestApp()
|
def setup_module():
|
||||||
optparser = frontend.OptionParser(components=(rst.Parser, HTMLWriter, LaTeXWriter))
|
global app, settings, parser
|
||||||
settings = optparser.get_default_values()
|
app = TestApp()
|
||||||
settings.env = app.builder.env
|
optparser = frontend.OptionParser(components=(rst.Parser, HTMLWriter, LaTeXWriter))
|
||||||
parser = rst.Parser()
|
settings = optparser.get_default_values()
|
||||||
|
settings.env = app.builder.env
|
||||||
|
parser = rst.Parser()
|
||||||
|
|
||||||
|
def teardown_module():
|
||||||
|
app.cleanup()
|
||||||
|
|
||||||
# since we're not resolving the markup afterwards, these nodes may remain
|
# since we're not resolving the markup afterwards, these nodes may remain
|
||||||
class ForgivingTranslator:
|
class ForgivingTranslator:
|
||||||
@@ -38,7 +45,7 @@ class ForgivingLaTeXTranslator(LaTeXTranslator, ForgivingTranslator):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def verify(rst, html_expected, latex_expected):
|
def verify_re(rst, html_expected, latex_expected):
|
||||||
document = utils.new_document('test data', settings)
|
document = utils.new_document('test data', settings)
|
||||||
parser.parse(rst, document)
|
parser.parse(rst, document)
|
||||||
for msg in document.traverse(nodes.system_message):
|
for msg in document.traverse(nodes.system_message):
|
||||||
@@ -49,14 +56,17 @@ def verify(rst, html_expected, latex_expected):
|
|||||||
html_translator = ForgivingHTMLTranslator(app.builder, document)
|
html_translator = ForgivingHTMLTranslator(app.builder, document)
|
||||||
document.walkabout(html_translator)
|
document.walkabout(html_translator)
|
||||||
html_translated = ''.join(html_translator.fragment).strip()
|
html_translated = ''.join(html_translator.fragment).strip()
|
||||||
assert html_translated == html_expected, 'from ' + rst
|
assert re.match(html_expected, html_translated), 'from' + rst
|
||||||
|
|
||||||
if latex_expected:
|
if latex_expected:
|
||||||
latex_translator = ForgivingLaTeXTranslator(document, app.builder)
|
latex_translator = ForgivingLaTeXTranslator(document, app.builder)
|
||||||
latex_translator.first_document = -1 # don't write \begin{document}
|
latex_translator.first_document = -1 # don't write \begin{document}
|
||||||
document.walkabout(latex_translator)
|
document.walkabout(latex_translator)
|
||||||
latex_translated = ''.join(latex_translator.body).strip()
|
latex_translated = ''.join(latex_translator.body).strip()
|
||||||
assert latex_translated == latex_expected, 'from ' + rst
|
assert re.match(latex_expected, latex_translated), 'from ' + rst
|
||||||
|
|
||||||
|
def verify(rst, html_expected, latex_expected):
|
||||||
|
verify_re(rst, re.escape(html_expected) + '$', re.escape(latex_expected) + '$')
|
||||||
|
|
||||||
|
|
||||||
def test_inline():
|
def test_inline():
|
||||||
@@ -78,9 +88,9 @@ def test_inline():
|
|||||||
'\\emph{a $\\rightarrow$ b}')
|
'\\emph{a $\\rightarrow$ b}')
|
||||||
|
|
||||||
# non-interpolation of dashes in option role
|
# non-interpolation of dashes in option role
|
||||||
verify(':option:`--with-option`',
|
verify_re(':option:`--with-option`',
|
||||||
'<p><em>--with-option</em></p>',
|
'<p><em( class="xref")?>--with-option</em></p>$',
|
||||||
r'\emph{\texttt{--with-option}}')
|
r'\\emph{\\texttt{--with-option}}$')
|
||||||
|
|
||||||
# verify smarty-pants quotes
|
# verify smarty-pants quotes
|
||||||
verify('"John"', '<p>“John”</p>', "``John''")
|
verify('"John"', '<p>“John”</p>', "``John''")
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ def mock_raw_input(answers, needanswer=False):
|
|||||||
|
|
||||||
def teardown_module():
|
def teardown_module():
|
||||||
qs.raw_input = __builtin__.raw_input
|
qs.raw_input = __builtin__.raw_input
|
||||||
|
qs.TERM_ENCODING = getattr(sys.stdin, 'encoding', None)
|
||||||
coloron()
|
coloron()
|
||||||
|
|
||||||
|
|
||||||
@@ -108,10 +109,10 @@ def test_quickstart_all_answers(tempdir):
|
|||||||
'Root path': tempdir,
|
'Root path': tempdir,
|
||||||
'Separate source and build': 'y',
|
'Separate source and build': 'y',
|
||||||
'Name prefix for templates': '_',
|
'Name prefix for templates': '_',
|
||||||
'Project name': 'Sphinx Test',
|
'Project name': 'STASI\xe2\x84\xa2',
|
||||||
'Author name': 'Georg Brandl',
|
'Author name': 'Wolfgang Sch\xc3\xa4uble',
|
||||||
'Project version': '0.1',
|
'Project version': '2.0',
|
||||||
'Project release': '0.1.1',
|
'Project release': '2.0.1',
|
||||||
'Source file suffix': '.txt',
|
'Source file suffix': '.txt',
|
||||||
'Name of your master document': 'contents',
|
'Name of your master document': 'contents',
|
||||||
'autodoc': 'y',
|
'autodoc': 'y',
|
||||||
@@ -119,6 +120,7 @@ def test_quickstart_all_answers(tempdir):
|
|||||||
'Create Makefile': 'no',
|
'Create Makefile': 'no',
|
||||||
}
|
}
|
||||||
qs.raw_input = mock_raw_input(answers, needanswer=True)
|
qs.raw_input = mock_raw_input(answers, needanswer=True)
|
||||||
|
qs.TERM_ENCODING = 'utf-8'
|
||||||
qs.inner_main([])
|
qs.inner_main([])
|
||||||
|
|
||||||
conffile = tempdir / 'source' / 'conf.py'
|
conffile = tempdir / 'source' / 'conf.py'
|
||||||
@@ -129,14 +131,14 @@ def test_quickstart_all_answers(tempdir):
|
|||||||
assert ns['templates_path'] == ['_templates']
|
assert ns['templates_path'] == ['_templates']
|
||||||
assert ns['source_suffix'] == '.txt'
|
assert ns['source_suffix'] == '.txt'
|
||||||
assert ns['master_doc'] == 'contents'
|
assert ns['master_doc'] == 'contents'
|
||||||
assert ns['project'] == 'Sphinx Test'
|
assert ns['project'] == u'STASI™'
|
||||||
assert ns['copyright'] == '%s, Georg Brandl' % time.strftime('%Y')
|
assert ns['copyright'] == u'%s, Wolfgang Schäuble' % time.strftime('%Y')
|
||||||
assert ns['version'] == '0.1'
|
assert ns['version'] == '2.0'
|
||||||
assert ns['release'] == '0.1.1'
|
assert ns['release'] == '2.0.1'
|
||||||
assert ns['html_static_path'] == ['_static']
|
assert ns['html_static_path'] == ['_static']
|
||||||
assert ns['latex_documents'] == [
|
assert ns['latex_documents'] == [
|
||||||
('contents', 'SphinxTest.tex', 'Sphinx Test Documentation',
|
('contents', 'STASI.tex', u'STASI™ Documentation',
|
||||||
'Georg Brandl', 'manual')]
|
u'Wolfgang Schäuble', 'manual')]
|
||||||
|
|
||||||
assert (tempdir / 'build').isdir()
|
assert (tempdir / 'build').isdir()
|
||||||
assert (tempdir / 'source' / '_static').isdir()
|
assert (tempdir / 'source' / '_static').isdir()
|
||||||
|
|||||||
@@ -8,19 +8,26 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
import StringIO
|
import StringIO
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
from sphinx import application, builder
|
from sphinx import application, builder
|
||||||
|
|
||||||
from path import path
|
from path import path
|
||||||
|
|
||||||
|
from nose import tools
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'test_root',
|
'test_root',
|
||||||
'raises', 'raises_msg',
|
'raises', 'raises_msg',
|
||||||
'ErrorOutput', 'TestApp',
|
'ListOutput', 'TestApp', 'with_testapp',
|
||||||
'path', 'with_tempdir', 'write_file',
|
'path', 'with_tempdir', 'write_file',
|
||||||
|
'sprint',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -59,15 +66,19 @@ def raises_msg(exc, msg, func, *args, **kwds):
|
|||||||
(func.__name__, _excstr(exc)))
|
(func.__name__, _excstr(exc)))
|
||||||
|
|
||||||
|
|
||||||
class ErrorOutput(object):
|
class ListOutput(object):
|
||||||
"""
|
"""
|
||||||
File-like object that raises :exc:`AssertionError` on ``write()``.
|
File-like object that collects written text in a list.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.content = []
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
del self.content[:]
|
||||||
|
|
||||||
def write(self, text):
|
def write(self, text):
|
||||||
assert False, 'tried to write %r to %s' % (text, self.name)
|
self.content.append(text)
|
||||||
|
|
||||||
|
|
||||||
class TestApp(application.Sphinx):
|
class TestApp(application.Sphinx):
|
||||||
@@ -84,20 +95,32 @@ class TestApp(application.Sphinx):
|
|||||||
|
|
||||||
if srcdir is None:
|
if srcdir is None:
|
||||||
srcdir = test_root
|
srcdir = test_root
|
||||||
|
if srcdir == '(temp)':
|
||||||
|
tempdir = path(tempfile.mkdtemp()) / 'root'
|
||||||
|
test_root.copytree(tempdir)
|
||||||
|
srcdir = tempdir
|
||||||
else:
|
else:
|
||||||
srcdir = path(srcdir)
|
srcdir = path(srcdir)
|
||||||
|
self.builddir = srcdir.joinpath('_build')
|
||||||
|
if not self.builddir.isdir():
|
||||||
|
self.builddir.makedirs()
|
||||||
|
self.made_builddir = True
|
||||||
|
else:
|
||||||
|
self.made_builddir = False
|
||||||
if confdir is None:
|
if confdir is None:
|
||||||
confdir = srcdir
|
confdir = srcdir
|
||||||
if outdir is None:
|
if outdir is None:
|
||||||
outdir = srcdir.joinpath('_build', buildername)
|
outdir = srcdir.joinpath(self.builddir, buildername)
|
||||||
|
if not outdir.isdir():
|
||||||
|
outdir.makedirs()
|
||||||
if doctreedir is None:
|
if doctreedir is None:
|
||||||
doctreedir = srcdir.joinpath(srcdir, '_build', 'doctrees')
|
doctreedir = srcdir.joinpath(srcdir, self.builddir, 'doctrees')
|
||||||
if confoverrides is None:
|
if confoverrides is None:
|
||||||
confoverrides = {}
|
confoverrides = {}
|
||||||
if status is None:
|
if status is None:
|
||||||
status = StringIO.StringIO()
|
status = StringIO.StringIO()
|
||||||
if warning is None:
|
if warning is None:
|
||||||
warning = ErrorOutput('stderr')
|
warning = ListOutput('stderr')
|
||||||
if freshenv is None:
|
if freshenv is None:
|
||||||
freshenv = True
|
freshenv = True
|
||||||
|
|
||||||
@@ -105,6 +128,30 @@ class TestApp(application.Sphinx):
|
|||||||
buildername, confoverrides, status, warning,
|
buildername, confoverrides, status, warning,
|
||||||
freshenv)
|
freshenv)
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
trees = [self.outdir, self.doctreedir]
|
||||||
|
#f self.made_builddir:
|
||||||
|
# trees.append(self.builddir)
|
||||||
|
#for tree in trees:
|
||||||
|
# shutil.rmtree(tree, True)
|
||||||
|
|
||||||
|
|
||||||
|
def with_testapp(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Make a TestApp with args and kwargs, pass it to the test and clean up
|
||||||
|
properly.
|
||||||
|
"""
|
||||||
|
def generator(func):
|
||||||
|
@wraps(func)
|
||||||
|
def deco(*args2, **kwargs2):
|
||||||
|
app = TestApp(*args, **kwargs)
|
||||||
|
try:
|
||||||
|
func(app, *args2, **kwargs2)
|
||||||
|
finally:
|
||||||
|
app.cleanup()
|
||||||
|
return deco
|
||||||
|
return generator
|
||||||
|
|
||||||
|
|
||||||
def with_tempdir(func):
|
def with_tempdir(func):
|
||||||
def new_func():
|
def new_func():
|
||||||
@@ -119,3 +166,7 @@ def write_file(name, contents):
|
|||||||
f = open(str(name), 'wb')
|
f = open(str(name), 'wb')
|
||||||
f.write(contents)
|
f.write(contents)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
def sprint(*args):
|
||||||
|
sys.stderr.write(' '.join(map(str, args)) + '\n')
|
||||||
|
|||||||
Reference in New Issue
Block a user