merge heads

This commit is contained in:
Takayuki Shimizukawa 2014-01-18 16:34:47 +09:00
commit dd41adf0a0
26 changed files with 54 additions and 382 deletions

View File

@ -1,6 +1,11 @@
Release 1.3 (in development)
============================
Change support versions
-----------------------
* Drop Python-2.5, 3.1 (support code was completely removed)
Incompatible changes
--------------------

View File

@ -4,7 +4,7 @@ Installing Sphinx
=================
Since Sphinx is written in the Python language, you need to install Python
(the required version is at least 2.5) and Sphinx.
(the required version is at least 2.6) and Sphinx.
Sphinx packages are available on the `Python Package Index
<https://pypi.python.org/pypi/Sphinx>`_.
@ -79,8 +79,8 @@ sidebar and under "Quick Links", click "Windows Installer" to download.
.. note::
Currently, Python offers two major versions, 2.x and 3.x. Sphinx 1.2 can run
under Python 2.5 to 2.7 and 3.1 to 3.3, with the recommended version being
Currently, Python offers two major versions, 2.x and 3.x. Sphinx 1.3 can run
under Python 2.6, 2.7, 3.2, 3.3, with the recommended version being
2.7. This chapter assumes you have installed Python 2.7.
Follow the Windows installer for Python.

View File

@ -54,7 +54,7 @@ See the :ref:`pertinent section in the FAQ list <usingwith>`.
Prerequisites
-------------
Sphinx needs at least **Python 2.5** or **Python 3.1** to run, as well as the
Sphinx needs at least **Python 2.6** or **Python 3.2** to run, as well as the
docutils_ and Jinja2_ libraries. Sphinx should work with docutils version 0.7
or some (not broken) SVN trunk snapshot. If you like to have source code
highlighting support, you must also install the Pygments_ library.

View File

@ -44,20 +44,20 @@ A development egg can be found `here
<http://bitbucket.org/birkenfeld/sphinx/get/tip.gz#egg=Sphinx-dev>`_.
'''
if sys.version_info < (2, 6) or (3, 0) <= sys.version_info < (3, 2):
print('ERROR: Sphinx requires at least Python 2.6 or 3.2 to run.')
sys.exit(1)
requires = ['Pygments>=1.2', 'docutils>=0.7']
if sys.version_info[:3] >= (3, 3, 0):
requires[1] = 'docutils>=0.10'
if sys.version_info < (2, 6) or (3, 0) <= sys.version_info < (3, 3):
if (3, 0) <= sys.version_info < (3, 3):
requires.append('Jinja2>=2.3,<2.7')
else:
else: # 2.6, 2.7, 3.3 or later
requires.append('Jinja2>=2.3')
if sys.version_info < (2, 5):
print('ERROR: Sphinx requires at least Python 2.5 to run.')
sys.exit(1)
# tell distribute to use 2to3 with our own fixers
extra = {}
if sys.version_info >= (3, 0):

View File

@ -42,8 +42,9 @@ if '+' in __version__ or 'pre' in __version__:
def main(argv=sys.argv):
"""Sphinx build "main" command-line entry."""
if sys.version_info[:3] < (2, 5, 0):
sys.stderr.write('Error: Sphinx requires at least Python 2.5 to run.\n')
if (sys.version_info[:3] < (2, 6, 0) or
(3, 0, 0) <= sys.version_info[:3] < (3, 2, 0)):
sys.stderr.write('Error: Sphinx requires at least Python 2.6 to run.\n')
return 1
try:
from sphinx import cmdline

View File

@ -12,7 +12,6 @@
import os
import re
import sys
import time
import codecs
import zipfile
@ -750,12 +749,5 @@ class EpubBuilder(StandaloneHTMLBuilder):
zipfile.ZIP_STORED)
for file in projectfiles:
fp = path.join(outdir, file)
if sys.version_info < (2, 6):
# When zipile.ZipFile.write call with unicode filename, ZipFile
# encode filename to 'utf-8' (only after Python-2.6).
if isinstance(file, unicode):
# OEBPS Container Format (OCF) 2.0.1 specification require
# "File Names MUST be UTF-8 encoded".
file = file.encode('utf-8')
epub.write(fp, file, zipfile.ZIP_DEFLATED)
epub.close()

View File

@ -16,11 +16,7 @@ import codecs
import posixpath
import cPickle as pickle
from os import path
try:
from hashlib import md5
except ImportError:
# 2.4 compatibility
from md5 import md5
from hashlib import md5
from docutils import nodes
from docutils.io import DocTreeInput, StringOutput
@ -35,7 +31,7 @@ from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \
movefile, ustrftime, copyfile
from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.matching import patmatch, compile_matchers
from sphinx.util.pycompat import any, b
from sphinx.util.pycompat import b
from sphinx.errors import SphinxError
from sphinx.locale import _
from sphinx.search import js_index
@ -1098,8 +1094,4 @@ class JSONHTMLBuilder(SerializingHTMLBuilder):
searchindex_filename = 'searchindex.json'
def init(self):
if jsonimpl.json is None:
raise SphinxError(
'The module simplejson (or json in Python >= 2.6) '
'is not available. The JSONHTMLBuilder builder will not work.')
SerializingHTMLBuilder.init(self)

View File

@ -10,7 +10,6 @@
"""
import re
import sys
import Queue
import socket
import threading
@ -110,7 +109,7 @@ class CheckExternalLinksBuilder(Builder):
def check_thread(self):
kwargs = {}
if sys.version_info > (2, 5) and self.app.config.linkcheck_timeout:
if self.app.config.linkcheck_timeout:
kwargs['timeout'] = self.app.config.linkcheck_timeout
def check():

View File

@ -29,7 +29,7 @@ from sphinx.util.nodes import nested_parse_with_titles
from sphinx.util.compat import Directive
from sphinx.util.inspect import getargspec, isdescriptor, safe_getmembers, \
safe_getattr, safe_repr, is_builtin_class_method
from sphinx.util.pycompat import base_exception, class_types
from sphinx.util.pycompat import class_types
from sphinx.util.docstrings import prepare_docstring
@ -1130,7 +1130,7 @@ class ExceptionDocumenter(ClassDocumenter):
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, class_types) and \
issubclass(member, base_exception)
issubclass(member, BaseException)
class DataDocumenter(ModuleLevelDocumenter):

View File

@ -63,12 +63,6 @@ _LATEX_STYLES = r'''
\newcommand\PYGZcb{\char`\}}
'''
parsing_exceptions = (SyntaxError, UnicodeEncodeError)
if sys.version_info < (2, 5):
# Python <= 2.4 raises MemoryError when parsing an
# invalid encoding cookie
parsing_exceptions += MemoryError,
class PygmentsBridge(object):
# Set these attributes if you want to have different Pygments formatters
@ -131,10 +125,6 @@ class PygmentsBridge(object):
# lines beginning with "..." are probably placeholders for suite
src = re.sub(r"(?m)^(\s*)" + mark + "(.)", r"\1"+ mark + r"# \2", src)
# if we're using 2.5, use the with statement
if sys.version_info >= (2, 5):
src = 'from __future__ import with_statement\n' + src
if sys.version_info < (3, 0) and isinstance(src, unicode):
# Non-ASCII chars will only occur in string literals
# and comments. If we wanted to give them to the parser
@ -143,18 +133,12 @@ class PygmentsBridge(object):
# just replace all non-ASCII characters.
src = src.encode('ascii', 'replace')
if (3, 0) <= sys.version_info < (3, 2):
# Python 3.1 can't process '\r' as linesep.
# `parser.suite("print('hello')\r\n")` cause error.
if '\r\n' in src:
src = src.replace('\r\n', '\n')
if parser is None:
return True
try:
parser.suite(src)
except parsing_exceptions:
except (SyntaxError, UnicodeEncodeError):
return False
else:
return True

View File

@ -17,7 +17,7 @@ from sphinx.errors import PycodeError
from sphinx.pycode import nodes
from sphinx.pycode.pgen2 import driver, token, tokenize, parse, literals
from sphinx.util import get_module_source, detect_encoding
from sphinx.util.pycompat import next, StringIO, BytesIO, TextIOWrapper
from sphinx.util.pycompat import StringIO, BytesIO, TextIOWrapper
from sphinx.util.docstrings import prepare_docstring, prepare_commentdoc

View File

@ -353,95 +353,6 @@ static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, const char* function_name); /*proto*/
#if PY_VERSION_HEX < 0x02050000
#ifndef PyAnySet_CheckExact
#define PyAnySet_CheckExact(ob) \
((ob)->ob_type == &PySet_Type || \
(ob)->ob_type == &PyFrozenSet_Type)
#define PySet_New(iterable) \
PyObject_CallFunctionObjArgs((PyObject *)&PySet_Type, (iterable), NULL)
#define Pyx_PyFrozenSet_New(iterable) \
PyObject_CallFunctionObjArgs((PyObject *)&PyFrozenSet_Type, (iterable), NULL)
#define PySet_Size(anyset) \
PyObject_Size((anyset))
#define PySet_Contains(anyset, key) \
PySequence_Contains((anyset), (key))
#define PySet_Pop(set) \
PyObject_CallMethod(set, (char *)"pop", NULL)
static INLINE int PySet_Clear(PyObject *set) {
PyObject *ret = PyObject_CallMethod(set, (char *)"clear", NULL);
if (!ret) return -1;
Py_DECREF(ret); return 0;
}
static INLINE int PySet_Discard(PyObject *set, PyObject *key) {
PyObject *ret = PyObject_CallMethod(set, (char *)"discard", (char *)"O", key);
if (!ret) return -1;
Py_DECREF(ret); return 0;
}
static INLINE int PySet_Add(PyObject *set, PyObject *key) {
PyObject *ret = PyObject_CallMethod(set, (char *)"add", (char *)"O", key);
if (!ret) return -1;
Py_DECREF(ret); return 0;
}
#endif /* PyAnySet_CheckExact (<= Py2.4) */
#if PY_VERSION_HEX < 0x02040000
#ifndef Py_SETOBJECT_H
#define Py_SETOBJECT_H
static PyTypeObject *__Pyx_PySet_Type = NULL;
static PyTypeObject *__Pyx_PyFrozenSet_Type = NULL;
#define PySet_Type (*__Pyx_PySet_Type)
#define PyFrozenSet_Type (*__Pyx_PyFrozenSet_Type)
#define PyAnySet_Check(ob) \
(PyAnySet_CheckExact(ob) || \
PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \
PyType_IsSubtype((ob)->ob_type, &PyFrozenSet_Type))
#define PyFrozenSet_CheckExact(ob) ((ob)->ob_type == &PyFrozenSet_Type)
static int __Pyx_Py23SetsImport(void) {
PyObject *sets=0, *Set=0, *ImmutableSet=0;
sets = PyImport_ImportModule((char *)"sets");
if (!sets) goto bad;
Set = PyObject_GetAttrString(sets, (char *)"Set");
if (!Set) goto bad;
ImmutableSet = PyObject_GetAttrString(sets, (char *)"ImmutableSet");
if (!ImmutableSet) goto bad;
Py_DECREF(sets);
__Pyx_PySet_Type = (PyTypeObject*) Set;
__Pyx_PyFrozenSet_Type = (PyTypeObject*) ImmutableSet;
return 0;
bad:
Py_XDECREF(sets);
Py_XDECREF(Set);
Py_XDECREF(ImmutableSet);
return -1;
}
#else
static int __Pyx_Py23SetsImport(void) { return 0; }
#endif /* !Py_SETOBJECT_H */
#endif /* < Py2.4 */
#endif /* < Py2.5 */
static INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
PyObject *r;
if (!j) return NULL;

View File

@ -11,6 +11,7 @@
import sys, os, time, re
from os import path
from io import open
TERM_ENCODING = getattr(sys.stdin, 'encoding', None)
@ -21,7 +22,6 @@ from sphinx.util.osutil import make_filename
from sphinx.util.console import purple, bold, red, turquoise, \
nocolor, color_terminal
from sphinx.util import texescape
from sphinx.util.pycompat import open
# function to get input from terminal -- overridden by the test suite
try:

View File

@ -23,7 +23,6 @@ from sphinx.util import split_index_msg
from sphinx.util.nodes import traverse_translatable_index, extract_messages
from sphinx.util.osutil import ustrftime, find_catalog
from sphinx.util.compat import docutils_version
from sphinx.util.pycompat import all
from sphinx.domains.std import (
make_term_from_paragraph_node,
make_termnodes_from_paragraph_node,

View File

@ -55,7 +55,7 @@ if sys.version_info >= (3, 0):
raise TypeError('%r is not a Python function' % func)
return inspect.getfullargspec(func)
elif sys.version_info >= (2, 5):
else: # 2.6, 2.7
from functools import partial
def getargspec(func):
"""Like inspect.getargspec but supports functools.partial as well."""
@ -86,12 +86,7 @@ elif sys.version_info >= (2, 5):
del func_defaults[i]
except IndexError:
pass
if sys.version_info >= (2, 6):
return inspect.ArgSpec(args, varargs, varkw, func_defaults)
else:
return (args, varargs, varkw, func_defaults)
else:
getargspec = inspect.getargspec
return inspect.ArgSpec(args, varargs, varkw, func_defaults)
def isdescriptor(x):

View File

@ -10,27 +10,15 @@
"""
import UserString
try:
import json
# json-py's json module has no JSONEncoder; this will raise AttributeError
# if json-py is imported instead of the built-in json module
JSONEncoder = json.JSONEncoder
except (ImportError, AttributeError):
try:
import simplejson as json
JSONEncoder = json.JSONEncoder
except ImportError:
json = None
JSONEncoder = object
import json
class SphinxJSONEncoder(JSONEncoder):
class SphinxJSONEncoder(json.JSONEncoder):
"""JSONEncoder subclass that forces translation proxies."""
def default(self, obj):
if isinstance(obj, UserString.UserString):
return unicode(obj)
return JSONEncoder.default(self, obj)
return json.JSONEncoder.default(self, obj)
def dump(obj, fp, *args, **kwds):

View File

@ -69,6 +69,9 @@ def ensuredir(path):
raise
# This function is same as os.walk of Python2.6, 2.7, 3.2, 3.3 except a
# customization that check UnicodeError.
# The customization obstacle to replace the function with the os.walk.
def walk(top, topdown=True, followlinks=False):
"""Backport of os.walk from 2.6, where the *followlinks* argument was
added.
@ -155,9 +158,8 @@ else:
def safe_relpath(path, start=None):
from sphinx.util.pycompat import relpath
try:
return relpath(path, start)
return os.path.relpath(path, start)
except ValueError:
return path
@ -171,14 +173,13 @@ def find_catalog(docname, compaction):
def find_catalog_files(docname, srcdir, locale_dirs, lang, compaction):
from sphinx.util.pycompat import relpath
if not(lang and locale_dirs):
return []
domain = find_catalog(docname, compaction)
files = [gettext.find(domain, path.join(srcdir, dir_), [lang])
for dir_ in locale_dirs]
files = [relpath(f, srcdir) for f in files if f]
files = [path.relpath(f, srcdir) for f in files if f]
return files

View File

@ -11,7 +11,6 @@
import sys
import codecs
import encodings
# ------------------------------------------------------------------------------
# Python 2/3 compatibility
@ -48,6 +47,7 @@ if sys.version_info >= (3, 0):
# try to match ParseError details with SyntaxError details
raise SyntaxError(err.msg, (filepath, lineno, offset, err.value))
return unicode(tree)
from itertools import zip_longest # Python 3 name
else:
# Python 2
@ -69,6 +69,8 @@ else:
# error handler
import locale
sys_encoding = locale.getpreferredencoding()
# use Python 3 name
from itertools import izip_longest as zip_longest
def execfile_(filepath, _globals):
@ -81,8 +83,8 @@ def execfile_(filepath, _globals):
finally:
f.close()
# py25,py26,py31 accept only LF eol instead of CRLF
if sys.version_info[:2] in ((2, 5), (2, 6), (3, 1)):
# py26 accept only LF eol instead of CRLF
if sys.version_info[:2] == (2, 6):
source = source.replace(b('\r\n'), b('\n'))
# compile to a code object, handle syntax errors
@ -100,178 +102,7 @@ def execfile_(filepath, _globals):
exec code in _globals
try:
from html import escape as htmlescape
except ImportError:
if sys.version_info >= (3, 2):
from html import escape as htmlescape # >= Python 3.2
else: # 2.6, 2.7, 3.1
from cgi import escape as htmlescape
# ------------------------------------------------------------------------------
# Missing builtins and itertools in Python < 2.6
if sys.version_info >= (2, 6):
# Python >= 2.6
next = next
from itertools import product
try:
from itertools import zip_longest # Python 3 name
except ImportError:
from itertools import izip_longest as zip_longest
import os
relpath = os.path.relpath
del os
import io
open = io.open
else:
# Python < 2.6
from itertools import izip, repeat, chain
# this is on Python 2, where the method is called "next" (it is refactored
# to __next__ by 2to3, but in that case never executed)
def next(iterator):
return iterator.next()
# These replacement functions have been taken from the Python 2.6
# itertools documentation.
def product(*args, **kwargs):
pools = map(tuple, args) * kwargs.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x + [y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
def zip_longest(*args, **kwds):
# zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
fillvalue = kwds.get('fillvalue')
def sentinel(counter = ([fillvalue]*(len(args)-1)).pop):
yield counter() # yields the fillvalue, or raises IndexError
fillers = repeat(fillvalue)
iters = [chain(it, sentinel(), fillers) for it in args]
try:
for tup in izip(*iters):
yield tup
except IndexError:
pass
from os.path import curdir
def relpath(path, start=curdir):
"""Return a relative version of a path"""
from os.path import sep, abspath, commonprefix, join, pardir
if not path:
raise ValueError("no path specified")
start_list = abspath(start).split(sep)
path_list = abspath(path).split(sep)
# Work out how much of the filepath is shared by start and path.
i = len(commonprefix([start_list, path_list]))
rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return start
return join(*rel_list)
del curdir
from types import MethodType
def open(filename, mode='r', *args, **kw):
newline = kw.pop('newline', None)
mode = mode.replace('t', '')
f = codecs.open(filename, mode, *args, **kw)
if newline is not None:
f._write = f.write
def write(self, text):
text = text.replace(u'\r\n', u'\n').replace(u'\n', newline)
self._write(text)
f.write = MethodType(write, f)
return f
# ------------------------------------------------------------------------------
# Missing builtins and codecs in Python < 2.5
if sys.version_info >= (2, 5):
# Python >= 2.5
base_exception = BaseException
any = any
all = all
else:
# Python 2.4
base_exception = Exception
def all(gen):
for i in gen:
if not i:
return False
return True
def any(gen):
for i in gen:
if i:
return True
return False
# Python 2.4 doesn't know the utf-8-sig encoding, so deliver it here
def my_search_function(encoding):
norm_encoding = encodings.normalize_encoding(encoding)
if norm_encoding != 'utf_8_sig':
return None
return (encode, decode, StreamReader, StreamWriter)
codecs.register(my_search_function)
# begin code copied from utf_8_sig.py in Python 2.6
def encode(input, errors='strict'):
return (codecs.BOM_UTF8 +
codecs.utf_8_encode(input, errors)[0], len(input))
def decode(input, errors='strict'):
prefix = 0
if input[:3] == codecs.BOM_UTF8:
input = input[3:]
prefix = 3
(output, consumed) = codecs.utf_8_decode(input, errors, True)
return (output, consumed+prefix)
class StreamWriter(codecs.StreamWriter):
def reset(self):
codecs.StreamWriter.reset(self)
try:
del self.encode
except AttributeError:
pass
def encode(self, input, errors='strict'):
self.encode = codecs.utf_8_encode
return encode(input, errors)
class StreamReader(codecs.StreamReader):
def reset(self):
codecs.StreamReader.reset(self)
try:
del self.decode
except AttributeError:
pass
def decode(self, input, errors='strict'):
if len(input) < 3:
if codecs.BOM_UTF8.startswith(input):
# not enough data to decide if this is a BOM
# => try again on the next call
return (u"", 0)
elif input[:3] == codecs.BOM_UTF8:
self.decode = codecs.utf_8_decode
(output, consumed) = codecs.utf_8_decode(input[3:],errors)
return (output, consumed+3)
# (else) no BOM present
self.decode = codecs.utf_8_decode
return codecs.utf_8_decode(input, errors)
# end code copied from utf_8_sig.py

View File

@ -11,8 +11,9 @@
"""
from uuid import uuid4
from operator import itemgetter
from itertools import product
from sphinx.util.pycompat import product, zip_longest, all
from sphinx.util.pycompat import zip_longest
# anything below that ratio is considered equal/changed

View File

@ -25,7 +25,6 @@ from sphinx.errors import SphinxError
from sphinx.locale import admonitionlabels, _
from sphinx.util import split_into
from sphinx.util.osutil import ustrftime
from sphinx.util.pycompat import any
from sphinx.util.texescape import tex_escape_map, tex_replace_map
from sphinx.util.smartypants import educate_quotes_latex

View File

@ -751,12 +751,8 @@ def _funky_classmethod(name, b, c, d, docstring=None):
some arguments."""
def template(cls, a, b, c, d=4, e=5, f=6):
return a, b, c, d, e, f
if sys.version_info >= (2, 5):
from functools import partial
function = partial(template, b=b, c=c, d=d)
else:
def function(cls, a, e=5, f=6):
return template(a, b, c, d, e, f)
from functools import partial
function = partial(template, b=b, c=c, d=d)
function.__name__ = name
function.__doc__ = docstring
return classmethod(function)
@ -788,10 +784,9 @@ class Class(Base):
#: should be documented -- süß
attr = 'bar'
@property
def prop(self):
"""Property."""
# stay 2.4 compatible (docstring!)
prop = property(prop, doc="Property.")
docattr = 'baz'
"""should likewise be documented -- süß"""

View File

@ -16,8 +16,6 @@ from StringIO import StringIO
from subprocess import Popen, PIPE
from xml.etree import ElementTree
from sphinx.util.pycompat import relpath
from util import test_roots, path, with_app, SkipTest
@ -49,7 +47,7 @@ def setup_module():
for f in [f for f in files if f.endswith('.po')]:
po = dirpath / f
mo = root / 'xx' / 'LC_MESSAGES' / (
relpath(po[:-3], root) + '.mo')
os.path.relpath(po[:-3], root) + '.mo')
if not mo.parent.exists():
mo.parent.makedirs()
try:
@ -75,7 +73,7 @@ def teardown_module():
def elem_gettexts(elem):
def itertext(self):
# this function copied from Python-2.7 'ElementTree.itertext'.
# for compatibility to Python-2.5, 2.6, 3.1
# for compatibility to Python-2.6
tag = self.tag
if not isinstance(tag, basestring) and tag is not None:
return

View File

@ -15,7 +15,6 @@ from docutils.parsers.rst.directives.html import MetaBody
from sphinx import addnodes
from sphinx.versioning import add_uids, merge_doctrees, get_ratio
from sphinx.util.pycompat import all
from util import test_root, TestApp

View File

@ -11,12 +11,7 @@
import os
from StringIO import StringIO
try:
from functools import wraps
except ImportError:
# functools is new in 2.5
wraps = lambda f: (lambda w: w)
from functools import wraps
from sphinx.websupport import WebSupport
from sphinx.websupport.errors import DocumentNotFoundError, \

View File

@ -13,12 +13,7 @@ import tempfile
import shutil
import re
from codecs import open
try:
from functools import wraps
except ImportError:
# functools is new in 2.4
wraps = lambda f: (lambda w: w)
from functools import wraps
from sphinx import application
from sphinx.theming import Theme

10
tox.ini
View File

@ -1,5 +1,5 @@
[tox]
envlist=py25,py26,py27,py31,py32,py33,pypy,du11,du10,du09,du08,du07
envlist=py26,py27,py32,py33,pypy,du11,du10,du09,du08,du07
[testenv]
deps=
@ -12,14 +12,6 @@ commands=
{envpython} tests/run.py {posargs}
sphinx-build -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html
[testenv:py25]
deps=
simplejson==2.5.0
{[testenv]deps}
setenv=
PIP_INSECURE = 1
{[testenv]setenv}
[testenv:py33]
deps=
docutils>=0.10.0