← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:captured-output-is-a-fixture into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:captured-output-is-a-fixture into launchpad:master.

Commit message:
Move CapturedOutput to lp.testing.fixture

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/408505

It's only used in tests, so doesn't belong in `lp.services.utils`.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:captured-output-is-a-fixture into launchpad:master.
diff --git a/lib/lp/archivepublisher/tests/test_copy_signingkeys.py b/lib/lp/archivepublisher/tests/test_copy_signingkeys.py
index d164fba..e821248 100644
--- a/lib/lp/archivepublisher/tests/test_copy_signingkeys.py
+++ b/lib/lp/archivepublisher/tests/test_copy_signingkeys.py
@@ -19,8 +19,8 @@ from lp.services.log.logger import BufferLogger
 from lp.services.scripts.base import LaunchpadScriptFailure
 from lp.services.signing.enums import SigningKeyType
 from lp.services.signing.model.signingkey import ArchiveSigningKey
-from lp.services.utils import CapturedOutput
 from lp.testing import TestCaseWithFactory
+from lp.testing.fixture import CapturedOutput
 from lp.testing.layers import ZopelessDatabaseLayer
 from lp.testing.script import run_script
 
diff --git a/lib/lp/scripts/tests/test_sphinxdocs.py b/lib/lp/scripts/tests/test_sphinxdocs.py
index 30fb601..717167d 100644
--- a/lib/lp/scripts/tests/test_sphinxdocs.py
+++ b/lib/lp/scripts/tests/test_sphinxdocs.py
@@ -1,4 +1,4 @@
-# Copyright 2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2011-2021 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for our Sphinx documentation."""
@@ -11,8 +11,8 @@ from sphinx.cmd.build import main as sphinx_main
 from testtools.content import text_content
 
 from lp.services.config import config
-from lp.services.utils import run_capturing_output
 from lp.testing import TestCase
+from lp.testing.fixture import run_capturing_output
 
 
 class TestSphinxDocumentation(TestCase):
diff --git a/lib/lp/scripts/utilities/tests/test_versioninfo.py b/lib/lp/scripts/utilities/tests/test_versioninfo.py
index a23100c..83e2061 100644
--- a/lib/lp/scripts/utilities/tests/test_versioninfo.py
+++ b/lib/lp/scripts/utilities/tests/test_versioninfo.py
@@ -1,4 +1,4 @@
-# Copyright 2019 Canonical Ltd.  This software is licensed under the
+# Copyright 2019-2021 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test the script to show version information."""
@@ -12,8 +12,8 @@ from testtools.content import text_content
 
 from lp.app import versioninfo
 from lp.scripts.utilities.versioninfo import main as versioninfo_main
-from lp.services.utils import CapturedOutput
 from lp.testing import TestCase
+from lp.testing.fixture import CapturedOutput
 
 
 class TestVersionInfo(TestCase):
diff --git a/lib/lp/services/crypto/scripts/tests/test_generatekeypair.py b/lib/lp/services/crypto/scripts/tests/test_generatekeypair.py
index fc6727c..ae7f443 100644
--- a/lib/lp/services/crypto/scripts/tests/test_generatekeypair.py
+++ b/lib/lp/services/crypto/scripts/tests/test_generatekeypair.py
@@ -1,4 +1,4 @@
-# Copyright 2019 Canonical Ltd.  This software is licensed under the
+# Copyright 2019-2021 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test the script to generate a NaCl key pair."""
@@ -19,8 +19,8 @@ from testtools.matchers import (
     )
 
 from lp.services.crypto.scripts.generatekeypair import main as gkp_main
-from lp.services.utils import CapturedOutput
 from lp.testing import TestCase
+from lp.testing.fixture import CapturedOutput
 
 
 def decode_key(factory, data):
diff --git a/lib/lp/services/tests/test_utils.py b/lib/lp/services/tests/test_utils.py
index d6cb1ec..aae92a6 100644
--- a/lib/lp/services/tests/test_utils.py
+++ b/lib/lp/services/tests/test_utils.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2020 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2021 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for lp.services.utils."""
@@ -10,7 +10,6 @@ from datetime import datetime
 from functools import partial
 import itertools
 import os
-import sys
 
 from fixtures import TempDir
 from pytz import UTC
@@ -33,7 +32,6 @@ from lp.services.utils import (
     load_bz2_pickle,
     obfuscate_structure,
     round_half_up,
-    run_capturing_output,
     sanitise_urls,
     save_bz2_pickle,
     seconds_since_epoch,
@@ -282,22 +280,6 @@ class TestTracebackInfo(TestCase):
         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)
-
-
 class TestFileExists(TestCase):
     """Tests for `file_exists`."""
 
diff --git a/lib/lp/services/utils.py b/lib/lp/services/utils.py
index a8de8e0..2735e93 100644
--- a/lib/lp/services/utils.py
+++ b/lib/lp/services/utils.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2020 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2021 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Generic Python utilities.
@@ -21,7 +21,6 @@ __all__ = [
     'obfuscate_structure',
     're_email_address',
     'round_half_up',
-    'run_capturing_output',
     'sanitise_urls',
     'save_bz2_pickle',
     'seconds_since_epoch',
@@ -44,10 +43,6 @@ import sys
 from textwrap import dedent
 from types import FunctionType
 
-from fixtures import (
-    Fixture,
-    MonkeyPatch,
-    )
 from lazr.enum import BaseItem
 import pytz
 import six
@@ -223,34 +218,6 @@ def file_exists(filename):
     return os.access(filename, os.F_OK)
 
 
-class CapturedOutput(Fixture):
-    """A fixture that captures output to stdout and stderr."""
-
-    def __init__(self):
-        super(CapturedOutput, self).__init__()
-        self.stdout = six.StringIO()
-        self.stderr = six.StringIO()
-
-    def _setUp(self):
-        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.
 
diff --git a/lib/lp/testing/fixture.py b/lib/lp/testing/fixture.py
index 418cc52..873fe35 100644
--- a/lib/lp/testing/fixture.py
+++ b/lib/lp/testing/fixture.py
@@ -1,15 +1,17 @@
-# Copyright 2009-2019 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2021 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Launchpad test fixtures that have no better home."""
 
 __metaclass__ = type
 __all__ = [
+    'CapturedOutput',
     'CaptureOops',
     'DemoMode',
     'DisableTriggerFixture',
     'PGBouncerFixture',
     'PGNotReadyError',
+    'run_capturing_output',
     'ZopeAdapterFixture',
     'ZopeEventHandlerFixture',
     'ZopeUtilityFixture',
@@ -25,11 +27,13 @@ import amqp
 from fixtures import (
     EnvironmentVariableFixture,
     Fixture,
+    MonkeyPatch,
     )
 from lazr.restful.utils import get_current_browser_request
 import oops
 import oops_amqp
 import pgbouncer.fixture
+import six
 from zope.component import (
     adapter,
     getGlobalSiteManager,
@@ -263,6 +267,34 @@ class ZopeUtilityFixture(Fixture):
             self.component, self.intf, self.name)
 
 
+class CapturedOutput(Fixture):
+    """A fixture that captures output to stdout and stderr."""
+
+    def __init__(self):
+        super(CapturedOutput, self).__init__()
+        self.stdout = six.StringIO()
+        self.stderr = six.StringIO()
+
+    def _setUp(self):
+        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()
+
+
 class CaptureOops(Fixture):
     """Capture OOPSes notified via zope event notification.
 
diff --git a/lib/lp/testing/tests/test_fixture.py b/lib/lp/testing/tests/test_fixture.py
index d47d957..16cf3f9 100644
--- a/lib/lp/testing/tests/test_fixture.py
+++ b/lib/lp/testing/tests/test_fixture.py
@@ -39,6 +39,7 @@ from lp.testing.fixture import (
     CaptureOops,
     DisableTriggerFixture,
     PGBouncerFixture,
+    run_capturing_output,
     ZopeAdapterFixture,
     ZopeUtilityFixture,
     )
@@ -265,6 +266,22 @@ class TestPGBouncerFixtureWithoutCA(TestCase):
         self.assertTrue(self.is_db_available())
 
 
+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)
+
+
 class TestCaptureOopsNoRabbit(TestCase):
 
     # Need CA for subscription.