diff options
-rw-r--r-- | NEWS | 15 | ||||
-rw-r--r-- | README | 15 | ||||
-rw-r--r-- | lib/fixtures/__init__.py | 4 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/__init__.py | 2 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/detailstream.py | 43 | ||||
-rw-r--r-- | lib/fixtures/_fixtures/logger.py | 13 | ||||
-rw-r--r-- | lib/fixtures/tests/_fixtures/__init__.py | 1 | ||||
-rw-r--r-- | lib/fixtures/tests/_fixtures/test_detailstream.py | 54 | ||||
-rwxr-xr-x | setup.py | 3 |
9 files changed, 138 insertions, 12 deletions
@@ -6,6 +6,18 @@ fixtures release notes NEXT ~~~~ +CHANGES +------- + +* ``FakeLogger`` has been split out into a ``LogHandler`` fixture that can + inject arbitrary handlers, giving more flexability. (Jonathan Lange) + +0.3.10 +~~~~~~ + +New ``DetailStream`` fixture to add file-like object content to testtools +details, cleanup logic factored out into a CallMany class. + CHANGES: * Add ``join`` method to ``TempDir`` to more readily get paths relative @@ -14,6 +26,9 @@ CHANGES: * Factor out new ``CallMany`` class to isolate the cleanup logic. (Robert Collins) +* New ``DetailStream`` fixture to add file-like object content to testtools + details. This allows for easy capture of sys.stdout and sys.stderr for + example. (Clark Boylan) 0.3.9 ~~~~~ @@ -28,7 +28,7 @@ Dependencies * Python 2.4+ This is the base language fixtures is written in and for. -* testtools <https://launchpad.net/testtools> 0.9.12 or newer. +* testtools <https://launchpad.net/testtools> 0.9.22 or newer. testtools provides helpful glue functions for the details API used to report information about a fixture (whether its used in a testing or production environment). @@ -266,6 +266,19 @@ In addition to the Fixture, FunctionFixture and MethodFixture classes fixtures includes a number of precanned fixtures. The API docs for fixtures will list the complete set of these, should the dcs be out of date or not to hand. +DetailStream +++++++++++++ + +Trivial adapter to make a StringIO (though it may in future auto-spill to disk +for large content) and expose that as a detail object, for automatic inclusion +in test failure descriptions. Very useful in combination with MonkeyPatch. + + >>> fixture = fixtures.DetailStream('stdout') + >>> fixture.setUp() + >>> with fixtures.MonkeyPatch('sys.stdout', fixture.stream): + ... pass + >>> fixture.cleanUp() + EnvironmentVariable +++++++++++++++++++ diff --git a/lib/fixtures/__init__.py b/lib/fixtures/__init__.py index 5863c52..1390ac8 100644 --- a/lib/fixtures/__init__.py +++ b/lib/fixtures/__init__.py @@ -36,9 +36,10 @@ Most users will want to look at TestWithFixtures and Fixture, to start with. # established at this point, and setup.py will use a version of next-$(revno). # If the releaselevel is 'final', then the tarball will be major.minor.micro. # Otherwise it is major.minor.micro~$(revno). -__version__ = (0, 3, 9, 'final', 0) +__version__ = (0, 3, 10, 'final', 0) __all__ = [ + 'DetailStream', 'EnvironmentVariable', 'EnvironmentVariableFixture', 'FakeLogger', @@ -68,6 +69,7 @@ from fixtures.fixture import ( MethodFixture, ) from fixtures._fixtures import ( + DetailStream, EnvironmentVariable, EnvironmentVariableFixture, FakeLogger, diff --git a/lib/fixtures/_fixtures/__init__.py b/lib/fixtures/_fixtures/__init__.py index b61b010..e113e1e 100644 --- a/lib/fixtures/_fixtures/__init__.py +++ b/lib/fixtures/_fixtures/__init__.py @@ -17,6 +17,7 @@ """Included fixtures.""" __all__ = [ + 'DetailStream', 'EnvironmentVariable', 'EnvironmentVariableFixture', 'FakeLogger', @@ -36,6 +37,7 @@ __all__ = [ ] +from fixtures._fixtures.detailstream import DetailStream from fixtures._fixtures.environ import ( EnvironmentVariable, EnvironmentVariableFixture, diff --git a/lib/fixtures/_fixtures/detailstream.py b/lib/fixtures/_fixtures/detailstream.py new file mode 100644 index 0000000..779ef18 --- /dev/null +++ b/lib/fixtures/_fixtures/detailstream.py @@ -0,0 +1,43 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2012, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +__all__ = [ + 'DetailStream' + ] + +from cStringIO import StringIO + +from fixtures import Fixture +import testtools + + +class DetailStream(Fixture): + """Provide a file-like object and expose it as a detail. + + :attr stream: The file-like object. + """ + + def __init__(self, detail_name): + """Create a DetailStream. + + :param detail_name: Use this as the name of the stream. + """ + self._detail_name = detail_name + + def setUp(self): + super(DetailStream, self).setUp() + self.stream = StringIO() + self.addDetail(self._detail_name, + testtools.content.content_from_stream(self.stream, seek_offset=0)) diff --git a/lib/fixtures/_fixtures/logger.py b/lib/fixtures/_fixtures/logger.py index 660e736..0beb170 100644 --- a/lib/fixtures/_fixtures/logger.py +++ b/lib/fixtures/_fixtures/logger.py @@ -14,12 +14,9 @@ # limitations under that license. from logging import StreamHandler, getLogger, INFO, Formatter -from cStringIO import StringIO - -from testtools.content import Content -from testtools.content_type import UTF8_TEXT from fixtures import Fixture +from fixtures._fixtures.detailstream import DetailStream __all__ = [ 'FakeLogger', @@ -55,8 +52,8 @@ class LogHandler(Fixture): logger.setLevel(self._level) if self._nuke_handlers: for handler in reversed(logger.handlers): - logger.removeHandler(handler) self.addCleanup(logger.addHandler, handler) + logger.removeHandler(handler) try: logger.addHandler(self.handler) finally: @@ -91,10 +88,8 @@ class FakeLogger(Fixture): def setUp(self): super(FakeLogger, self).setUp() - output = StringIO() - self.addDetail( - u"pythonlogging:'%s'" % self._name, - Content(UTF8_TEXT, lambda: [output.getvalue()])) + name = u"pythonlogging:'%s'" % self._name + output = self.useFixture(DetailStream(name)).stream self._output = output handler = StreamHandler(output) if self._format: diff --git a/lib/fixtures/tests/_fixtures/__init__.py b/lib/fixtures/tests/_fixtures/__init__.py index d8e0979..38987b9 100644 --- a/lib/fixtures/tests/_fixtures/__init__.py +++ b/lib/fixtures/tests/_fixtures/__init__.py @@ -15,6 +15,7 @@ def load_tests(loader, standard_tests, pattern): test_modules = [ + 'detailstream', 'environ', 'logger', 'monkeypatch', diff --git a/lib/fixtures/tests/_fixtures/test_detailstream.py b/lib/fixtures/tests/_fixtures/test_detailstream.py new file mode 100644 index 0000000..9df351d --- /dev/null +++ b/lib/fixtures/tests/_fixtures/test_detailstream.py @@ -0,0 +1,54 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2012, Robert Collins <robertc@robertcollins.net> +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. + +from testtools import TestCase + +from fixtures import DetailStream + + +class DetailStreamTest(TestCase): + + def test_empty_detail_stream(self): + detail_name = 'test' + fixture = DetailStream(detail_name) + with fixture: + content = fixture.getDetails()[detail_name] + self.assertEqual("", content.as_text()) + + def test_stream_content_in_details(self): + detail_name = 'test' + fixture = DetailStream(detail_name) + with fixture: + stream = fixture.stream + content = fixture.getDetails()[detail_name] + # Output after getDetails is called is included. + stream.write("testing 1 2 3") + self.assertEqual("testing 1 2 3", content.as_text()) + + def test_stream_content_reset(self): + detail_name = 'test' + fixture = DetailStream(detail_name) + with fixture: + stream = fixture.stream + content = fixture.getDetails()[detail_name] + stream.write("testing 1 2 3") + with fixture: + # The old content object returns the old usage + self.assertEqual("testing 1 2 3", content.as_text()) + content = fixture.getDetails()[detail_name] + # A new fixture returns the new output: + stream = fixture.stream + stream.write("1 2 3 testing") + self.assertEqual("1 2 3 testing", content.as_text()) @@ -6,8 +6,9 @@ import os.path description = file(os.path.join(os.path.dirname(__file__), 'README'), 'rb').read() setup(name="fixtures", - version="0.3.9", + version="0.3.10", description="Fixtures, reusable state for writing clean tests and more.", + keywords="fixture fixtures unittest contextmanager", long_description=description, maintainer="Robert Collins", maintainer_email="robertc@robertcollins.net", |