PYTHON-1153 - Make docs build and test under python 3

This commit is contained in:
Bernie Hackett 2016-09-26 15:49:59 -07:00
parent e89ba4bcd0
commit c0767a551a
11 changed files with 192 additions and 84 deletions

View File

@ -30,8 +30,8 @@ Example usage (serialization):
>>> from bson.json_util import dumps
>>> dumps([{'foo': [1, 2]},
... {'bar': {'hello': 'world'}},
... {'code': Code("function x() { return 1; }")},
... {'bin': Binary("\x01\x02\x03\x04")}])
... {'code': Code("function x() { return 1; }", {})},
... {'bin': Binary(b"\x01\x02\x03\x04")}])
'[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }", "$scope": {}}}, {"bin": {"$binary": "AQIDBA==", "$type": "00"}}]'
Example usage (deserialization):

View File

@ -66,9 +66,9 @@ pygments_style = 'sphinx'
# -- Options for extensions ----------------------------------------------------
autoclass_content = 'init'
doctest_path = os.path.abspath('..')
doctest_path = [os.path.abspath('..')]
doctest_test_doctest_blocks = False
doctest_test_doctest_blocks = ''
doctest_global_setup = """
from pymongo.mongo_client import MongoClient

View File

@ -56,8 +56,11 @@ eg "$sort":
... {"$group": {"_id": "$tags", "count": {"$sum": 1}}},
... {"$sort": SON([("count", -1), ("_id", -1)])}
... ]
>>> list(db.things.aggregate(pipeline))
[{u'count': 3, u'_id': u'cat'}, {u'count': 2, u'_id': u'dog'}, {u'count': 1, u'_id': u'mouse'}]
>>> import pprint
>>> pprint.pprint(list(db.things.aggregate(pipeline)))
[{u'_id': u'cat', u'count': 3},
{u'_id': u'dog', u'count': 2},
{u'_id': u'mouse', u'count': 1}]
To run an explain plan for this aggregation use the
:meth:`~pymongo.database.Database.command` method::
@ -118,7 +121,7 @@ iterate over the result collection:
>>> result = db.things.map_reduce(mapper, reducer, "myresults")
>>> for doc in result.find():
... print doc
... pprint.pprint(doc)
...
{u'_id': u'cat', u'value': 3.0}
{u'_id': u'dog', u'value': 2.0}
@ -135,8 +138,12 @@ response to the map/reduce command, rather than just the result collection:
.. doctest::
>>> db.things.map_reduce(mapper, reducer, "myresults", full_response=True)
{u'counts': {u'input': 4, u'reduce': 2, u'emit': 6, u'output': 3}, u'timeMillis': ..., u'ok': ..., u'result': u'...'}
>>> pprint.pprint(
... db.things.map_reduce(mapper, reducer, "myresults", full_response=True))
{u'counts': {u'emit': 6, u'input': 4, u'output': 3, u'reduce': 2},
u'ok': ...,
u'result': u'...',
u'timeMillis': ...}
All of the optional map/reduce parameters are also supported, simply pass them
as keyword arguments. In this example we use the `query` parameter to limit the
@ -144,9 +151,10 @@ documents that will be mapped over:
.. doctest::
>>> result = db.things.map_reduce(mapper, reducer, "myresults", query={"x": {"$lt": 2}})
>>> for doc in result.find():
... print doc
>>> results = db.things.map_reduce(
... mapper, reducer, "myresults", query={"x": {"$lt": 2}})
>>> for doc in results.find():
... pprint.pprint(doc)
...
{u'_id': u'cat', u'value': 1.0}
{u'_id': u'dog', u'value': 1.0}
@ -157,8 +165,16 @@ specify a different database to store the result collection:
.. doctest::
>>> from bson.son import SON
>>> db.things.map_reduce(mapper, reducer, out=SON([("replace", "results"), ("db", "outdb")]), full_response=True)
{u'counts': {u'input': 4, u'reduce': 2, u'emit': 6, u'output': 3}, u'timeMillis': ..., u'ok': ..., u'result': {u'db': ..., u'collection': ...}}
>>> pprint.pprint(
... db.things.map_reduce(
... mapper,
... reducer,
... out=SON([("replace", "results"), ("db", "outdb")]),
... full_response=True))
{u'counts': {u'emit': 6, u'input': 4, u'output': 3, u'reduce': 2},
u'ok': ...,
u'result': {u'collection': ..., u'db': ...},
u'timeMillis': ...}
.. seealso:: The full list of options for MongoDB's `map reduce engine <http://www.mongodb.org/display/DOCS/MapReduce>`_
@ -186,7 +202,7 @@ Here we are doing a simple group and count of the occurrences of ``x`` values:
...
>>> results = db.things.group(key={"x":1}, condition={}, initial={"count": 0}, reduce=reducer)
>>> for doc in results:
... print doc
... pprint.pprint(doc)
{u'count': 1.0, u'x': 1.0}
{u'count': 2.0, u'x': 2.0}
{u'count': 1.0, u'x': 3.0}

View File

@ -27,7 +27,7 @@ bulk insert operations.
>>> import pymongo
>>> db = pymongo.MongoClient().bulk_example
>>> db.test.insert_many([{'i': i} for i in xrange(10000)]).inserted_ids
>>> db.test.insert_many([{'i': i} for i in range(10000)]).inserted_ids
[...]
>>> db.test.count()
10000
@ -51,6 +51,7 @@ order provided for serial execution. The return value is a document
describing the type and count of operations performed.
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> from pprint import pprint
>>>
@ -88,6 +89,7 @@ occurred and details about the failure - including the operation that caused
the failure.
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> from pymongo.errors import BulkWriteError
>>> bulk = db.test.initialize_ordered_bulk_op()
@ -99,7 +101,7 @@ the failure.
>>> try:
... bulk.execute()
... except BulkWriteError as bwe:
... pprint(bwe.details) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
... pprint(bwe.details)
...
{'nInserted': 0,
'nMatched': 1,
@ -127,6 +129,7 @@ constraint on _id. Since we are doing unordered execution the second
and fourth operations succeed.
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> bulk = db.test.initialize_unordered_bulk_op()
>>> bulk.insert({'_id': 1})
@ -136,7 +139,7 @@ and fourth operations succeed.
>>> try:
... bulk.execute()
... except BulkWriteError as bwe:
... pprint(bwe.details) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
... pprint(bwe.details)
...
{'nInserted': 0,
'nMatched': 1,
@ -165,6 +168,7 @@ errors (e.g. wtimeout) will be reported after all operations are attempted,
regardless of execution order.
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> bulk = db.test.initialize_ordered_bulk_op()
>>> bulk.insert({'a': 0})

View File

@ -88,10 +88,12 @@ use them with PyMongo:
.. doctest::
>>> import pprint
>>> db.test.insert({"custom": encode_custom(Custom(5))})
ObjectId('...')
>>> db.test.find_one()
{u'_id': ObjectId('...'), u'custom': {u'x': 5, u'_type': u'custom'}}
>>> pprint.pprint(db.test.find_one())
{u'_id': ObjectId('...'),
u'custom': {u'_type': u'custom', u'x': 5}}
>>> decode_custom(db.test.find_one()["custom"])
<Custom object at ...>
>>> decode_custom(db.test.find_one()["custom"]).x()
@ -142,8 +144,9 @@ After doing so we can save and restore :class:`Custom` instances seamlessly:
{...}
>>> db.test.insert({"custom": Custom(5)})
ObjectId('...')
>>> db.test.find_one()
{u'_id': ObjectId('...'), u'custom': <Custom object at ...>}
>>> pprint.pprint(db.test.find_one())
{u'_id': ObjectId('...'),
u'custom': <Custom object at ...>}
>>> db.test.find_one()["custom"].x()
5
@ -159,8 +162,9 @@ This allows us to see what was actually saved to the database:
.. doctest::
>>> db.test.find_one()
{u'_id': ObjectId('...'), u'custom': {u'x': 5, u'_type': u'custom'}}
>>> pprint.pprint(db.test.find_one())
{u'_id': ObjectId('...'),
u'custom': {u'_type': u'custom', u'x': 5}}
which is the same format that we encode to with our
:meth:`encode_custom` method!
@ -183,7 +187,7 @@ from :class:`~bson.binary.Binary` instances:
>>> from bson.binary import Binary
>>> def to_binary(custom):
... return Binary(str(custom.x()), 128)
... return Binary(str(custom.x()).encode(), 128)
...
>>> def from_binary(binary):
... return Custom(int(binary))
@ -229,8 +233,9 @@ seamlessly:
>>> db.test.insert({"custom": Custom(5)})
ObjectId('...')
>>> db.test.find_one()
{u'_id': ObjectId('...'), u'custom': <Custom object at ...>}
>>> pprint.pprint(db.test.find_one())
{u'_id': ObjectId('...'),
u'custom': <Custom object at ...>}
>>> db.test.find_one()["custom"].x()
5
@ -242,5 +247,5 @@ clearing out the manipulators and repeating our
.. doctest::
>>> db = client.custom_type_example
>>> db.test.find_one()
>>> pprint.pprint(db.test.find_one())
{u'_id': ObjectId('...'), u'custom': Binary('5', 128)}

View File

@ -47,12 +47,13 @@ Using the geospatial index we can find documents near another point:
.. doctest::
>>> import pprint
>>> for doc in db.places.find({"loc": {"$near": [3, 6]}}).limit(3):
... repr(doc) # doctest: +ELLIPSIS
... pprint.pprint(doc)
...
"{u'loc': [2, 5], u'_id': ObjectId('...')}"
"{u'loc': [4, 4], u'_id': ObjectId('...')}"
"{u'loc': [1, 2], u'_id': ObjectId('...')}"
{u'_id': ObjectId('...'), u'loc': [2, 5]}
{u'_id': ObjectId('...'), u'loc': [4, 4]}
{u'_id': ObjectId('...'), u'loc': [1, 2]}
The $maxDistance operator requires the use of :class:`~bson.son.SON`:
@ -61,11 +62,11 @@ The $maxDistance operator requires the use of :class:`~bson.son.SON`:
>>> from bson.son import SON
>>> query = {"loc": SON([("$near", [3, 6]), ("$maxDistance", 100)])}
>>> for doc in db.places.find(query).limit(3):
... repr(doc) # doctest: +ELLIPSIS
... pprint.pprint(doc)
...
"{u'loc': [2, 5], u'_id': ObjectId('...')}"
"{u'loc': [4, 4], u'_id': ObjectId('...')}"
"{u'loc': [1, 2], u'_id': ObjectId('...')}"
{u'_id': ObjectId('...'), u'loc': [2, 5]}
{u'_id': ObjectId('...'), u'loc': [4, 4]}
{u'_id': ObjectId('...'), u'loc': [1, 2]}
It's also possible to query for all items within a given rectangle
(specified by lower-left and upper-right coordinates):
@ -74,9 +75,9 @@ It's also possible to query for all items within a given rectangle
>>> query = {"loc": {"$within": {"$box": [[2, 2], [5, 6]]}}}
>>> for doc in db.places.find(query).sort('_id'):
... repr(doc)
"{u'loc': [2, 5], u'_id': ObjectId('...')}"
"{u'loc': [4, 4], u'_id': ObjectId('...')}"
... pprint.pprint(doc)
{u'_id': ObjectId('...'), u'loc': [2, 5]}
{u'_id': ObjectId('...'), u'loc': [4, 4]}
Or circle (specified by center point and radius):
@ -84,11 +85,11 @@ Or circle (specified by center point and radius):
>>> query = {"loc": {"$within": {"$center": [[0, 0], 6]}}}
>>> for doc in db.places.find(query).sort('_id'):
... repr(doc) # doctest: +ELLIPSIS
... pprint.pprint(doc)
...
"{u'loc': [2, 5], u'_id': ObjectId('...')}"
"{u'loc': [1, 2], u'_id': ObjectId('...')}"
"{u'loc': [4, 4], u'_id': ObjectId('...')}"
{u'_id': ObjectId('...'), u'loc': [2, 5]}
{u'_id': ObjectId('...'), u'loc': [1, 2]}
{u'_id': ObjectId('...'), u'loc': [4, 4]}
geoNear queries are also supported using :class:`~bson.son.SON`::

View File

@ -42,7 +42,7 @@ interface (the :meth:`~gridfs.GridFS.put` and
.. doctest::
>>> a = fs.put("hello world")
>>> a = fs.put(b"hello world")
:meth:`~gridfs.GridFS.put` creates a new file in GridFS, and returns
the value of the file document's ``"_id"`` key. Given that ``"_id"``

View File

@ -214,19 +214,15 @@ PyMongo represents BSON documents as Python dicts by default, and the order
of keys in dicts is not defined. That is, a dict declared with the "a" key
first is the same, to Python, as one with "b" first:
.. doctest:: key-order
>>> print {'a': 1.0, 'b': 1.0}
>>> print({'a': 1.0, 'b': 1.0})
{'a': 1.0, 'b': 1.0}
>>> print {'b': 1.0, 'a': 1.0}
>>> print({'b': 1.0, 'a': 1.0})
{'a': 1.0, 'b': 1.0}
Therefore, Python dicts are not guaranteed to show keys in the order they are
stored in BSON. Here, "a" is shown before "b":
.. doctest:: key-order
>>> print collection.find_one()
>>> print(collection.find_one())
{u'_id': 1.0, u'subdocument': {u'a': 1.0, u'b': 1.0}}
To preserve order when reading BSON, use the :class:`~bson.son.SON` class,
@ -234,10 +230,11 @@ which is a dict that remembers its key order. First, get a handle to the
collection, configured to use :class:`~bson.son.SON` instead of dict:
.. doctest:: key-order
:options: +NORMALIZE_WHITESPACE
>>> from bson import CodecOptions, SON
>>> opts = CodecOptions(document_class=SON)
>>> opts # doctest: +NORMALIZE_WHITESPACE
>>> opts
CodecOptions(document_class=<class 'bson.son.SON'>,
tz_aware=False,
uuid_representation=PYTHON_LEGACY,
@ -250,7 +247,7 @@ Now, documents and subdocuments in query results are represented with
.. doctest:: key-order
>>> print collection_son.find_one()
>>> print(collection_son.find_one())
SON([(u'_id', 1.0), (u'subdocument', SON([(u'b', 1.0), (u'a', 1.0)]))])
The subdocument's actual storage layout is now visible: "b" is before "a".
@ -260,15 +257,11 @@ serialized **to** BSON. But MongoDB considers subdocuments equal only if their
keys have the same order. So if you use a dict to query on a subdocument it may
not match:
.. doctest:: key-order
>>> collection.find_one({'subdocument': {'a': 1.0, 'b': 1.0}}) is None
True
Swapping the key order in your query makes no difference:
.. doctest:: key-order
>>> collection.find_one({'subdocument': {'b': 1.0, 'a': 1.0}}) is None
True
@ -276,8 +269,6 @@ Swapping the key order in your query makes no difference:
There are two solutions. First, you can match the subdocument field-by-field:
.. doctest:: key-order
>>> collection.find_one({'subdocument.a': 1.0,
... 'subdocument.b': 1.0})
{u'_id': 1.0, u'subdocument': {u'a': 1.0, u'b': 1.0}}
@ -289,8 +280,6 @@ keys besides "a" and "b", whereas the previous query required an exact match.
The second solution is to use a :class:`~bson.son.SON` to specify the key order:
.. doctest:: key-order
>>> query = {'subdocument': SON([('b', 1.0), ('a', 1.0)])}
>>> collection.find_one(query)
{u'_id': 1.0, u'subdocument': {u'a': 1.0, u'b': 1.0}}

View File

@ -157,8 +157,13 @@ document from the posts collection:
.. doctest::
>>> posts.find_one()
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}
>>> import pprint
>>> pprint.pprint(posts.find_one())
{u'_id': ObjectId('...'),
u'author': u'Mike',
u'date': datetime.datetime(...),
u'tags': [u'mongodb', u'python', u'pymongo'],
u'text': u'My first blog post!'}
The result is a dictionary matching the one that we inserted previously.
@ -171,8 +176,12 @@ our results to a document with author "Mike" we do:
.. doctest::
>>> posts.find_one({"author": "Mike"})
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}
>>> pprint.pprint(posts.find_one({"author": "Mike"}))
{u'_id': ObjectId('...'),
u'author': u'Mike',
u'date': datetime.datetime(...),
u'tags': [u'mongodb', u'python', u'pymongo'],
u'text': u'My first blog post!'}
If we try with a different author, like "Eliot", we'll get no result:
@ -191,8 +200,12 @@ We can also find a post by its ``_id``, which in our example is an ObjectId:
>>> post_id
ObjectId(...)
>>> posts.find_one({"_id": post_id})
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}
>>> pprint.pprint(posts.find_one({"_id": post_id}))
{u'_id': ObjectId('...'),
u'author': u'Mike',
u'date': datetime.datetime(...),
u'tags': [u'mongodb', u'python', u'pymongo'],
u'text': u'My first blog post!'}
Note that an ObjectId is not the same as its string representation:
@ -278,11 +291,23 @@ document in the ``posts`` collection:
.. doctest::
>>> for post in posts.find():
... post
... pprint.pprint(post)
...
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}
{u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'bulk', u'insert']}
{u'date': datetime.datetime(2009, 11, 10, 10, 45), u'text': u'and pretty easy too!', u'_id': ObjectId('...'), u'author': u'Eliot', u'title': u'MongoDB is fun'}
{u'_id': ObjectId('...'),
u'author': u'Mike',
u'date': datetime.datetime(...),
u'tags': [u'mongodb', u'python', u'pymongo'],
u'text': u'My first blog post!'}
{u'_id': ObjectId('...'),
u'author': u'Mike',
u'date': datetime.datetime(...),
u'tags': [u'bulk', u'insert'],
u'text': u'Another post!'}
{u'_id': ObjectId('...'),
u'author': u'Eliot',
u'date': datetime.datetime(...),
u'text': u'and pretty easy too!',
u'title': u'MongoDB is fun'}
Just like we did with :meth:`~pymongo.collection.Collection.find_one`,
we can pass a document to :meth:`~pymongo.collection.Collection.find`
@ -292,10 +317,18 @@ author is "Mike":
.. doctest::
>>> for post in posts.find({"author": "Mike"}):
... post
... pprint.pprint(post)
...
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}
{u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'bulk', u'insert']}
{u'_id': ObjectId('...'),
u'author': u'Mike',
u'date': datetime.datetime(...),
u'tags': [u'mongodb', u'python', u'pymongo'],
u'text': u'My first blog post!'}
{u'_id': ObjectId('...'),
u'author': u'Mike',
u'date': datetime.datetime(...),
u'tags': [u'bulk', u'insert'],
u'text': u'Another post!'}
Counting
--------
@ -327,10 +360,18 @@ than a certain date, but also sort the results by author:
>>> d = datetime.datetime(2009, 11, 12, 12)
>>> for post in posts.find({"date": {"$lt": d}}).sort("author"):
... print post
... pprint.pprint(post)
...
{u'date': datetime.datetime(2009, 11, 10, 10, 45), u'text': u'and pretty easy too!', u'_id': ObjectId('...'), u'author': u'Eliot', u'title': u'MongoDB is fun'}
{u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'bulk', u'insert']}
{u'_id': ObjectId('...'),
u'author': u'Eliot',
u'date': datetime.datetime(...),
u'text': u'and pretty easy too!',
u'title': u'MongoDB is fun'}
{u'_id': ObjectId('...'),
u'author': u'Mike',
u'date': datetime.datetime(...),
u'tags': [u'bulk', u'insert'],
u'text': u'Another post!'}
Here we use the special ``"$lt"`` operator to do a range query, and
also call :meth:`~pymongo.cursor.Cursor.sort` to sort the results
@ -351,8 +392,8 @@ First, we'll need to create the index:
>>> result = db.profiles.create_index([('user_id', pymongo.ASCENDING)],
... unique=True)
>>> list(db.profiles.index_information())
[u'user_id_1', u'_id_']
>>> sorted(list(db.profiles.index_information()))
[u'_id_', u'user_id_1']
Notice that we have two indexes now: one is the index on ``_id`` that MongoDB
creates automatically, and the other is the index on ``user_id`` we just

View File

@ -26,9 +26,9 @@ access:
>>> from pymongo import MongoClient
>>> c = MongoClient()
>>> c.test_database
Database(MongoClient('localhost', 27017), u'test_database')
Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), u'test_database')
>>> c['test-database']
Database(MongoClient('localhost', 27017), u'test-database')
Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), u'test-database')
"""
import contextlib

View File

@ -1,7 +1,6 @@
import os
import platform
import re
import subprocess
import sys
import warnings
@ -26,6 +25,12 @@ from distutils.errors import CCompilerError, DistutilsOptionError
from distutils.errors import DistutilsPlatformError, DistutilsExecError
from distutils.core import Extension
try:
import sphinx
_HAVE_SPHINX = True
except ImportError:
_HAVE_SPHINX = False
version = "3.4rc1.dev0"
f = open("README.rst")
@ -125,6 +130,54 @@ class doc(Command):
pass
def run(self):
if not _HAVE_SPHINX:
raise RuntimeError(
"You must install Sphinx to build or test the documentation.")
if sys.version_info[0] >= 3:
import doctest
from doctest import OutputChecker as _OutputChecker
# Match u or U (possibly followed by r or R), removing it.
# r/R can follow u/U but not precede it. Don't match the
# single character string 'u' or 'U'.
_u_literal_re = re.compile(
r"(\W|^)(?<![\'\"])[uU]([rR]?[\'\"])", re.UNICODE)
# Match b or B (possibly followed by r or R), removing.
# r/R can follow b/B but not precede it. Don't match the
# single character string 'b' or 'B'.
_b_literal_re = re.compile(
r"(\W|^)(?<![\'\"])[bB]([rR]?[\'\"])", re.UNICODE)
class _StringPrefixFixer(_OutputChecker):
def check_output(self, want, got, optionflags):
if sys.version_info[0] >= 3:
# The docstrings are written with python 2.x in mind.
# To make the doctests pass in python 3 we have to
# strip the 'u' prefix from the expected results. The
# actual results won't have that prefix.
want = re.sub(_u_literal_re, r'\1\2', want)
# We also have to strip the 'b' prefix from the actual
# results since python 2.x expected results won't have
# that prefix.
got = re.sub(_b_literal_re, r'\1\2', got)
return super(
_StringPrefixFixer, self).check_output(
want, got, optionflags)
def output_difference(self, example, got, optionflags):
if sys.version_info[0] >= 3:
example.want = re.sub(
_u_literal_re, r'\1\2', example.want)
got = re.sub(_b_literal_re, r'\1\2', got)
return super(
_StringPrefixFixer, self).output_difference(
example, got, optionflags)
doctest.OutputChecker = _StringPrefixFixer
if self.test:
path = "doc/_build/doctest"
mode = "doctest"
@ -137,8 +190,7 @@ class doc(Command):
except:
pass
status = subprocess.call(["sphinx-build", "-E",
"-b", mode, "doc", path])
status = sphinx.build_main(["-E", "-b", mode, "doc", path])
if status:
raise RuntimeError("documentation step '%s' failed" % (mode,))