summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDasIch <dasdasich@gmail.com>2010-08-15 11:55:46 +0200
committerDasIch <dasdasich@gmail.com>2010-08-15 11:55:46 +0200
commit7926331c6fa1d80e08ae4d6c19bc1cfdce9e16c8 (patch)
treec31e72f4dc43e03502213c08a6d036492ea98856 /tests
parentc8f16b61cc6682fbbe47a5902b3c92e4b9336be0 (diff)
parentc0e116c026aebb10854d8e083e702f6290403116 (diff)
downloadsphinx-7926331c6fa1d80e08ae4d6c19bc1cfdce9e16c8.tar.gz
merge with lehmannro/sphinx-i18n
Diffstat (limited to 'tests')
-rw-r--r--tests/etree13/ElementTree.py14
-rw-r--r--tests/path.py1023
-rw-r--r--tests/root/conf.py2
-rw-r--r--tests/root/contents.txt1
-rw-r--r--tests/root/doctest.txt38
-rw-r--r--tests/root/literal.inc2
-rw-r--r--tests/root/markup.txt30
-rw-r--r--tests/root/objects.txt11
-rw-r--r--tests/root/versioning/added.txt20
-rw-r--r--tests/root/versioning/deleted.txt12
-rw-r--r--tests/root/versioning/deleted_end.txt11
-rw-r--r--tests/root/versioning/index.txt11
-rw-r--r--tests/root/versioning/insert.txt18
-rw-r--r--tests/root/versioning/modified.txt17
-rw-r--r--tests/root/versioning/original.txt15
-rwxr-xr-xtests/run.py16
-rw-r--r--tests/test_application.py2
-rw-r--r--tests/test_autosummary.py4
-rw-r--r--tests/test_build.py4
-rw-r--r--tests/test_build_html.py338
-rw-r--r--tests/test_build_latex.py9
-rw-r--r--tests/test_config.py17
-rw-r--r--tests/test_coverage.py2
-rw-r--r--tests/test_env.py10
-rw-r--r--tests/test_intersphinx.py84
-rw-r--r--tests/test_markup.py3
-rw-r--r--tests/test_quickstart.py31
-rw-r--r--tests/test_search.py3
-rw-r--r--tests/test_versioning.py104
-rw-r--r--tests/util.py18
30 files changed, 735 insertions, 1135 deletions
diff --git a/tests/etree13/ElementTree.py b/tests/etree13/ElementTree.py
index d3732504..f459c7f8 100644
--- a/tests/etree13/ElementTree.py
+++ b/tests/etree13/ElementTree.py
@@ -1425,12 +1425,16 @@ class XMLParser(object):
err.position = value.lineno, value.offset
raise err
- def _fixtext(self, text):
- # convert text string to ascii, if possible
- try:
- return text.encode("ascii")
- except UnicodeError:
+ if sys.version_info >= (3, 0):
+ def _fixtext(self, text):
return text
+ else:
+ def _fixtext(self, text):
+ # convert text string to ascii, if possible
+ try:
+ return text.encode("ascii")
+ except UnicodeError:
+ return text
def _fixname(self, key):
# expand qname, and convert name string to ascii, if possible
diff --git a/tests/path.py b/tests/path.py
index ceb895f5..df96bce4 100644
--- a/tests/path.py
+++ b/tests/path.py
@@ -1,953 +1,200 @@
-""" path.py - An object representing a path to a file or directory.
-
-Example:
-
-from path import path
-d = path('/home/guido/bin')
-for f in d.files('*.py'):
- f.chmod(0755)
-
-This module requires Python 2.2 or later.
-
-
-URL: http://www.jorendorff.com/articles/python/path
-Author: Jason Orendorff <jason.orendorff\x40gmail\x2ecom> (and others - see the url!)
-Date: 9 Mar 2007
+#!/usr/bin/env python
+# coding: utf-8
"""
+ path
+ ~~~~
+ :copyright: Copyright 2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+import os
+import sys
+import shutil
+from codecs import open
-# TODO
-# - Tree-walking functions don't avoid symlink loops. Matt Harrison
-# sent me a patch for this.
-# - Bug in write_text(). It doesn't support Universal newline mode.
-# - Better error message in listdir() when self isn't a
-# directory. (On Windows, the error message really sucks.)
-# - Make sure everything has a good docstring.
-# - Add methods for regex find and replace.
-# - guess_content_type() method?
-# - Perhaps support arguments to touch().
-
-from __future__ import generators
-
-import sys, warnings, os, fnmatch, glob, shutil, codecs
-
-__version__ = '2.2'
-__all__ = ['path']
-
-# Platform-specific support for path.owner
-if os.name == 'nt':
- try:
- import win32security
- except ImportError:
- win32security = None
-else:
- try:
- import pwd
- except ImportError:
- pwd = None
-
-# Pre-2.3 support. Are unicode filenames supported?
-_base = str
-_getcwd = os.getcwd
-try:
- if os.path.supports_unicode_filenames:
- _base = unicode
- _getcwd = os.getcwdu
-except AttributeError:
- pass
-
-# Pre-2.3 workaround for booleans
-try:
- True, False
-except NameError:
- True, False = 1, 0
-
-# Pre-2.3 workaround for basestring.
-try:
- basestring
-except NameError:
- basestring = (str, unicode)
-
-# Universal newline support
-_textmode = 'r'
-if hasattr(file, 'newlines'):
- _textmode = 'U'
-
-
-class TreeWalkWarning(Warning):
- pass
-
-class path(_base):
- """ Represents a filesystem path.
-
- For documentation on individual methods, consult their
- counterparts in os.path.
- """
-
- # --- Special Python methods.
- def __repr__(self):
- return 'path(%s)' % _base.__repr__(self)
+FILESYSTEMENCODING = sys.getfilesystemencoding() or sys.getdefaultencoding()
- # Adding a path and a string yields a path.
- def __add__(self, more):
- try:
- resultStr = _base.__add__(self, more)
- except TypeError: #Python bug
- resultStr = NotImplemented
- if resultStr is NotImplemented:
- return resultStr
- return self.__class__(resultStr)
-
- def __radd__(self, other):
- if isinstance(other, basestring):
- return self.__class__(other.__add__(self))
- else:
- return NotImplemented
- # The / operator joins paths.
- def __div__(self, rel):
- """ fp.__div__(rel) == fp / rel == fp.joinpath(rel)
+class path(str):
+ """
+ Represents a path which behaves like a string.
+ """
+ if sys.version_info < (3, 0):
+ def __new__(cls, s, encoding=FILESYSTEMENCODING, errors='strict'):
+ if isinstance(s, unicode):
+ s = s.encode(encoding, errors=errors)
+ return str.__new__(cls, s)
+ return str.__new__(cls, s)
- Join two path components, adding a separator character if
- needed.
+ @property
+ def parent(self):
"""
- return self.__class__(os.path.join(self, rel))
-
- # Make the / operator work even when true division is enabled.
- __truediv__ = __div__
-
- def getcwd(cls):
- """ Return the current working directory as a path object. """
- return cls(_getcwd())
- getcwd = classmethod(getcwd)
-
-
- # --- Operations on path strings.
-
- isabs = os.path.isabs
- def abspath(self): return self.__class__(os.path.abspath(self))
- def normcase(self): return self.__class__(os.path.normcase(self))
- def normpath(self): return self.__class__(os.path.normpath(self))
- def realpath(self): return self.__class__(os.path.realpath(self))
- def expanduser(self): return self.__class__(os.path.expanduser(self))
- def expandvars(self): return self.__class__(os.path.expandvars(self))
- def dirname(self): return self.__class__(os.path.dirname(self))
- basename = os.path.basename
-
- def expand(self):
- """ Clean up a filename by calling expandvars(),
- expanduser(), and normpath() on it.
-
- This is commonly everything needed to clean up a filename
- read from a configuration file, for example.
+ The name of the directory the file or directory is in.
"""
- return self.expandvars().expanduser().normpath()
-
- def _get_namebase(self):
- base, ext = os.path.splitext(self.name)
- return base
-
- def _get_ext(self):
- f, ext = os.path.splitext(_base(self))
- return ext
-
- def _get_drive(self):
- drive, r = os.path.splitdrive(self)
- return self.__class__(drive)
-
- parent = property(
- dirname, None, None,
- """ This path's parent directory, as a new path object.
-
- For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib')
- """)
-
- name = property(
- basename, None, None,
- """ The name of this file or directory without the full path.
-
- For example, path('/usr/local/lib/libpython.so').name == 'libpython.so'
- """)
+ return self.__class__(os.path.dirname(self))
- namebase = property(
- _get_namebase, None, None,
- """ The same as path.name, but with one file extension stripped off.
-
- For example, path('/home/guido/python.tar.gz').name == 'python.tar.gz',
- but path('/home/guido/python.tar.gz').namebase == 'python.tar'
- """)
-
- ext = property(
- _get_ext, None, None,
- """ The file extension, for example '.py'. """)
-
- drive = property(
- _get_drive, None, None,
- """ The drive specifier, for example 'C:'.
- This is always empty on systems that don't use drive specifiers.
- """)
-
- def splitpath(self):
- """ p.splitpath() -> Return (p.parent, p.name). """
- parent, child = os.path.split(self)
- return self.__class__(parent), child
-
- def splitdrive(self):
- """ p.splitdrive() -> Return (p.drive, <the rest of p>).
-
- Split the drive specifier from this path. If there is
- no drive specifier, p.drive is empty, so the return value
- is simply (path(''), p). This is always the case on Unix.
+ def abspath(self):
"""
- drive, rel = os.path.splitdrive(self)
- return self.__class__(drive), rel
-
- def splitext(self):
- """ p.splitext() -> Return (p.stripext(), p.ext).
-
- Split the filename extension from this path and return
- the two parts. Either part may be empty.
-
- The extension is everything from '.' to the end of the
- last path segment. This has the property that if
- (a, b) == p.splitext(), then a + b == p.
+ Returns the absolute path.
"""
- filename, ext = os.path.splitext(self)
- return self.__class__(filename), ext
-
- def stripext(self):
- """ p.stripext() -> Remove one file extension from the path.
+ return self.__class__(os.path.abspath(self))
- For example, path('/home/guido/python.tar.gz').stripext()
- returns path('/home/guido/python.tar').
+ def isabs(self):
"""
- return self.splitext()[0]
-
- if hasattr(os.path, 'splitunc'):
- def splitunc(self):
- unc, rest = os.path.splitunc(self)
- return self.__class__(unc), rest
-
- def _get_uncshare(self):
- unc, r = os.path.splitunc(self)
- return self.__class__(unc)
-
- uncshare = property(
- _get_uncshare, None, None,
- """ The UNC mount point for this path.
- This is empty for paths on local drives. """)
-
- def joinpath(self, *args):
- """ Join two or more path components, adding a separator
- character (os.sep) if needed. Returns a new path
- object.
- """
- return self.__class__(os.path.join(self, *args))
-
- def splitall(self):
- r""" Return a list of the path components in this path.
-
- The first item in the list will be a path. Its value will be
- either os.curdir, os.pardir, empty, or the root directory of
- this path (for example, '/' or 'C:\\'). The other items in
- the list will be strings.
-
- path.path.joinpath(*result) will yield the original path.
- """
- parts = []
- loc = self
- while loc != os.curdir and loc != os.pardir:
- prev = loc
- loc, child = prev.splitpath()
- if loc == prev:
- break
- parts.append(child)
- parts.append(loc)
- parts.reverse()
- return parts
-
- def relpath(self):
- """ Return this path as a relative path,
- based from the current working directory.
- """
- cwd = self.__class__(os.getcwd())
- return cwd.relpathto(self)
-
- def relpathto(self, dest):
- """ Return a relative path from self to dest.
-
- If there is no relative path from self to dest, for example if
- they reside on different drives in Windows, then this returns
- dest.abspath().
- """
- origin = self.abspath()
- dest = self.__class__(dest).abspath()
-
- orig_list = origin.normcase().splitall()
- # Don't normcase dest! We want to preserve the case.
- dest_list = dest.splitall()
-
- if orig_list[0] != os.path.normcase(dest_list[0]):
- # Can't get here from there.
- return dest
-
- # Find the location where the two paths start to differ.
- i = 0
- for start_seg, dest_seg in zip(orig_list, dest_list):
- if start_seg != os.path.normcase(dest_seg):
- break
- i += 1
-
- # Now i is the point where the two paths diverge.
- # Need a certain number of "os.pardir"s to work up
- # from the origin to the point of divergence.
- segments = [os.pardir] * (len(orig_list) - i)
- # Need to add the diverging part of dest_list.
- segments += dest_list[i:]
- if len(segments) == 0:
- # If they happen to be identical, use os.curdir.
- relpath = os.curdir
- else:
- relpath = os.path.join(*segments)
- return self.__class__(relpath)
-
- # --- Listing, searching, walking, and matching
+ Returns ``True`` if the path is absolute.
+ """
+ return os.path.isabs(self)
- def listdir(self, pattern=None):
- """ D.listdir() -> List of items in this directory.
+ def isdir(self):
+ """
+ Returns ``True`` if the path is a directory.
+ """
+ return os.path.isdir(self)
- Use D.files() or D.dirs() instead if you want a listing
- of just files or just subdirectories.
+ def isfile(self):
+ """
+ Returns ``True`` if the path is a file.
+ """
+ return os.path.isfile(self)
- The elements of the list are path objects.
+ def islink(self):
+ """
+ Returns ``True`` if the path is a symbolic link.
+ """
+ return os.path.islink(self)
- With the optional 'pattern' argument, this only lists
- items whose names match the given pattern.
+ def ismount(self):
+ """
+ Returns ``True`` if the path is a mount point.
"""
- names = os.listdir(self)
- if pattern is not None:
- names = fnmatch.filter(names, pattern)
- return [self / child for child in names]
+ return os.path.ismount(self)
- def dirs(self, pattern=None):
- """ D.dirs() -> List of this directory's subdirectories.
+ def rmtree(self, ignore_errors=False, onerror=None):
+ """
+ Removes the file or directory and any files or directories it may
+ contain.
- The elements of the list are path objects.
- This does not walk recursively into subdirectories
- (but see path.walkdirs).
+ :param ignore_errors:
+ If ``True`` errors are silently ignored, otherwise an exception
+ is raised in case an error occurs.
- With the optional 'pattern' argument, this only lists
- directories whose names match the given pattern. For
- example, d.dirs('build-*').
+ :param onerror:
+ A callback which gets called with the arguments `func`, `path` and
+ `exc_info`. `func` is one of :func:`os.listdir`, :func:`os.remove`
+ or :func:`os.rmdir`. `path` is the argument to the function which
+ caused it to fail and `exc_info` is a tuple as returned by
+ :func:`sys.exc_info`.
"""
- return [p for p in self.listdir(pattern) if p.isdir()]
+ shutil.rmtree(self, ignore_errors=ignore_errors, onerror=onerror)
- def files(self, pattern=None):
- """ D.files() -> List of the files in this directory.
+ def copytree(self, destination, symlinks=False, ignore=None):
+ """
+ Recursively copy a directory to the given `destination`. If the given
+ `destination` does not exist it will be created.
- The elements of the list are path objects.
- This does not walk into subdirectories (see path.walkfiles).
+ :param symlinks:
+ If ``True`` symbolic links in the source tree result in symbolic
+ links in the destination tree otherwise the contents of the files
+ pointed to by the symbolic links are copied.
- With the optional 'pattern' argument, this only lists files
- whose names match the given pattern. For example,
- d.files('*.pyc').
+ :param ignore:
+ A callback which gets called with the path of the directory being
+ copied and a list of paths as returned by :func:`os.listdir`.
"""
+ shutil.copytree(self, destination, symlinks=symlinks, ignore=ignore)
- return [p for p in self.listdir(pattern) if p.isfile()]
-
- def walk(self, pattern=None, errors='strict'):
- """ D.walk() -> iterator over files and subdirs, recursively.
+ def movetree(self, destination):
+ """
+ Recursively move the file or directory to the given `destination`
+ similar to the Unix "mv" command.
- The iterator yields path objects naming each child item of
- this directory and its descendants. This requires that
- D.isdir().
+ If the `destination` is a file it may be overwritten depending on the
+ :func:`os.rename` semantics.
+ """
+ shutil.move(self, destination)
- This performs a depth-first traversal of the directory tree.
- Each directory is returned just before all its children.
+ move = movetree
- The errors= keyword argument controls behavior when an
- error occurs. The default is 'strict', which causes an
- exception. The other allowed values are 'warn', which
- reports the error via warnings.warn(), and 'ignore'.
+ def unlink(self):
"""
- if errors not in ('strict', 'warn', 'ignore'):
- raise ValueError("invalid errors parameter")
-
- try:
- childList = self.listdir()
- except Exception:
- if errors == 'ignore':
- return
- elif errors == 'warn':
- warnings.warn(
- "Unable to list directory '%s': %s"
- % (self, sys.exc_info()[1]),
- TreeWalkWarning)
- return
- else:
- raise
-
- for child in childList:
- if pattern is None or child.fnmatch(pattern):
- yield child
- try:
- isdir = child.isdir()
- except Exception:
- if errors == 'ignore':
- isdir = False
- elif errors == 'warn':
- warnings.warn(
- "Unable to access '%s': %s"
- % (child, sys.exc_info()[1]),
- TreeWalkWarning)
- isdir = False
- else:
- raise
-
- if isdir:
- for item in child.walk(pattern, errors):
- yield item
-
- def walkdirs(self, pattern=None, errors='strict'):
- """ D.walkdirs() -> iterator over subdirs, recursively.
-
- With the optional 'pattern' argument, this yields only
- directories whose names match the given pattern. For
- example, mydir.walkdirs('*test') yields only directories
- with names ending in 'test'.
-
- The errors= keyword argument controls behavior when an
- error occurs. The default is 'strict', which causes an
- exception. The other allowed values are 'warn', which
- reports the error via warnings.warn(), and 'ignore'.
- """
- if errors not in ('strict', 'warn', 'ignore'):
- raise ValueError("invalid errors parameter")
+ Removes a file.
+ """
+ os.unlink(self)
+ def write_text(self, text, **kwargs):
+ """
+ Writes the given `text` to the file.
+ """
+ f = open(self, 'w', **kwargs)
try:
- dirs = self.dirs()
- except Exception:
- if errors == 'ignore':
- return
- elif errors == 'warn':
- warnings.warn(
- "Unable to list directory '%s': %s"
- % (self, sys.exc_info()[1]),
- TreeWalkWarning)
- return
- else:
- raise
-
- for child in dirs:
- if pattern is None or child.fnmatch(pattern):
- yield child
- for subsubdir in child.walkdirs(pattern, errors):
- yield subsubdir
-
- def walkfiles(self, pattern=None, errors='strict'):
- """ D.walkfiles() -> iterator over files in D, recursively.
-
- The optional argument, pattern, limits the results to files
- with names that match the pattern. For example,
- mydir.walkfiles('*.tmp') yields only files with the .tmp
- extension.
- """
- if errors not in ('strict', 'warn', 'ignore'):
- raise ValueError("invalid errors parameter")
+ f.write(text)
+ finally:
+ f.close()
+ def text(self, **kwargs):
+ """
+ Returns the text in the file.
+ """
+ f = open(self, mode='U', **kwargs)
try:
- childList = self.listdir()
- except Exception:
- if errors == 'ignore':
- return
- elif errors == 'warn':
- warnings.warn(
- "Unable to list directory '%s': %s"
- % (self, sys.exc_info()[1]),
- TreeWalkWarning)
- return
- else:
- raise
-
- for child in childList:
- try:
- isfile = child.isfile()
- isdir = not isfile and child.isdir()
- except:
- if errors == 'ignore':
- continue
- elif errors == 'warn':
- warnings.warn(
- "Unable to access '%s': %s"
- % (self, sys.exc_info()[1]),
- TreeWalkWarning)
- continue
- else:
- raise
-
- if isfile:
- if pattern is None or child.fnmatch(pattern):
- yield child
- elif isdir:
- for f in child.walkfiles(pattern, errors):
- yield f
-
- def fnmatch(self, pattern):
- """ Return True if self.name matches the given pattern.
-
- pattern - A filename pattern with wildcards,
- for example '*.py'.
- """
- return fnmatch.fnmatch(self.name, pattern)
-
- def glob(self, pattern):
- """ Return a list of path objects that match the pattern.
-
- pattern - a path relative to this directory, with wildcards.
-
- For example, path('/users').glob('*/bin/*') returns a list
- of all the files users have in their bin directories.
- """
- cls = self.__class__
- return [cls(s) for s in glob.glob(_base(self / pattern))]
-
-
- # --- Reading or writing an entire file at once.
-
- def open(self, mode='r'):
- """ Open this file. Return a file object. """
- return file(self, mode)
+ return f.read()
+ finally:
+ f.close()
def bytes(self):
- """ Open this file, read all bytes, return them as a string. """
- f = self.open('rb')
+ """
+ Returns the bytes in the file.
+ """
+ f = open(self, mode='rb')
try:
return f.read()
finally:
f.close()
def write_bytes(self, bytes, append=False):
- """ Open this file and write the given bytes to it.
+ """
+ Writes the given `bytes` to the file.
- Default behavior is to overwrite any existing file.
- Call p.write_bytes(bytes, append=True) to append instead.
+ :param append:
+ If ``True`` given `bytes` are added at the end of the file.
"""
if append:
mode = 'ab'
else:
mode = 'wb'
- f = self.open(mode)
+ f = open(self, mode=mode)
try:
f.write(bytes)
finally:
f.close()
- def text(self, encoding=None, errors='strict'):
- r""" Open this file, read it in, return the content as a string.
-
- This uses 'U' mode in Python 2.3 and later, so '\r\n' and '\r'
- are automatically translated to '\n'.
-
- Optional arguments:
-
- encoding - The Unicode encoding (or character set) of
- the file. If present, the content of the file is
- decoded and returned as a unicode object; otherwise
- it is returned as an 8-bit str.
- errors - How to handle Unicode errors; see help(str.decode)
- for the options. Default is 'strict'.
+ def exists(self):
"""
- if encoding is None:
- # 8-bit
- f = self.open(_textmode)
- try:
- return f.read()
- finally:
- f.close()
- else:
- # Unicode
- f = codecs.open(self, 'r', encoding, errors)
- # (Note - Can't use 'U' mode here, since codecs.open
- # doesn't support 'U' mode, even in Python 2.3.)
- try:
- t = f.read()
- finally:
- f.close()
- return (t.replace(u'\r\n', u'\n')
- .replace(u'\r\x85', u'\n')
- .replace(u'\r', u'\n')
- .replace(u'\x85', u'\n')
- .replace(u'\u2028', u'\n'))
-
- def write_text(self, text, encoding=None, errors='strict', linesep=os.linesep, append=False):
- r""" Write the given text to this file.
-
- The default behavior is to overwrite any existing file;
- to append instead, use the 'append=True' keyword argument.
-
- There are two differences between path.write_text() and
- path.write_bytes(): newline handling and Unicode handling.
- See below.
-
- Parameters:
-
- - text - str/unicode - The text to be written.
-
- - encoding - str - The Unicode encoding that will be used.
- This is ignored if 'text' isn't a Unicode string.
-
- - errors - str - How to handle Unicode encoding errors.
- Default is 'strict'. See help(unicode.encode) for the
- options. This is ignored if 'text' isn't a Unicode
- string.
-
- - linesep - keyword argument - str/unicode - The sequence of
- characters to be used to mark end-of-line. The default is
- os.linesep. You can also specify None; this means to
- leave all newlines as they are in 'text'.
-
- - append - keyword argument - bool - Specifies what to do if
- the file already exists (True: append to the end of it;
- False: overwrite it.) The default is False.
-
-
- --- Newline handling.
-
- write_text() converts all standard end-of-line sequences
- ('\n', '\r', and '\r\n') to your platform's default end-of-line
- sequence (see os.linesep; on Windows, for example, the
- end-of-line marker is '\r\n').
-
- If you don't like your platform's default, you can override it
- using the 'linesep=' keyword argument. If you specifically want
- write_text() to preserve the newlines as-is, use 'linesep=None'.
-
- This applies to Unicode text the same as to 8-bit text, except
- there are three additional standard Unicode end-of-line sequences:
- u'\x85', u'\r\x85', and u'\u2028'.
-
- (This is slightly different from when you open a file for
- writing with fopen(filename, "w") in C or file(filename, 'w')
- in Python.)
-
-
- --- Unicode
-
- If 'text' isn't Unicode, then apart from newline handling, the
- bytes are written verbatim to the file. The 'encoding' and
- 'errors' arguments are not used and must be omitted.
-
- If 'text' is Unicode, it is first converted to bytes using the
- specified 'encoding' (or the default encoding if 'encoding'
- isn't specified). The 'errors' argument applies only to this
- conversion.
-
- """
- if isinstance(text, unicode):
- if linesep is not None:
- # Convert all standard end-of-line sequences to
- # ordinary newline characters.
- text = (text.replace(u'\r\n', u'\n')
- .replace(u'\r\x85', u'\n')
- .replace(u'\r', u'\n')
- .replace(u'\x85', u'\n')
- .replace(u'\u2028', u'\n'))
- text = text.replace(u'\n', linesep)
- if encoding is None:
- encoding = sys.getdefaultencoding()
- bytes = text.encode(encoding, errors)
- else:
- # It is an error to specify an encoding if 'text' is
- # an 8-bit string.
- assert encoding is None
-
- if linesep is not None:
- text = (text.replace('\r\n', '\n')
- .replace('\r', '\n'))
- bytes = text.replace('\n', linesep)
-
- self.write_bytes(bytes, append)
-
- def lines(self, encoding=None, errors='strict', retain=True):
- r""" Open this file, read all lines, return them in a list.
-
- Optional arguments:
- encoding - The Unicode encoding (or character set) of
- the file. The default is None, meaning the content
- of the file is read as 8-bit characters and returned
- as a list of (non-Unicode) str objects.
- errors - How to handle Unicode errors; see help(str.decode)
- for the options. Default is 'strict'
- retain - If true, retain newline characters; but all newline
- character combinations ('\r', '\n', '\r\n') are
- translated to '\n'. If false, newline characters are
- stripped off. Default is True.
-
- This uses 'U' mode in Python 2.3 and later.
- """
- if encoding is None and retain:
- f = self.open(_textmode)
- try:
- return f.readlines()
- finally:
- f.close()
- else:
- return self.text(encoding, errors).splitlines(retain)
-
- def write_lines(self, lines, encoding=None, errors='strict',
- linesep=os.linesep, append=False):
- r""" Write the given lines of text to this file.
-
- By default this overwrites any existing file at this path.
-
- This puts a platform-specific newline sequence on every line.
- See 'linesep' below.
-
- lines - A list of strings.
-
- encoding - A Unicode encoding to use. This applies only if
- 'lines' contains any Unicode strings.
-
- errors - How to handle errors in Unicode encoding. This
- also applies only to Unicode strings.
-
- linesep - The desired line-ending. This line-ending is
- applied to every line. If a line already has any
- standard line ending ('\r', '\n', '\r\n', u'\x85',
- u'\r\x85', u'\u2028'), that will be stripped off and
- this will be used instead. The default is os.linesep,
- which is platform-dependent ('\r\n' on Windows, '\n' on
- Unix, etc.) Specify None to write the lines as-is,
- like file.writelines().
-
- Use the keyword argument append=True to append lines to the
- file. The default is to overwrite the file. Warning:
- When you use this with Unicode data, if the encoding of the
- existing data in the file is different from the encoding
- you specify with the encoding= parameter, the result is
- mixed-encoding data, which can really confuse someone trying
- to read the file later.
+ Returns ``True`` if the path exist.
"""
- if append:
- mode = 'ab'
- else:
- mode = 'wb'
- f = self.open(mode)
- try:
- for line in lines:
- isUnicode = isinstance(line, unicode)
- if linesep is not None:
- # Strip off any existing line-end and add the
- # specified linesep string.
- if isUnicode:
- if line[-2:] in (u'\r\n', u'\x0d\x85'):
- line = line[:-2]
- elif line[-1:] in (u'\r', u'\n',
- u'\x85', u'\u2028'):
- line = line[:-1]
- else:
- if line[-2:] == '\r\n':
- line = line[:-2]
- elif line[-1:] in ('\r', '\n'):
- line = line[:-1]
- line += linesep
- if isUnicode:
- if encoding is None:
- encoding = sys.getdefaultencoding()
- line = line.encode(encoding, errors)
- f.write(line)
- finally:
- f.close()
-
- # --- Methods for querying the filesystem.
-
- exists = os.path.exists
- isdir = os.path.isdir
- isfile = os.path.isfile
- islink = os.path.islink
- ismount = os.path.ismount
-
- if hasattr(os.path, 'samefile'):
- samefile = os.path.samefile
-
- getatime = os.path.getatime
- atime = property(
- getatime, None, None,
- """ Last access time of the file. """)
-
- getmtime = os.path.getmtime
- mtime = property(
- getmtime, None, None,
- """ Last-modified time of the file. """)
-
- if hasattr(os.path, 'getctime'):
- getctime = os.path.getctime
- ctime = property(
- getctime, None, None,
- """ Creation time of the file. """)
-
- getsize = os.path.getsize
- size = property(
- getsize, None, None,
- """ Size of the file, in bytes. """)
-
- if hasattr(os, 'access'):
- def access(self, mode):
- """ Return true if current user has access to this path.
-
- mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
- """
- return os.access(self, mode)
-
- def stat(self):
- """ Perform a stat() system call on this path. """
- return os.stat(self)
-
- def lstat(self):
- """ Like path.stat(), but do not follow symbolic links. """
- return os.lstat(self)
-
- def get_owner(self):
- r""" Return the name of the owner of this file or directory.
-
- This follows symbolic links.
-
- On Windows, this returns a name of the form ur'DOMAIN\User Name'.
- On Windows, a group can own a file or directory.
- """
- if os.name == 'nt':
- if win32security is None:
- raise Exception("path.owner requires win32all to be installed")
- desc = win32security.GetFileSecurity(
- self, win32security.OWNER_SECURITY_INFORMATION)
- sid = desc.GetSecurityDescriptorOwner()
- account, domain, typecode = win32security.LookupAccountSid(None, sid)
- return domain + u'\\' + account
- else:
- if pwd is None:
- raise NotImplementedError("path.owner is not implemented on this platform.")
- st = self.stat()
- return pwd.getpwuid(st.st_uid).pw_name
-
- owner = property(
- get_owner, None, None,
- """ Name of the owner of this file or directory. """)
-
- if hasattr(os, 'statvfs'):
- def statvfs(self):
- """ Perform a statvfs() system call on this path. """
- return os.statvfs(self)
-
- if hasattr(os, 'pathconf'):
- def pathconf(self, name):
- return os.pathconf(self, name)
-
-
- # --- Modifying operations on files and directories
-
- def utime(self, times):
- """ Set the access and modified times of this file. """
- os.utime(self, times)
-
- def chmod(self, mode):
- os.chmod(self, mode)
+ return os.path.exists(self)
- if hasattr(os, 'chown'):
- def chown(self, uid, gid):
- os.chown(self, uid, gid)
-
- def rename(self, new):
- os.rename(self, new)
-
- def renames(self, new):
- os.renames(self, new)
-
-
- # --- Create/delete operations on directories
-
- def mkdir(self, mode=0777):
- os.mkdir(self, mode)
+ def lexists(self):
+ """
+ Returns ``True`` if the path exists unless it is a broken symbolic
+ link.
+ """
+ return os.path.lexists(self)
def makedirs(self, mode=0777):
+ """
+ Recursively create directories.
+ """
os.makedirs(self, mode)
- def rmdir(self):
- os.rmdir(self)
-
- def removedirs(self):
- os.removedirs(self)
-
-
- # --- Modifying operations on files
-
- def touch(self):
- """ Set the access/modified times of this file to the current time.
- Create the file if it does not exist.
+ def joinpath(self, *args):
"""
- fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666)
- os.close(fd)
- os.utime(self, None)
-
- def remove(self):
- os.remove(self)
-
- def unlink(self):
- os.unlink(self)
-
-
- # --- Links
-
- if hasattr(os, 'link'):
- def link(self, newpath):
- """ Create a hard link at 'newpath', pointing to this file. """
- os.link(self, newpath)
-
- if hasattr(os, 'symlink'):
- def symlink(self, newlink):
- """ Create a symbolic link at 'newlink', pointing here. """
- os.symlink(self, newlink)
-
- if hasattr(os, 'readlink'):
- def readlink(self):
- """ Return the path to which this symbolic link points.
-
- The result may be an absolute or a relative path.
- """
- return self.__class__(os.readlink(self))
-
- def readlinkabs(self):
- """ Return the path to which this symbolic link points.
-
- The result is always an absolute path.
- """
- p = self.readlink()
- if p.isabs():
- return p
- else:
- return (self.parent / p).abspath()
-
-
- # --- High-level functions from shutil
-
- copyfile = shutil.copyfile
- copymode = shutil.copymode
- copystat = shutil.copystat
- copy = shutil.copy
- copy2 = shutil.copy2
- copytree = shutil.copytree
- if hasattr(shutil, 'move'):
- move = shutil.move
- rmtree = shutil.rmtree
-
-
- # --- Special stuff from os
-
- if hasattr(os, 'chroot'):
- def chroot(self):
- os.chroot(self)
+ Joins the path with the argument given and returns the result.
+ """
+ return self.__class__(os.path.join(self, *map(self.__class__, args)))
- if hasattr(os, 'startfile'):
- def startfile(self):
- os.startfile(self)
+ __div__ = __truediv__ = joinpath
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, str.__repr__(self))
diff --git a/tests/root/conf.py b/tests/root/conf.py
index 2b6d6a9a..b4734189 100644
--- a/tests/root/conf.py
+++ b/tests/root/conf.py
@@ -22,7 +22,7 @@ copyright = '2010, Georg Brandl & Team'
version = '0.6'
release = '0.6alpha1'
today_fmt = '%B %d, %Y'
-#unused_docs = []
+# unused_docs = []
exclude_patterns = ['_build', '**/excluded.*']
keep_warnings = True
pygments_style = 'sphinx'
diff --git a/tests/root/contents.txt b/tests/root/contents.txt
index e052e04b..280953b4 100644
--- a/tests/root/contents.txt
+++ b/tests/root/contents.txt
@@ -26,6 +26,7 @@ Contents:
extensions
doctest
extensions
+ versioning/index
Python <http://python.org/>
diff --git a/tests/root/doctest.txt b/tests/root/doctest.txt
index 35cdd589..6ac0b286 100644
--- a/tests/root/doctest.txt
+++ b/tests/root/doctest.txt
@@ -30,7 +30,7 @@ Special directives
.. testcode::
- print 1+1
+ print(1+1)
.. testoutput::
@@ -50,30 +50,30 @@ Special directives
.. testsetup:: *
- from math import floor
+ from math import factorial
.. doctest::
- >>> floor(1.2)
- 1.0
+ >>> factorial(1)
+ 1
.. testcode::
- print floor(1.2)
+ print(factorial(1))
.. testoutput::
- 1.0
+ 1
- >>> floor(1.2)
- 1.0
+ >>> factorial(1)
+ 1
* options for testcode/testoutput blocks
.. testcode::
:hide:
- print 'Output text.'
+ print('Output text.')
.. testoutput::
:hide:
@@ -85,36 +85,36 @@ Special directives
.. testsetup:: group1
- from math import ceil
+ from math import trunc
- ``ceil`` is now known in "group1", but not in others.
+ ``trunc`` is now known in "group1", but not in others.
.. doctest:: group1
- >>> ceil(0.8)
- 1.0
+ >>> trunc(1.1)
+ 1
.. doctest:: group2
- >>> ceil(0.8)
+ >>> trunc(1.1)
Traceback (most recent call last):
...
- NameError: name 'ceil' is not defined
+ NameError: name 'trunc' is not defined
Interleaving testcode/testoutput:
.. testcode:: group1
- print ceil(0.8)
+ print(factorial(3))
.. testcode:: group2
- print floor(0.8)
+ print(factorial(4))
.. testoutput:: group1
- 1.0
+ 6
.. testoutput:: group2
- 0.0
+ 24
diff --git a/tests/root/literal.inc b/tests/root/literal.inc
index d5b9890c..694f15ed 100644
--- a/tests/root/literal.inc
+++ b/tests/root/literal.inc
@@ -1,7 +1,7 @@
# Literally included file using Python highlighting
# -*- coding: utf-8 -*-
-foo = u"Including Unicode characters: üöä"
+foo = "Including Unicode characters: üöä"
class Foo:
pass
diff --git a/tests/root/markup.txt b/tests/root/markup.txt
index e286d26c..a72285ed 100644
--- a/tests/root/markup.txt
+++ b/tests/root/markup.txt
@@ -97,21 +97,23 @@ Inline markup
*Generic inline markup*
-* :command:`command`
-* :dfn:`dfn`
-* :guilabel:`guilabel with &accelerator`
-* :kbd:`kbd`
-* :mailheader:`mailheader`
-* :makevar:`makevar`
-* :manpage:`manpage`
-* :mimetype:`mimetype`
-* :newsgroup:`newsgroup`
-* :program:`program`
-* :regexp:`regexp`
-* :menuselection:`File --> Close`
+Adding \n to test unescaping.
+
+* :command:`command\\n`
+* :dfn:`dfn\\n`
+* :guilabel:`guilabel with &accelerator and \\n`
+* :kbd:`kbd\\n`
+* :mailheader:`mailheader\\n`
+* :makevar:`makevar\\n`
+* :manpage:`manpage\\n`
+* :mimetype:`mimetype\\n`
+* :newsgroup:`newsgroup\\n`
+* :program:`program\\n`
+* :regexp:`regexp\\n`
+* :menuselection:`File --> Close\\n`
* :menuselection:`&File --> &Print`
-* :file:`a/{varpart}/b`
-* :samp:`print {i}`
+* :file:`a/{varpart}/b\\n`
+* :samp:`print {i}\\n`
*Linking inline markup*
diff --git a/tests/root/objects.txt b/tests/root/objects.txt
index ca3d0eb7..e62f6d96 100644
--- a/tests/root/objects.txt
+++ b/tests/root/objects.txt
@@ -41,8 +41,17 @@ Testing object descriptions
.. function:: func_without_module2() -> annotation
+.. object:: long(parameter, \
+ list)
+ another one
+
.. class:: TimeInt
+ :param moo: |test|
+ :type moo: |test|
+
+.. |test| replace:: Moo
+
.. class:: Time(hour, minute, isdst)
:param hour: The year.
@@ -57,6 +66,8 @@ Testing object descriptions
:ivar int hour: like *hour*
:ivar minute: like *minute*
:vartype minute: int
+ :param hour: Duplicate param. Should not lead to crashes.
+ :type hour: Duplicate type.
C items
diff --git a/tests/root/versioning/added.txt b/tests/root/versioning/added.txt
new file mode 100644
index 00000000..22a70739
--- /dev/null
+++ b/tests/root/versioning/added.txt
@@ -0,0 +1,20 @@
+Versioning test text
+====================
+
+So the thing is I need some kind of text - not the lorem ipsum stuff, that
+doesn't work out that well - to test :mod:`sphinx.versioning`. I couldn't find
+a good text for that under public domain so I thought the easiest solution is
+to write one by myself. It's not really interesting, in fact it is *really*
+boring.
+
+Anyway I need more than one paragraph, at least three for the original
+document, I think, and another one for two different ones.
+
+So the previous paragraph was a bit short because I don't want to test this
+only on long paragraphs, I hope it was short enough to cover most stuff.
+Anyway I see this lacks ``some markup`` so I have to add a **little** bit.
+
+Woho another paragraph, if this test fails we really have a problem because
+this means the algorithm itself fails and not the diffing algorithm which is
+pretty much doomed anyway as it probably fails for some kind of language
+respecting certain nodes anyway but we can't work around that anyway.
diff --git a/tests/root/versioning/deleted.txt b/tests/root/versioning/deleted.txt
new file mode 100644
index 00000000..a1a9c4c9
--- /dev/null
+++ b/tests/root/versioning/deleted.txt
@@ -0,0 +1,12 @@
+Versioning test text
+====================
+
+So the thing is I need some kind of text - not the lorem ipsum stuff, that
+doesn't work out that well - to test :mod:`sphinx.versioning`. I couldn't find
+a good text for that under public domain so I thought the easiest solution is
+to write one by myself. It's not really interesting, in fact it is *really*
+boring.
+
+So the previous paragraph was a bit short because I don't want to test this
+only on long paragraphs, I hope it was short enough to cover most stuff.
+Anyway I see this lacks ``some markup`` so I have to add a **little** bit.
diff --git a/tests/root/versioning/deleted_end.txt b/tests/root/versioning/deleted_end.txt
new file mode 100644
index 00000000..f30e6300
--- /dev/null
+++ b/tests/root/versioning/deleted_end.txt
@@ -0,0 +1,11 @@
+Versioning test text
+====================
+
+So the thing is I need some kind of text - not the lorem ipsum stuff, that
+doesn't work out that well - to test :mod:`sphinx.versioning`. I couldn't find
+a good text for that under public domain so I thought the easiest solution is
+to write one by myself. It's not really interesting, in fact it is *really*
+boring.
+
+Anyway I need more than one paragraph, at least three for the original
+document, I think, and another one for two different ones.
diff --git a/tests/root/versioning/index.txt b/tests/root/versioning/index.txt
new file mode 100644
index 00000000..234e223f
--- /dev/null
+++ b/tests/root/versioning/index.txt
@@ -0,0 +1,11 @@
+Versioning Stuff
+================
+
+.. toctree::
+
+ original
+ added
+ insert
+ deleted
+ deleted_end
+ modified
diff --git a/tests/root/versioning/insert.txt b/tests/root/versioning/insert.txt
new file mode 100644
index 00000000..1c157cc9
--- /dev/null
+++ b/tests/root/versioning/insert.txt
@@ -0,0 +1,18 @@
+Versioning test text
+====================
+
+So the thing is I need some kind of text - not the lorem ipsum stuff, that
+doesn't work out that well - to test :mod:`sphinx.versioning`. I couldn't find
+a good text for that under public domain so I thought the easiest solution is
+to write one by myself. It's not really interesting, in fact it is *really*
+boring.
+
+So this paragraph is just something I inserted in this document to test if our
+algorithm notices that this paragraph is not just a changed version.
+
+Anyway I need more than one paragraph, at least three for the original
+document, I think, and another one for two different ones.
+
+So the previous paragraph was a bit short because I don't want to test this
+only on long paragraphs, I hope it was short enough to cover most stuff.
+Anyway I see this lacks ``some markup`` so I have to add a **little** bit.
diff --git a/tests/root/versioning/modified.txt b/tests/root/versioning/modified.txt
new file mode 100644
index 00000000..49cdad93
--- /dev/null
+++ b/tests/root/versioning/modified.txt
@@ -0,0 +1,17 @@
+Versioning test text
+====================
+
+So the thing is I need some kind of text - not the lorem ipsum stuff, that
+doesn't work out that well - to test :mod:`sphinx.versioning`. I couldn't find
+a good text for that under public domain so I thought the easiest solution is
+to write one by myself. Inserting something silly as a modification, btw. have
+you seen the typo below?. It's not really interesting, in fact it is *really*
+boring.
+
+Anyway I need more than one paragraph, at least three for the original
+document, I think, and another one for two different ones. So this is a small
+modification by adding something to this paragraph.
+
+So the previous paragraph was a bit short because I don't want to test this
+only on long paragraphs, I hoep it was short enough to cover most stuff.
+Anyway I see this lacks ``some markup`` so I have to add a **little** bit.
diff --git a/tests/root/versioning/original.txt b/tests/root/versioning/original.txt
new file mode 100644
index 00000000..b3fe0609
--- /dev/null
+++ b/tests/root/versioning/original.txt
@@ -0,0 +1,15 @@
+Versioning test text
+====================
+
+So the thing is I need some kind of text - not the lorem ipsum stuff, that
+doesn't work out that well - to test :mod:`sphinx.versioning`. I couldn't find
+a good text for that under public domain so I thought the easiest solution is
+to write one by myself. It's not really interesting, in fact it is *really*
+boring.
+
+Anyway I need more than one paragraph, at least three for the original
+document, I think, and another one for two different ones.
+
+So the previous paragraph was a bit short because I don't want to test this
+only on long paragraphs, I hope it was short enough to cover most stuff.
+Anyway I see this lacks ``some markup`` so I have to add a **little** bit.
diff --git a/tests/run.py b/tests/run.py
index 0cb41442..50567fbc 100755
--- a/tests/run.py
+++ b/tests/run.py
@@ -11,7 +11,17 @@
"""
import sys
-from os import path
+from os import path, chdir, listdir
+
+if sys.version_info >= (3, 0):
+ print('Copying and converting sources to build/lib/tests...')
+ from distutils.util import copydir_run_2to3
+ testroot = path.dirname(__file__) or '.'
+ newroot = path.join(testroot, path.pardir, 'build')
+ newroot = path.join(newroot, listdir(newroot)[0], 'tests')
+ copydir_run_2to3(testroot, newroot)
+ # switch to the converted dir so nose tests the right tests
+ chdir(newroot)
# always test the sphinx package from this directory
sys.path.insert(0, path.join(path.dirname(__file__), path.pardir))
@@ -19,8 +29,8 @@ sys.path.insert(0, path.join(path.dirname(__file__), path.pardir))
try:
import nose
except ImportError:
- print "The nose package is needed to run the Sphinx test suite."
+ print("The nose package is needed to run the Sphinx test suite.")
sys.exit(1)
-print "Running Sphinx test suite..."
+print("Running Sphinx test suite...")
nose.main()
diff --git a/tests/test_application.py b/tests/test_application.py
index 3d287a57..d1154863 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -45,9 +45,11 @@ def test_output():
app = TestApp(status=status, warning=warnings)
try:
status.truncate(0) # __init__ writes to status
+ status.seek(0)
app.info("Nothing here...")
assert status.getvalue() == "Nothing here...\n"
status.truncate(0)
+ status.seek(0)
app.info("Nothing here...", True)
assert status.getvalue() == "Nothing here..."
diff --git a/tests/test_autosummary.py b/tests/test_autosummary.py
index 7e309367..20fb06e0 100644
--- a/tests/test_autosummary.py
+++ b/tests/test_autosummary.py
@@ -9,8 +9,6 @@
:license: BSD, see LICENSE for details.
"""
-import string
-
from util import *
from sphinx.ext.autosummary import mangle_signature
@@ -27,7 +25,7 @@ def test_mangle_signature():
(a, b, c='foobar()', d=123) :: (a, b[, c, d])
"""
- TEST = [map(string.strip, x.split("::")) for x in TEST.split("\n")
+ TEST = [map(lambda x: x.strip(), x.split("::")) for x in TEST.split("\n")
if '::' in x]
for inp, outp in TEST:
res = mangle_signature(inp).strip().replace(u"\u00a0", " ")
diff --git a/tests/test_build.py b/tests/test_build.py
index f18ff175..d571febd 100644
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -21,6 +21,10 @@ def teardown_module():
def test_pickle(app):
app.builder.build_all()
+@with_app(buildername='json')
+def test_json(app):
+ app.builder.build_all()
+
@with_app(buildername='linkcheck')
def test_linkcheck(app):
app.builder.build_all()
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index fe249f44..a685fcb6 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -11,8 +11,8 @@
import os
import re
-import difflib
import htmlentitydefs
+import sys
from StringIO import StringIO
try:
@@ -37,8 +37,11 @@ ENV_WARNINGS = """\
http://www.python.org/logo.png
%(root)s/includes.txt:\\d*: \\(WARNING/2\\) Encoding 'utf-8-sig' used for \
reading included file u'wrongenc.inc' seems to be wrong, try giving an \
-:encoding: option
+:encoding: option\\n?
%(root)s/includes.txt:4: WARNING: download file not readable: nonexisting.png
+%(root)s/objects.txt:\\d*: WARNING: using old C markup; please migrate to \
+new-style markup \(e.g. c:function instead of cfunction\), see \
+http://sphinx.pocoo.org/domains.html
"""
HTML_WARNINGS = ENV_WARNINGS + """\
@@ -48,183 +51,204 @@ HTML_WARNINGS = ENV_WARNINGS + """\
%(root)s/markup.txt:: WARNING: invalid pair index entry u'keyword; '
"""
+if sys.version_info >= (3, 0):
+ ENV_WARNINGS = remove_unicode_literals(ENV_WARNINGS)
+ HTML_WARNINGS = remove_unicode_literals(HTML_WARNINGS)
+
+
+def tail_check(check):
+ rex = re.compile(check)
+ def checker(nodes):
+ for node in nodes:
+ if node.tail and rex.search(node.tail):
+ return True
+ assert False, '%r not found in tail of any nodes %s' % (check, nodes)
+ return checker
+
+
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']": '',
- ".//img[@src='../_images/img.png']": '',
- ".//p": 'This is an include file.',
- },
- '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/p": 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',
+ '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']", ''),
+ (".//img[@src='../_images/img.png']", ''),
+ (".//p", 'This is an include file.'),
+ ],
+ '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/p", 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']": '',
+ (".//meta[@name='author'][@content='Me']", ''),
+ (".//meta[@name='keywords'][@content='docs, sphinx']", ''),
# a label created by ``.. _label:``
- ".//div[@id='label']": '',
+ (".//div[@id='label']", ''),
# code with standard code blocks
- ".//pre": '^some code$',
+ (".//pre", '^some code$'),
# an option list
- ".//span[@class='option']": '--help',
+ (".//span[@class='option']", '--help'),
# admonitions
- ".//p[@class='first admonition-title']": 'My Admonition',
- ".//p[@class='last']": 'Note text.',
- ".//p[@class='last']": 'Warning text.',
+ (".//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']"
- "[@class='pep reference external']/strong": 'PEP 8',
- ".//a[@href='http://tools.ietf.org/html/rfc1.html']"
- "[@class='rfc reference external']/strong": 'RFC 1',
- ".//a[@href='objects.html#envvar-HOME']"
- "[@class='reference internal']/tt/span[@class='pre']": 'HOME',
- ".//a[@href='#with']"
- "[@class='reference internal']/tt/span[@class='pre']": '^with$',
- ".//a[@href='#grammar-token-try_stmt']"
- "[@class='reference internal']/tt/span": '^statement$',
- ".//a[@href='subdir/includes.html']"
- "[@class='reference internal']/em": 'Including in subdir',
- ".//a[@href='objects.html#cmdoption-python-c']"
- "[@class='reference internal']/em": 'Python -c option',
+ (".//li/strong", r'^command\\n$'),
+ (".//li/strong", r'^program\\n$'),
+ (".//li/em", r'^dfn\\n$'),
+ (".//li/tt/span[@class='pre']", r'^kbd\\n$'),
+ (".//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']"
+ "[@class='pep reference external']/strong", 'PEP 8'),
+ (".//a[@href='http://tools.ietf.org/html/rfc1.html']"
+ "[@class='rfc reference external']/strong", 'RFC 1'),
+ (".//a[@href='objects.html#envvar-HOME']"
+ "[@class='reference internal']/tt/span[@class='pre']", 'HOME'),
+ (".//a[@href='#with']"
+ "[@class='reference internal']/tt/span[@class='pre']", '^with$'),
+ (".//a[@href='#grammar-token-try_stmt']"
+ "[@class='reference internal']/tt/span", '^statement$'),
+ (".//a[@href='subdir/includes.html']"
+ "[@class='reference internal']/em", 'Including in subdir'),
+ (".//a[@href='objects.html#cmdoption-python-c']"
+ "[@class='reference internal']/em", 'Python -c option'),
# abbreviations
- ".//abbr[@title='abbreviation']": '^abbr$',
+ (".//abbr[@title='abbreviation']", '^abbr$'),
# version stuff
- ".//span[@class='versionmodified']": 'New in version 0.6',
+ (".//span[@class='versionmodified']", 'New in version 0.6'),
# footnote reference
- ".//a[@class='footnote-reference']": r'\[1\]',
+ (".//a[@class='footnote-reference']", r'\[1\]'),
# created by reference lookup
- ".//a[@href='contents.html#ref1']": '',
+ (".//a[@href='contents.html#ref1']", ''),
# ``seealso`` directive
- ".//div/p[@class='first admonition-title']": 'See also',
+ (".//div/p[@class='first admonition-title']", 'See also'),
# a ``hlist`` directive
- ".//table[@class='hlist']/tr/td/ul/li": '^This$',
+ (".//table[@class='hlist']/tr/td/ul/li", '^This$'),
# a ``centered`` directive
- ".//p[@class='centered']/strong": 'LICENSE',
+ (".//p[@class='centered']/strong", 'LICENSE'),
# a glossary
- ".//dl/dt[@id='term-boson']": 'boson',
+ (".//dl/dt[@id='term-boson']", 'boson'),
# a production list
- ".//pre/strong": 'try_stmt',
- ".//pre/a[@href='#grammar-token-try1_stmt']/tt/span": 'try1_stmt',
+ (".//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'][@class='reference internal']": '',
- ".//dl[@class='userdesc']": '',
- ".//dt[@id='userdesc-myobj']": '',
- ".//a[@href='#userdesc-myobj']": '',
+ (".//p", 'A global substitution.'),
+ (".//p", 'In HTML.'),
+ (".//p", 'In both.'),
+ (".//p", 'Always present'),
+ ],
+ 'objects.html': [
+ (".//dt[@id='mod.Cls.meth1']", ''),
+ (".//dt[@id='errmod.Error']", ''),
+ (".//dt/tt", r'long\(parameter,\s* list\)'),
+ (".//dt/tt", 'another one'),
+ (".//a[@href='#mod.Cls'][@class='reference internal']", ''),
+ (".//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']": '',
+ (".//span[@class='pre']", 'CFunction()'),
+ (".//a[@href='#Sphinx_DoSomething']", ''),
+ (".//a[@href='#SphinxStruct.member']", ''),
+ (".//a[@href='#SPHINX_USE_PYTHON']", ''),
+ (".//a[@href='#SphinxType']", ''),
+ (".//a[@href='#sphinx_global']", ''),
# reference from old C markup extension
- ".//a[@href='#Sphinx_Func']": '',
+ (".//a[@href='#Sphinx_Func']", ''),
# 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',
+ (".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='']",
+ 'Testing object descriptions'),
+ (".//li[@class='toctree-l1']/a[@href='markup.html']",
+ 'Testing various markup'),
# custom sidebar
- ".//h4": 'Custom sidebar',
- },
- 'contents.html': {
- ".//meta[@name='hc'][@content='hcval']": '',
- ".//meta[@name='hc_co'][@content='hcval_co']": '',
- ".//meta[@name='testopt'][@content='testoverride']": '',
- ".//td[@class='label']": r'\[Ref1\]',
- ".//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/']"
- "[@class='reference external']": '',
- ".//li/a[@href='genindex.html']/em": 'Index',
- ".//li/a[@href='py-modindex.html']/em": 'Module Index',
- ".//li/a[@href='search.html']/em": 'Search Page',
+ (".//h4", 'Custom sidebar'),
+ # docfields
+ (".//td[@class='field-body']/ul/li/strong", '^moo$'),
+ (".//td[@class='field-body']/ul/li/strong",
+ tail_check(r'\(Moo\) .* Moo')),
+ ],
+ 'contents.html': [
+ (".//meta[@name='hc'][@content='hcval']", ''),
+ (".//meta[@name='hc_co'][@content='hcval_co']", ''),
+ (".//meta[@name='testopt'][@content='testoverride']", ''),
+ (".//td[@class='label']", r'\[Ref1\]'),
+ (".//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/']"
+ "[@class='reference external']", ''),
+ (".//li/a[@href='genindex.html']/em", 'Index'),
+ (".//li/a[@href='py-modindex.html']/em", 'Module Index'),
+ (".//li/a[@href='search.html']/em", 'Search Page'),
# custom sidebar only for contents
- ".//h4": 'Contents sidebar',
- },
- '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>',
- },
+ (".//h4", 'Contents sidebar'),
+ ],
+ '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']//pre":
- r'^class Foo:\n pass\n\s*$',
- ".//div[@class='inc-pyobj2 highlight-text']//pre":
- r'^ def baz\(\):\n pass\n\s*$',
- ".//div[@class='inc-lines highlight-text']//pre":
- r'^class Foo:\n pass\nclass Bar:\n$',
- ".//div[@class='inc-startend highlight-text']//pre":
- ur'^foo = u"Including Unicode characters: üöä"\n$',
- ".//div[@class='inc-preappend highlight-text']//pre":
- r'(?m)^START CODE$',
- ".//div[@class='inc-pyobj-dedent highlight-python']//span":
- r'def',
- ".//div[@class='inc-tab3 highlight-text']//pre":
- r'-| |-',
- ".//div[@class='inc-tab8 highlight-python']//pre":
- r'-| |-',
- })
- HTML_XPATH['subdir/includes.html'].update({
- ".//pre/span": 'line 1',
- ".//pre/span": 'line 2',
- })
+ HTML_XPATH['includes.html'].extend([
+ (".//pre/span[@class='s']", u'üöä'),
+ (".//div[@class='inc-pyobj1 highlight-text']//pre",
+ r'^class Foo:\n pass\n\s*$'),
+ (".//div[@class='inc-pyobj2 highlight-text']//pre",
+ r'^ def baz\(\):\n pass\n\s*$'),
+ (".//div[@class='inc-lines highlight-text']//pre",
+ r'^class Foo:\n pass\nclass Bar:\n$'),
+ (".//div[@class='inc-startend highlight-text']//pre",
+ ur'^foo = "Including Unicode characters: üöä"\n$'),
+ (".//div[@class='inc-preappend highlight-text']//pre",
+ r'(?m)^START CODE$'),
+ (".//div[@class='inc-pyobj-dedent highlight-python']//span",
+ r'def'),
+ (".//div[@class='inc-tab3 highlight-text']//pre",
+ r'-| |-'),
+ (".//div[@class='inc-tab8 highlight-python']//pre",
+ r'-| |-'),
+ ])
+ HTML_XPATH['subdir/includes.html'].extend([
+ (".//pre/span", 'line 1'),
+ (".//pre/span", 'line 2'),
+ ])
class NslessParser(ET.XMLParser):
"""XMLParser that throws away namespaces in tag names."""
@@ -282,14 +306,14 @@ def test_html(app):
html_warnings_exp = HTML_WARNINGS % {'root': re.escape(app.srcdir)}
assert re.match(html_warnings_exp + '$', html_warnings), \
'Warnings don\'t match:\n' + \
- '\n'.join(difflib.ndiff(html_warnings_exp.splitlines(),
- html_warnings.splitlines()))
+ '--- Expected (regex):\n' + html_warnings_exp + \
+ '--- Got:\n' + html_warnings
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():
+ for path, check in paths:
yield check_xpath, etree, fname, path, check
check_static_entries(app.builder.outdir)
diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py
index 6a20746b..6c1ccad9 100644
--- a/tests/test_build_latex.py
+++ b/tests/test_build_latex.py
@@ -12,7 +12,6 @@
import os
import re
import sys
-import difflib
from StringIO import StringIO
from subprocess import Popen, PIPE
@@ -33,6 +32,9 @@ None:None: WARNING: no matching candidate for image URI u'foo.\\*'
WARNING: invalid pair index entry u''
"""
+if sys.version_info >= (3, 0):
+ LATEX_WARNINGS = remove_unicode_literals(LATEX_WARNINGS)
+
@with_app(buildername='latex', warning=latex_warnfile, cleanenv=True)
def test_latex(app):
@@ -42,8 +44,9 @@ def test_latex(app):
latex_warnings_exp = LATEX_WARNINGS % {'root': app.srcdir}
assert re.match(latex_warnings_exp + '$', latex_warnings), \
'Warnings don\'t match:\n' + \
- '\n'.join(difflib.ndiff(latex_warnings_exp.splitlines(),
- latex_warnings.splitlines()))
+ '--- Expected (regex):\n' + latex_warnings_exp + \
+ '--- Got:\n' + latex_warnings
+
# file from latex_additional_files
assert (app.outdir / 'svgimg.svg').isfile()
diff --git a/tests/test_config.py b/tests/test_config.py
index cb4e1105..b5f88a6f 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -9,6 +9,7 @@
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+import sys
from util import *
@@ -84,11 +85,23 @@ def test_extension_values(app):
@with_tempdir
def test_errors_warnings(dir):
# test the error for syntax errors in the config file
- write_file(dir / 'conf.py', 'project = \n')
+ write_file(dir / 'conf.py', u'project = \n', 'ascii')
raises_msg(ConfigError, 'conf.py', Config, dir, 'conf.py', {}, None)
+ # test the automatic conversion of 2.x only code in configs
+ write_file(dir / 'conf.py', u'# -*- coding: utf-8\n\n'
+ u'project = u"Jägermeister"\n', 'utf-8')
+ cfg = Config(dir, 'conf.py', {}, None)
+ cfg.init_values()
+ assert cfg.project == u'Jägermeister'
+
# test the warning for bytestrings with non-ascii content
- write_file(dir / 'conf.py', '# -*- coding: latin-1\nproject = "foo\xe4"\n')
+ # bytestrings with non-ascii content are a syntax error in python3 so we
+ # skip the test there
+ if sys.version_info >= (3, 0):
+ return
+ write_file(dir / 'conf.py', u'# -*- coding: latin-1\nproject = "fooä"\n',
+ 'latin-1')
cfg = Config(dir, 'conf.py', {}, None)
warned = [False]
def warn(msg):
diff --git a/tests/test_coverage.py b/tests/test_coverage.py
index 1262ebf5..cb831635 100644
--- a/tests/test_coverage.py
+++ b/tests/test_coverage.py
@@ -33,7 +33,7 @@ def test_build(app):
assert 'api.h' in c_undoc
assert ' * Py_SphinxTest' in c_undoc
- undoc_py, undoc_c = pickle.loads((app.outdir / 'undoc.pickle').text())
+ undoc_py, undoc_c = pickle.loads((app.outdir / 'undoc.pickle').bytes())
assert len(undoc_c) == 1
# the key is the full path to the header file, which isn't testable
assert undoc_c.values()[0] == [('function', 'Py_SphinxTest')]
diff --git a/tests/test_env.py b/tests/test_env.py
index 4ecbaac4..124ed08c 100644
--- a/tests/test_env.py
+++ b/tests/test_env.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+import sys
from util import *
@@ -54,8 +55,10 @@ def test_images():
app._warning.reset()
htmlbuilder = StandaloneHTMLBuilder(app)
htmlbuilder.post_process_images(tree)
- assert "no matching candidate for image URI u'foo.*'" in \
- app._warning.content[-1]
+ image_uri_message = "no matching candidate for image URI u'foo.*'"
+ if sys.version_info >= (3, 0):
+ image_uri_message = remove_unicode_literals(image_uri_message)
+ assert image_uri_message in app._warning.content[-1]
assert set(htmlbuilder.images.keys()) == \
set(['subdir/img.png', 'img.png', 'subdir/simg.png', 'svgimg.svg'])
assert set(htmlbuilder.images.values()) == \
@@ -64,8 +67,7 @@ def test_images():
app._warning.reset()
latexbuilder = LaTeXBuilder(app)
latexbuilder.post_process_images(tree)
- assert "no matching candidate for image URI u'foo.*'" in \
- app._warning.content[-1]
+ assert image_uri_message in app._warning.content[-1]
assert set(latexbuilder.images.keys()) == \
set(['subdir/img.png', 'subdir/simg.png', 'img.png', 'img.pdf',
'svgimg.pdf'])
diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py
index 622243e6..990e35bd 100644
--- a/tests/test_intersphinx.py
+++ b/tests/test_intersphinx.py
@@ -11,7 +11,10 @@
import zlib
import posixpath
-from cStringIO import StringIO
+try:
+ from io import BytesIO
+except ImportError:
+ from cStringIO import StringIO as BytesIO
from docutils import nodes
@@ -28,23 +31,23 @@ inventory_v1 = '''\
# Version: 1.0
module mod foo.html
module.cls class foo.html
-'''
+'''.encode('utf-8')
inventory_v2 = '''\
# Sphinx inventory version 2
# Project: foo
# Version: 2.0
# The remainder of this file is compressed with zlib.
-''' + zlib.compress('''\
+'''.encode('utf-8') + zlib.compress('''\
module1 py:module 0 foo.html#module-module1 Long Module desc
module2 py:module 0 foo.html#module-$ -
module1.func py:function 1 sub/foo.html#$ -
CFunc c:function 2 cfunc.html#CFunc -
-''')
+'''.encode('utf-8'))
def test_read_inventory_v1():
- f = StringIO(inventory_v1)
+ f = BytesIO(inventory_v1)
f.readline()
invdata = read_inventory_v1(f, '/util', posixpath.join)
assert invdata['py:module']['module'] == \
@@ -54,12 +57,12 @@ def test_read_inventory_v1():
def test_read_inventory_v2():
- f = StringIO(inventory_v2)
+ f = BytesIO(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 = BytesIO(inventory_v2)
f.readline()
invdata2 = read_inventory_v2(f, '/util', posixpath.join, bufsize=5)
@@ -80,7 +83,10 @@ def test_read_inventory_v2():
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_mapping = {
+ 'http://docs.python.org/': inv_file,
+ 'py3k': ('http://docs.python.org/py3k/', inv_file),
+ }
app.config.intersphinx_cache_limit = 0
# load the inventory and check if it's done correctly
@@ -91,22 +97,58 @@ def test_missing_reference(tempdir, app):
('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)
+ def fake_node(domain, type, target, content, **attrs):
+ contnode = nodes.emphasis(content, content)
+ node = addnodes.pending_xref('')
+ node['reftarget'] = target
+ node['reftype'] = type
+ node['refdomain'] = domain
+ node.attributes.update(attrs)
+ node += contnode
+ return node, contnode
+
+ def reference_check(*args, **kwds):
+ node, contnode = fake_node(*args, **kwds)
+ return missing_reference(app, app.env, node, contnode)
+
+ # check resolution when a target is found
+ rn = reference_check('py', 'func', 'module1.func', 'foo')
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
+ assert rn[0].astext() == 'foo'
# 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
+ assert reference_check('py', 'foo', 'module1.func', 'foo') is None
+ assert reference_check('py', 'func', 'foo', 'foo') is None
+ assert reference_check('py', 'func', 'foo', 'foo') is None
+
+ # check handling of prefixes
+
+ # prefix given, target found: prefix is stripped
+ rn = reference_check('py', 'mod', 'py3k:module2', 'py3k:module2')
+ assert rn[0].astext() == 'module2'
+
+ # prefix given, but not in title: nothing stripped
+ rn = reference_check('py', 'mod', 'py3k:module2', 'module2')
+ assert rn[0].astext() == 'module2'
+
+ # prefix given, but explicit: nothing stripped
+ rn = reference_check('py', 'mod', 'py3k:module2', 'py3k:module2',
+ refexplicit=True)
+ assert rn[0].astext() == 'py3k:module2'
+
+ # prefix given, target not found and nonexplicit title: prefix is stripped
+ node, contnode = fake_node('py', 'mod', 'py3k:unknown', 'py3k:unknown',
+ refexplicit=False)
+ rn = missing_reference(app, app.env, node, contnode)
+ assert rn is None
+ assert contnode[0].astext() == 'unknown'
+
+ # prefix given, target not found and explicit title: nothing is changed
+ node, contnode = fake_node('py', 'mod', 'py3k:unknown', 'py3k:unknown',
+ refexplicit=True)
+ rn = missing_reference(app, app.env, node, contnode)
+ assert rn is None
+ assert contnode[0].astext() == 'py3k:unknown'
diff --git a/tests/test_markup.py b/tests/test_markup.py
index 31817df6..092113bb 100644
--- a/tests/test_markup.py
+++ b/tests/test_markup.py
@@ -17,6 +17,7 @@ from docutils import frontend, utils, nodes
from docutils.parsers import rst
from sphinx.util import texescape
+from sphinx.util.pycompat import b
from sphinx.writers.html import HTMLWriter, SmartyPantsHTMLTranslator
from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator
@@ -50,7 +51,7 @@ class ForgivingLaTeXTranslator(LaTeXTranslator, ForgivingTranslator):
def verify_re(rst, html_expected, latex_expected):
- document = utils.new_document('test data', settings)
+ document = utils.new_document(b('test data'), settings)
document['file'] = 'dummy'
parser.parse(rst, document)
for msg in document.traverse(nodes.system_message):
diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py
index cb40d27c..541959bd 100644
--- a/tests/test_quickstart.py
+++ b/tests/test_quickstart.py
@@ -36,8 +36,13 @@ def mock_raw_input(answers, needanswer=False):
return ''
return raw_input
+try:
+ real_raw_input = raw_input
+except NameError:
+ real_raw_input = input
+
def teardown_module():
- qs.raw_input = __builtin__.raw_input
+ qs.term_input = real_raw_input
qs.TERM_ENCODING = getattr(sys.stdin, 'encoding', None)
coloron()
@@ -51,7 +56,7 @@ def test_do_prompt():
'Q5': 'no',
'Q6': 'foo',
}
- qs.raw_input = mock_raw_input(answers)
+ qs.term_input = mock_raw_input(answers)
try:
qs.do_prompt(d, 'k1', 'Q1')
except AssertionError:
@@ -79,13 +84,18 @@ def test_quickstart_defaults(tempdir):
'Author name': 'Georg Brandl',
'Project version': '0.1',
}
- qs.raw_input = mock_raw_input(answers)
+ qs.term_input = mock_raw_input(answers)
qs.inner_main([])
conffile = tempdir / 'conf.py'
assert conffile.isfile()
ns = {}
- execfile(conffile, ns)
+ f = open(conffile, 'U')
+ try:
+ code = compile(f.read(), conffile, 'exec')
+ finally:
+ f.close()
+ exec code in ns
assert ns['extensions'] == []
assert ns['templates_path'] == ['_templates']
assert ns['source_suffix'] == '.rst'
@@ -112,8 +122,8 @@ def test_quickstart_all_answers(tempdir):
'Root path': tempdir,
'Separate source and build': 'y',
'Name prefix for templates': '.',
- 'Project name': 'STASI\xe2\x84\xa2',
- 'Author name': 'Wolfgang Sch\xc3\xa4uble & G\'Beckstein',
+ 'Project name': u'STASI™'.encode('utf-8'),
+ 'Author name': u'Wolfgang Schäuble & G\'Beckstein'.encode('utf-8'),
'Project version': '2.0',
'Project release': '2.0.1',
'Source file suffix': '.txt',
@@ -131,14 +141,19 @@ def test_quickstart_all_answers(tempdir):
'Create Windows command file': 'no',
'Do you want to use the epub builder': 'yes',
}
- qs.raw_input = mock_raw_input(answers, needanswer=True)
+ qs.term_input = mock_raw_input(answers, needanswer=True)
qs.TERM_ENCODING = 'utf-8'
qs.inner_main([])
conffile = tempdir / 'source' / 'conf.py'
assert conffile.isfile()
ns = {}
- execfile(conffile, ns)
+ f = open(conffile, 'U')
+ try:
+ code = compile(f.read(), conffile, 'exec')
+ finally:
+ f.close()
+ exec code in ns
assert ns['extensions'] == ['sphinx.ext.autodoc', 'sphinx.ext.doctest']
assert ns['templates_path'] == ['.templates']
assert ns['source_suffix'] == '.txt'
diff --git a/tests/test_search.py b/tests/test_search.py
index 0b5b158b..c0750366 100644
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -13,6 +13,7 @@ from docutils import frontend, utils
from docutils.parsers import rst
from sphinx.search import IndexBuilder
+from sphinx.util.pycompat import b
settings = parser = None
@@ -31,7 +32,7 @@ test that non-comments are indexed: fermion
'''
def test_wordcollector():
- doc = utils.new_document('test data', settings)
+ doc = utils.new_document(b('test data'), settings)
doc['file'] = 'dummy'
parser.parse(FILE_CONTENTS, doc)
diff --git a/tests/test_versioning.py b/tests/test_versioning.py
new file mode 100644
index 00000000..54a48f4a
--- /dev/null
+++ b/tests/test_versioning.py
@@ -0,0 +1,104 @@
+# -*- coding: utf-8 -*-
+"""
+ test_versioning
+ ~~~~~~~~~~~~~~~
+
+ Test the versioning implementation.
+
+ :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+import pickle
+
+from util import *
+
+from docutils.statemachine import ViewList
+from docutils.parsers.rst.directives.html import MetaBody
+
+from sphinx import addnodes
+from sphinx.versioning import make_diff, add_uids, merge_doctrees
+
+def setup_module():
+ global app, original, original_uids
+ app = TestApp()
+ app.builder.env.app = app
+ app.connect('doctree-resolved', on_doctree_resolved)
+ app.build()
+ original = doctrees['versioning/original']
+ original_uids = [n.uid for n in add_uids(original, is_paragraph)]
+
+def teardown_module():
+ app.cleanup()
+ (test_root / '_build').rmtree(True)
+
+doctrees = {}
+
+def on_doctree_resolved(app, doctree, docname):
+ doctrees[docname] = doctree
+
+def test_make_diff():
+ tests = [
+ (('aaa', 'aaa'), (True, False, False)),
+ (('aaa', 'aab'), (False, True, False)),
+ (('aaa', 'abb'), (False, True, False)),
+ (('aaa', 'aba'), (False, True, False)),
+ (('aaa', 'baa'), (False, True, False)),
+ (('aaa', 'bbb'), (False, False, True))
+ ]
+ for args, result in tests:
+ assert make_diff(*args) == result
+
+def is_paragraph(node):
+ return node.__class__.__name__ == 'paragraph'
+
+def test_add_uids():
+ assert len(original_uids) == 3
+
+def test_picklablility():
+ # we have to modify the doctree so we can pickle it
+ copy = original.copy()
+ copy.reporter = None
+ copy.transformer = None
+ copy.settings.warning_stream = None
+ copy.settings.env = None
+ copy.settings.record_dependencies = None
+ for metanode in copy.traverse(MetaBody.meta):
+ metanode.__class__ = addnodes.meta
+ loaded = pickle.loads(pickle.dumps(copy, pickle.HIGHEST_PROTOCOL))
+ assert all(getattr(n, 'uid', False) for n in loaded.traverse(is_paragraph))
+
+def test_modified():
+ modified = doctrees['versioning/modified']
+ new_nodes = list(merge_doctrees(original, modified, is_paragraph))
+ uids = [n.uid for n in modified.traverse(is_paragraph)]
+ assert not new_nodes
+ assert original_uids == uids
+
+def test_added():
+ added = doctrees['versioning/added']
+ new_nodes = list(merge_doctrees(original, added, is_paragraph))
+ uids = [n.uid for n in added.traverse(is_paragraph)]
+ assert len(new_nodes) == 1
+ assert original_uids == uids[:-1]
+
+def test_deleted():
+ deleted = doctrees['versioning/deleted']
+ new_nodes = list(merge_doctrees(original, deleted, is_paragraph))
+ uids = [n.uid for n in deleted.traverse(is_paragraph)]
+ assert not new_nodes
+ assert original_uids[::2] == uids
+
+def test_deleted_end():
+ deleted_end = doctrees['versioning/deleted_end']
+ new_nodes = list(merge_doctrees(original, deleted_end, is_paragraph))
+ uids = [n.uid for n in deleted_end.traverse(is_paragraph)]
+ assert not new_nodes
+ assert original_uids[:-1] == uids
+
+def test_insert():
+ insert = doctrees['versioning/insert']
+ new_nodes = list(merge_doctrees(original, insert, is_paragraph))
+ uids = [n.uid for n in insert.traverse(is_paragraph)]
+ assert len(new_nodes) == 1
+ assert original_uids[0] == uids[0]
+ assert original_uids[1:] == uids[2:]
diff --git a/tests/util.py b/tests/util.py
index 1b24af0e..b81e15b6 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -11,6 +11,8 @@ import sys
import StringIO
import tempfile
import shutil
+import re
+from codecs import open
try:
from functools import wraps
@@ -31,7 +33,7 @@ __all__ = [
'raises', 'raises_msg', 'Struct',
'ListOutput', 'TestApp', 'with_app', 'gen_with_app',
'path', 'with_tempdir', 'write_file',
- 'sprint',
+ 'sprint', 'remove_unicode_literals',
]
@@ -191,11 +193,21 @@ def with_tempdir(func):
return new_func
-def write_file(name, contents):
- f = open(str(name), 'wb')
+def write_file(name, contents, encoding=None):
+ if encoding is None:
+ mode = 'wb'
+ if isinstance(contents, unicode):
+ contents = contents.encode('ascii')
+ else:
+ mode = 'w'
+ f = open(str(name), 'wb', encoding=encoding)
f.write(contents)
f.close()
def sprint(*args):
sys.stderr.write(' '.join(map(str, args)) + '\n')
+
+_unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')')
+def remove_unicode_literals(s):
+ return _unicode_literals_re.sub(lambda x: x.group(1) or x.group(2), s)