← Back to team overview

launchpad-reviewers team mailing list archive

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

 

Jonathan Lange has proposed merging lp:~jml/launchpad/prevent-new-sphinx-errors into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~jml/launchpad/prevent-new-sphinx-errors/+merge/50136

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.
-- 
https://code.launchpad.net/~jml/launchpad/prevent-new-sphinx-errors/+merge/50136
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jml/launchpad/prevent-new-sphinx-errors into lp:launchpad.
=== modified file 'doc/Makefile'
--- doc/Makefile	2011-02-03 16:06:24 +0000
+++ doc/Makefile	2011-02-17 12:34:57 +0000
@@ -2,7 +2,7 @@
 #
 
 # You can set these variables from the command line.
-SPHINXOPTS    =
+SPHINXOPTS    = -Nq
 SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = _build

=== 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-17 12:34:57 +0000
@@ -0,0 +1,35 @@
+# Copyright 2011 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for our Sphinx documentation."""
+
+__metaclass__ = type
+
+import os
+
+import sphinx
+
+from canonical.config import config
+from lp.services.utils import run_capturing_output
+from lp.testing import TestCase
+
+
+class TestSphinxDocumentation(TestCase):
+    """Is our Sphinx documentation building correctly?"""
+
+    def test_docs_build_without_error(self):
+        # The Sphinx documentation must build without errors or warnings.
+        #
+        # Note that the documents are built on devpad.canonical.com in a
+        # cronscript that runs 'make -C doc html' in the Launchpad tree.  This
+        # test assumes that make command devolves into 'sphinx-build ...',
+        # because running make commands from tests seems distasteful.
+        output_dir = self.makeTemporaryDirectory()
+        doc_dir = os.path.join(config.root, 'doc')
+        returncode, stdout, stderr = run_capturing_output(
+            sphinx.main,
+            ['sphinx-build', '-d', '%s/doctrees' % output_dir,
+             '-aNq', doc_dir, '%s/html' % output_dir])
+        self.assertEqual(0, returncode)
+        self.assertEqual('Making output directory...\n', stderr)
+        self.assertEqual('', stdout)

=== modified file 'lib/lp/services/tests/test_utils.py'
--- lib/lp/services/tests/test_utils.py	2011-02-09 10:59:00 +0000
+++ lib/lp/services/tests/test_utils.py	2011-02-17 12:34:57 +0000
@@ -7,6 +7,7 @@
 
 from contextlib import contextmanager
 import itertools
+import sys
 import unittest
 
 from lp.services.utils import (
@@ -14,6 +15,7 @@
     decorate_with,
     docstring_dedent,
     iter_split,
+    run_capturing_output,
     traceback_info,
     )
 from lp.testing import TestCase
@@ -168,5 +170,19 @@
         self.assertEqual("Pugwash", locals().get("__traceback_info__"))
 
 
+class TestRunCapturingOutput(TestCase):
+    """Test `run_capturing_output`."""
+
+    def test_run_capturing_output(self):
+        def f(a, b):
+            sys.stdout.write(str(a))
+            sys.stderr.write(str(b))
+            return a + b
+        c, stdout, stderr = run_capturing_output(f, 3, 4)
+        self.assertEqual(7, c)
+        self.assertEqual('3', stdout)
+        self.assertEqual('4', stderr)
+
+
 def test_suite():
     return unittest.TestLoader().loadTestsFromName(__name__)

=== modified file 'lib/lp/services/utils.py'
--- lib/lp/services/utils.py	2011-02-08 21:17:56 +0000
+++ lib/lp/services/utils.py	2011-02-17 12:34:57 +0000
@@ -13,6 +13,7 @@
     'decorate_with',
     'docstring_dedent',
     'iter_split',
+    'run_capturing_output',
     'synchronize',
     'text_delta',
     'traceback_info',
@@ -20,9 +21,14 @@
     ]
 
 from itertools import tee
+from StringIO import StringIO
 import sys
 from textwrap import dedent
 
+from fixtures import (
+    Fixture,
+    MonkeyPatch,
+    )
 from lazr.enum import BaseItem
 from twisted.python.util import mergeFunctionMetadata
 from zope.security.proxy import isinstance as zope_isinstance
@@ -154,6 +160,35 @@
     return (first + '\n' + dedent(rest)).strip()
 
 
+class CapturedOutput(Fixture):
+    """A fixture that captures output to stdout and stderr."""
+
+    def __init__(self):
+        super(CapturedOutput, self).__init__()
+        self.stdout = StringIO()
+        self.stderr = StringIO()
+
+    def setUp(self):
+        super(CapturedOutput, self).setUp()
+        self.useFixture(MonkeyPatch('sys.stdout', self.stdout))
+        self.useFixture(MonkeyPatch('sys.stderr', self.stderr))
+
+
+def run_capturing_output(function, *args, **kwargs):
+    """Run ``function`` capturing output to stdout and stderr.
+
+    :param function: A function to run.
+    :param args: Arguments passed to the function.
+    :param kwargs: Keyword arguments passed to the function.
+    :return: A tuple of ``(ret, stdout, stderr)``, where ``ret`` is the value
+        returned by ``function``, ``stdout`` is the captured standard output
+        and ``stderr`` is the captured stderr.
+    """
+    with CapturedOutput() as captured:
+        ret = function(*args, **kwargs)
+    return ret, captured.stdout.getvalue(), captured.stderr.getvalue()
+
+
 def traceback_info(info):
     """Set `__traceback_info__` in the caller's locals.
 

=== modified file 'lib/lp_sitecustomize.py'
--- lib/lp_sitecustomize.py	2010-12-24 13:03:02 +0000
+++ lib/lp_sitecustomize.py	2011-02-17 12:34:57 +0000
@@ -93,6 +93,13 @@
         category=DeprecationWarning,
         module="Crypto")
 
+    # pygments-0.8 on Python 2.6:
+    #   DeprecationWarning: object.__init__() takes no parameters
+    warnings.filterwarnings(
+        'ignore',
+        category=DeprecationWarning,
+        module='pygments')
+
 
 def customize_logger():
     """Customize the logging system.

=== modified file 'setup.py'
--- setup.py	2011-01-06 22:21:02 +0000
+++ setup.py	2011-02-17 12:34:57 +0000
@@ -68,6 +68,7 @@
         'RestrictedPython',
         'setproctitle',
         'setuptools',
+        'Sphinx',
         'soupmatchers',
         'sourcecodegen',
         'storm',

=== modified file 'versions.cfg'
--- versions.cfg	2011-02-11 04:25:27 +0000
+++ versions.cfg	2011-02-17 12:34:57 +0000
@@ -25,6 +25,7 @@
 grokcore.component = 1.6
 httplib2 = 0.6.0
 ipython = 0.9.1
+Jinja2 = 2.2
 keyring = 0.5.1
 launchpadlib = 1.9.3
 lazr.authentication = 0.1.1
@@ -54,6 +55,7 @@
 pyasn1 = 0.0.9a
 pycrypto = 2.0.1
 pydkim = 0.3-mbp-r7
+Pygments = 0.8
 pyOpenSSL = 0.10
 python-memcached = 1.45
 # 2.2.1 with the one-liner Expect: 100-continue fix from
@@ -67,6 +69,7 @@
 simplejson = 2.0.9
 simplesettings = 0.4
 SimpleTal = 4.1
+Sphinx = 1.0.7
 soupmatchers = 0.1r53
 sourcecodegen = 0.6.9
 storm = 0.18


Follow ups