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
1=== modified file 'doc/Makefile'
2--- doc/Makefile 2011-02-03 16:06:24 +0000
3+++ doc/Makefile 2011-02-20 13:31:11 +0000
4@@ -2,7 +2,7 @@
5 #
6
7 # You can set these variables from the command line.
8-SPHINXOPTS =
9+SPHINXOPTS = -Nq
10 SPHINXBUILD = sphinx-build
11 PAPER =
12 BUILDDIR = _build
13
14=== added file 'lib/lp/scripts/tests/test_sphinxdocs.py'
15--- lib/lp/scripts/tests/test_sphinxdocs.py 1970-01-01 00:00:00 +0000
16+++ lib/lp/scripts/tests/test_sphinxdocs.py 2011-02-20 13:31:11 +0000
17@@ -0,0 +1,35 @@
18+# Copyright 2011 Canonical Ltd. This software is licensed under the
19+# GNU Affero General Public License version 3 (see the file LICENSE).
20+
21+"""Tests for our Sphinx documentation."""
22+
23+__metaclass__ = type
24+
25+import os
26+
27+import sphinx
28+
29+from canonical.config import config
30+from lp.services.utils import run_capturing_output
31+from lp.testing import TestCase
32+
33+
34+class TestSphinxDocumentation(TestCase):
35+ """Is our Sphinx documentation building correctly?"""
36+
37+ def test_docs_build_without_error(self):
38+ # The Sphinx documentation must build without errors or warnings.
39+ #
40+ # Note that the documents are built on devpad.canonical.com in a
41+ # cronscript that runs 'make -C doc html' in the Launchpad tree. This
42+ # test assumes that make command devolves into 'sphinx-build ...',
43+ # because running make commands from tests seems distasteful.
44+ output_dir = self.makeTemporaryDirectory()
45+ doc_dir = os.path.join(config.root, 'doc')
46+ returncode, stdout, stderr = run_capturing_output(
47+ sphinx.main,
48+ ['sphinx-build', '-d', '%s/doctrees' % output_dir,
49+ '-aNq', doc_dir, '%s/html' % output_dir])
50+ self.assertEqual(0, returncode)
51+ self.assertEqual('Making output directory...\n', stderr)
52+ self.assertEqual('', stdout)
53
54=== modified file 'lib/lp/services/tests/test_utils.py'
55--- lib/lp/services/tests/test_utils.py 2011-02-17 18:29:45 +0000
56+++ lib/lp/services/tests/test_utils.py 2011-02-20 13:31:11 +0000
57@@ -8,6 +8,7 @@
58 from contextlib import contextmanager
59 import hashlib
60 import itertools
61+import sys
62 import unittest
63
64 from lp.services.utils import (
65@@ -18,6 +19,7 @@
66 decorate_with,
67 docstring_dedent,
68 iter_split,
69+ run_capturing_output,
70 traceback_info,
71 )
72 from lp.testing import TestCase
73@@ -252,5 +254,19 @@
74 self.assertEqual("Pugwash", locals().get("__traceback_info__"))
75
76
77+class TestRunCapturingOutput(TestCase):
78+ """Test `run_capturing_output`."""
79+
80+ def test_run_capturing_output(self):
81+ def f(a, b):
82+ sys.stdout.write(str(a))
83+ sys.stderr.write(str(b))
84+ return a + b
85+ c, stdout, stderr = run_capturing_output(f, 3, 4)
86+ self.assertEqual(7, c)
87+ self.assertEqual('3', stdout)
88+ self.assertEqual('4', stderr)
89+
90+
91 def test_suite():
92 return unittest.TestLoader().loadTestsFromName(__name__)
93
94=== modified file 'lib/lp/services/utils.py'
95--- lib/lp/services/utils.py 2011-02-17 18:29:45 +0000
96+++ lib/lp/services/utils.py 2011-02-20 13:31:11 +0000
97@@ -16,6 +16,7 @@
98 'decorate_with',
99 'docstring_dedent',
100 'iter_split',
101+ 'run_capturing_output',
102 'synchronize',
103 'text_delta',
104 'traceback_info',
105@@ -23,11 +24,16 @@
106 ]
107
108 from itertools import tee
109+from StringIO import StringIO
110 import string
111 import sys
112 from textwrap import dedent
113 from types import FunctionType
114
115+from fixtures import (
116+ Fixture,
117+ MonkeyPatch,
118+ )
119 from lazr.enum import BaseItem
120 from twisted.python.util import mergeFunctionMetadata
121 from zope.security.proxy import isinstance as zope_isinstance
122@@ -220,6 +226,35 @@
123 return (first + '\n' + dedent(rest)).strip()
124
125
126+class CapturedOutput(Fixture):
127+ """A fixture that captures output to stdout and stderr."""
128+
129+ def __init__(self):
130+ super(CapturedOutput, self).__init__()
131+ self.stdout = StringIO()
132+ self.stderr = StringIO()
133+
134+ def setUp(self):
135+ super(CapturedOutput, self).setUp()
136+ self.useFixture(MonkeyPatch('sys.stdout', self.stdout))
137+ self.useFixture(MonkeyPatch('sys.stderr', self.stderr))
138+
139+
140+def run_capturing_output(function, *args, **kwargs):
141+ """Run ``function`` capturing output to stdout and stderr.
142+
143+ :param function: A function to run.
144+ :param args: Arguments passed to the function.
145+ :param kwargs: Keyword arguments passed to the function.
146+ :return: A tuple of ``(ret, stdout, stderr)``, where ``ret`` is the value
147+ returned by ``function``, ``stdout`` is the captured standard output
148+ and ``stderr`` is the captured stderr.
149+ """
150+ with CapturedOutput() as captured:
151+ ret = function(*args, **kwargs)
152+ return ret, captured.stdout.getvalue(), captured.stderr.getvalue()
153+
154+
155 def traceback_info(info):
156 """Set `__traceback_info__` in the caller's locals.
157
158
159=== modified file 'lib/lp_sitecustomize.py'
160--- lib/lp_sitecustomize.py 2011-02-17 18:29:45 +0000
161+++ lib/lp_sitecustomize.py 2011-02-20 13:31:11 +0000
162@@ -102,6 +102,13 @@
163 warnings.filterwarnings(
164 'ignore', '.*apt_pkg.*', category=DeprecationWarning)
165
166+ # pygments-0.8 on Python 2.6:
167+ # DeprecationWarning: object.__init__() takes no parameters
168+ warnings.filterwarnings(
169+ 'ignore',
170+ category=DeprecationWarning,
171+ module='pygments')
172+
173
174 def customize_logger():
175 """Customize the logging system.
176
177=== modified file 'setup.py'
178--- setup.py 2011-01-06 22:21:02 +0000
179+++ setup.py 2011-02-20 13:31:11 +0000
180@@ -68,6 +68,7 @@
181 'RestrictedPython',
182 'setproctitle',
183 'setuptools',
184+ 'Sphinx',
185 'soupmatchers',
186 'sourcecodegen',
187 'storm',
188
189=== modified file 'versions.cfg'
190--- versions.cfg 2011-02-17 01:41:03 +0000
191+++ versions.cfg 2011-02-20 13:31:11 +0000
192@@ -25,6 +25,7 @@
193 grokcore.component = 1.6
194 httplib2 = 0.6.0
195 ipython = 0.9.1
196+Jinja2 = 2.2
197 keyring = 0.5.1
198 launchpadlib = 1.9.3
199 lazr.authentication = 0.1.1
200@@ -54,6 +55,7 @@
201 pyasn1 = 0.0.9a
202 pycrypto = 2.0.1
203 pydkim = 0.3-mbp-r7
204+Pygments = 0.8
205 pyOpenSSL = 0.10
206 python-memcached = 1.45
207 # 2.2.1 with the one-liner Expect: 100-continue fix from
208@@ -67,6 +69,7 @@
209 simplejson = 2.0.9
210 simplesettings = 0.4
211 SimpleTal = 4.1
212+Sphinx = 1.0.7
213 soupmatchers = 0.1r53
214 sourcecodegen = 0.6.9
215 storm = 0.18