Merge lp:~jml/launchpad/prevent-new-sphinx-errors into lp:launchpad

Proposed by Jonathan Lange
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 12442
Proposed branch: lp:~jml/launchpad/prevent-new-sphinx-errors
Merge into: lp:launchpad
Diff against target: 215 lines (+98/-1)
7 files modified
doc/Makefile (+1/-1)
lib/lp/scripts/tests/test_sphinxdocs.py (+35/-0)
lib/lp/services/tests/test_utils.py (+16/-0)
lib/lp/services/utils.py (+35/-0)
lib/lp_sitecustomize.py (+7/-0)
setup.py (+1/-0)
versions.cfg (+3/-0)
To merge this branch: bzr merge lp:~jml/launchpad/prevent-new-sphinx-errors
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
j.c.sackett (community) code* Approve
Review via email: mp+50136@code.launchpad.net

Commit message

[r=jcsackett,sinzui][no-qa] Add a test to prevent new Sphinx errors

Description of the change

This branch adds a test that prevents new sphinx doc build errors.

It does the equivalent of running 'sphinx-build', but imports the sphinx command and runs it in process to save a little time (1-2s).

Also added a run_capturing_output helper, because I can't believe we don't already have one.

Oh, also adds Sphinx as a dependency. I had thought of making the test optional, but Benji convinced me that it's not an onerous dependency, and it's good to have new developers able to build the documentation. The lp_sitecustomize thing is to silence a silly warning in pygments.

To post a comment you must log in.
Revision history for this message
j.c.sackett (jcsackett) wrote :

This looks good to land. Tests confirming documentation isn't broken is a great idea, and the output capturing tool is handy.

review: Approve (code*)
Revision history for this message
Curtis Hovey (sinzui) wrote :

This looks good to land.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'doc/Makefile'
--- doc/Makefile 2011-02-03 16:06:24 +0000
+++ doc/Makefile 2011-02-20 13:31:11 +0000
@@ -2,7 +2,7 @@
2#2#
33
4# You can set these variables from the command line.4# You can set these variables from the command line.
5SPHINXOPTS =5SPHINXOPTS = -Nq
6SPHINXBUILD = sphinx-build6SPHINXBUILD = sphinx-build
7PAPER =7PAPER =
8BUILDDIR = _build8BUILDDIR = _build
99
=== added file 'lib/lp/scripts/tests/test_sphinxdocs.py'
--- lib/lp/scripts/tests/test_sphinxdocs.py 1970-01-01 00:00:00 +0000
+++ lib/lp/scripts/tests/test_sphinxdocs.py 2011-02-20 13:31:11 +0000
@@ -0,0 +1,35 @@
1# Copyright 2011 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for our Sphinx documentation."""
5
6__metaclass__ = type
7
8import os
9
10import sphinx
11
12from canonical.config import config
13from lp.services.utils import run_capturing_output
14from lp.testing import TestCase
15
16
17class TestSphinxDocumentation(TestCase):
18 """Is our Sphinx documentation building correctly?"""
19
20 def test_docs_build_without_error(self):
21 # The Sphinx documentation must build without errors or warnings.
22 #
23 # Note that the documents are built on devpad.canonical.com in a
24 # cronscript that runs 'make -C doc html' in the Launchpad tree. This
25 # test assumes that make command devolves into 'sphinx-build ...',
26 # because running make commands from tests seems distasteful.
27 output_dir = self.makeTemporaryDirectory()
28 doc_dir = os.path.join(config.root, 'doc')
29 returncode, stdout, stderr = run_capturing_output(
30 sphinx.main,
31 ['sphinx-build', '-d', '%s/doctrees' % output_dir,
32 '-aNq', doc_dir, '%s/html' % output_dir])
33 self.assertEqual(0, returncode)
34 self.assertEqual('Making output directory...\n', stderr)
35 self.assertEqual('', stdout)
036
=== modified file 'lib/lp/services/tests/test_utils.py'
--- lib/lp/services/tests/test_utils.py 2011-02-17 18:29:45 +0000
+++ lib/lp/services/tests/test_utils.py 2011-02-20 13:31:11 +0000
@@ -8,6 +8,7 @@
8from contextlib import contextmanager8from contextlib import contextmanager
9import hashlib9import hashlib
10import itertools10import itertools
11import sys
11import unittest12import unittest
1213
13from lp.services.utils import (14from lp.services.utils import (
@@ -18,6 +19,7 @@
18 decorate_with,19 decorate_with,
19 docstring_dedent,20 docstring_dedent,
20 iter_split,21 iter_split,
22 run_capturing_output,
21 traceback_info,23 traceback_info,
22 )24 )
23from lp.testing import TestCase25from lp.testing import TestCase
@@ -252,5 +254,19 @@
252 self.assertEqual("Pugwash", locals().get("__traceback_info__"))254 self.assertEqual("Pugwash", locals().get("__traceback_info__"))
253255
254256
257class TestRunCapturingOutput(TestCase):
258 """Test `run_capturing_output`."""
259
260 def test_run_capturing_output(self):
261 def f(a, b):
262 sys.stdout.write(str(a))
263 sys.stderr.write(str(b))
264 return a + b
265 c, stdout, stderr = run_capturing_output(f, 3, 4)
266 self.assertEqual(7, c)
267 self.assertEqual('3', stdout)
268 self.assertEqual('4', stderr)
269
270
255def test_suite():271def test_suite():
256 return unittest.TestLoader().loadTestsFromName(__name__)272 return unittest.TestLoader().loadTestsFromName(__name__)
257273
=== modified file 'lib/lp/services/utils.py'
--- lib/lp/services/utils.py 2011-02-17 18:29:45 +0000
+++ lib/lp/services/utils.py 2011-02-20 13:31:11 +0000
@@ -16,6 +16,7 @@
16 'decorate_with',16 'decorate_with',
17 'docstring_dedent',17 'docstring_dedent',
18 'iter_split',18 'iter_split',
19 'run_capturing_output',
19 'synchronize',20 'synchronize',
20 'text_delta',21 'text_delta',
21 'traceback_info',22 'traceback_info',
@@ -23,11 +24,16 @@
23 ]24 ]
2425
25from itertools import tee26from itertools import tee
27from StringIO import StringIO
26import string28import string
27import sys29import sys
28from textwrap import dedent30from textwrap import dedent
29from types import FunctionType31from types import FunctionType
3032
33from fixtures import (
34 Fixture,
35 MonkeyPatch,
36 )
31from lazr.enum import BaseItem37from lazr.enum import BaseItem
32from twisted.python.util import mergeFunctionMetadata38from twisted.python.util import mergeFunctionMetadata
33from zope.security.proxy import isinstance as zope_isinstance39from zope.security.proxy import isinstance as zope_isinstance
@@ -220,6 +226,35 @@
220 return (first + '\n' + dedent(rest)).strip()226 return (first + '\n' + dedent(rest)).strip()
221227
222228
229class CapturedOutput(Fixture):
230 """A fixture that captures output to stdout and stderr."""
231
232 def __init__(self):
233 super(CapturedOutput, self).__init__()
234 self.stdout = StringIO()
235 self.stderr = StringIO()
236
237 def setUp(self):
238 super(CapturedOutput, self).setUp()
239 self.useFixture(MonkeyPatch('sys.stdout', self.stdout))
240 self.useFixture(MonkeyPatch('sys.stderr', self.stderr))
241
242
243def run_capturing_output(function, *args, **kwargs):
244 """Run ``function`` capturing output to stdout and stderr.
245
246 :param function: A function to run.
247 :param args: Arguments passed to the function.
248 :param kwargs: Keyword arguments passed to the function.
249 :return: A tuple of ``(ret, stdout, stderr)``, where ``ret`` is the value
250 returned by ``function``, ``stdout`` is the captured standard output
251 and ``stderr`` is the captured stderr.
252 """
253 with CapturedOutput() as captured:
254 ret = function(*args, **kwargs)
255 return ret, captured.stdout.getvalue(), captured.stderr.getvalue()
256
257
223def traceback_info(info):258def traceback_info(info):
224 """Set `__traceback_info__` in the caller's locals.259 """Set `__traceback_info__` in the caller's locals.
225260
226261
=== modified file 'lib/lp_sitecustomize.py'
--- lib/lp_sitecustomize.py 2011-02-17 18:29:45 +0000
+++ lib/lp_sitecustomize.py 2011-02-20 13:31:11 +0000
@@ -102,6 +102,13 @@
102 warnings.filterwarnings(102 warnings.filterwarnings(
103 'ignore', '.*apt_pkg.*', category=DeprecationWarning)103 'ignore', '.*apt_pkg.*', category=DeprecationWarning)
104104
105 # pygments-0.8 on Python 2.6:
106 # DeprecationWarning: object.__init__() takes no parameters
107 warnings.filterwarnings(
108 'ignore',
109 category=DeprecationWarning,
110 module='pygments')
111
105112
106def customize_logger():113def customize_logger():
107 """Customize the logging system.114 """Customize the logging system.
108115
=== modified file 'setup.py'
--- setup.py 2011-01-06 22:21:02 +0000
+++ setup.py 2011-02-20 13:31:11 +0000
@@ -68,6 +68,7 @@
68 'RestrictedPython',68 'RestrictedPython',
69 'setproctitle',69 'setproctitle',
70 'setuptools',70 'setuptools',
71 'Sphinx',
71 'soupmatchers',72 'soupmatchers',
72 'sourcecodegen',73 'sourcecodegen',
73 'storm',74 'storm',
7475
=== modified file 'versions.cfg'
--- versions.cfg 2011-02-17 01:41:03 +0000
+++ versions.cfg 2011-02-20 13:31:11 +0000
@@ -25,6 +25,7 @@
25grokcore.component = 1.625grokcore.component = 1.6
26httplib2 = 0.6.026httplib2 = 0.6.0
27ipython = 0.9.127ipython = 0.9.1
28Jinja2 = 2.2
28keyring = 0.5.129keyring = 0.5.1
29launchpadlib = 1.9.330launchpadlib = 1.9.3
30lazr.authentication = 0.1.131lazr.authentication = 0.1.1
@@ -54,6 +55,7 @@
54pyasn1 = 0.0.9a55pyasn1 = 0.0.9a
55pycrypto = 2.0.156pycrypto = 2.0.1
56pydkim = 0.3-mbp-r757pydkim = 0.3-mbp-r7
58Pygments = 0.8
57pyOpenSSL = 0.1059pyOpenSSL = 0.10
58python-memcached = 1.4560python-memcached = 1.45
59# 2.2.1 with the one-liner Expect: 100-continue fix from61# 2.2.1 with the one-liner Expect: 100-continue fix from
@@ -67,6 +69,7 @@
67simplejson = 2.0.969simplejson = 2.0.9
68simplesettings = 0.470simplesettings = 0.4
69SimpleTal = 4.171SimpleTal = 4.1
72Sphinx = 1.0.7
70soupmatchers = 0.1r5373soupmatchers = 0.1r53
71sourcecodegen = 0.6.974sourcecodegen = 0.6.9
72storm = 0.1875storm = 0.18