diff -Nru python-fixtures-0.3.6/.bzrignore python-fixtures-0.3.14/.bzrignore --- python-fixtures-0.3.6/.bzrignore 2010-08-15 08:52:48.000000000 +0000 +++ python-fixtures-0.3.14/.bzrignore 2013-08-16 00:45:03.000000000 +0000 @@ -4,3 +4,5 @@ MANIFEST dist .testrepository +__pycache__ +fixtures.egg-info diff -Nru python-fixtures-0.3.6/debian/changelog python-fixtures-0.3.14/debian/changelog --- python-fixtures-0.3.6/debian/changelog 2014-07-19 23:30:23.000000000 +0000 +++ python-fixtures-0.3.14/debian/changelog 2014-07-17 17:07:51.000000000 +0000 @@ -1,8 +1,64 @@ -python-fixtures (0.3.6-1ubuntu1) precise; urgency=low +python-fixtures (0.3.14-1ubuntu3) precise; urgency=low - * Build using dh_python2 + * No-change backport to precise - -- Matthias Klose Sat, 17 Dec 2011 14:13:32 +0000 + -- Lars Butler (larsbutler) Thu, 17 Jul 2014 17:07:24 +0000 + +python-fixtures (0.3.14-1ubuntu2) trusty; urgency=medium + + * d/control: Build-Depend on python3-all. + + -- Barry Warsaw Thu, 16 Jan 2014 10:47:08 -0500 + +python-fixtures (0.3.14-1ubuntu1) trusty; urgency=low + + * Drop not-needed python-support build-depends. + + -- Dmitrijs Ledkovs Tue, 12 Nov 2013 15:37:41 +0000 + +python-fixtures (0.3.14-1) unstable; urgency=low + + * New upstream release. + * Switched to dh short style instead of CDBS. + * Added support for Python 3. + * Added a debian/gbp.conf, and some VCS fields. + * Now running the nose tests. + + -- Thomas Goirand Sat, 07 Sep 2013 10:46:53 +0800 + +python-fixtures (0.3.12-0.2) unstable; urgency=low + + * Uploading to unstable. + + -- Thomas Goirand Sat, 11 May 2013 04:54:53 +0000 + +python-fixtures (0.3.12-0.1) experimental; urgency=low + + * Non-maintainer upload (with current maintainer approval). + * Uploading to experimental. + * New upstream release. + * Now using compat and debhelper 9. + * Using parsable format 1.0 for debian/copyright. + * Now using source format 3.0 (quilt). + * Build-depends on python (>= 2.6.6-3~), remove python-dev build-depends. + * Standard-Version is now 3.9.4 (no change but the above). + * Added a debian/watch file. + * Disabled test suite as it fails. + * Added a homepage field. + * Removes /usr/share/cdbs/1/rules/simple-patchsys.mk since it's now + deprecated. + + -- Thomas Goirand Fri, 15 Feb 2013 05:23:19 +0000 + +python-fixtures (0.3.6-1.1) unstable; urgency=low + + * Non-maintainer upload. + * Fix "FTBFS: AttributeError: 'BrokenFixture' object has no attribute + 'items'": add patch from Emanuele Aina (add missing calls to + getDetails()). + (Closes: #665018) + + -- gregor herrmann Fri, 06 Jul 2012 16:48:36 -0600 python-fixtures (0.3.6-1) unstable; urgency=low diff -Nru python-fixtures-0.3.6/debian/compat python-fixtures-0.3.14/debian/compat --- python-fixtures-0.3.6/debian/compat 2014-07-19 23:30:23.000000000 +0000 +++ python-fixtures-0.3.14/debian/compat 2014-01-16 15:46:55.000000000 +0000 @@ -1 +1 @@ -5 +9 diff -Nru python-fixtures-0.3.6/debian/control python-fixtures-0.3.14/debian/control --- python-fixtures-0.3.6/debian/control 2014-07-19 23:30:23.000000000 +0000 +++ python-fixtures-0.3.14/debian/control 2014-01-16 15:47:03.000000000 +0000 @@ -1,22 +1,49 @@ Source: python-fixtures Section: python Priority: optional -Maintainer: Robert Collins -Build-Depends: debhelper (>= 5.0.38), cdbs (>= 0.4.49), - python-all-dev (>= 2.3.5-11) -Build-Depends-Indep: python-docutils, python (>= 2.6.6-3~), - python-testtools (>= 0.9.11) -Standards-Version: 3.8.3 +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Robert Collins +Uploaders: Thomas Goirand +Build-Depends: debhelper (>= 9), + python (>= 2.6.6-3~), + python-setuptools, + python3-all, + python3-setuptools +Build-Depends-Indep: python-docutils, + python-nose, + python-testtools (>= 0.9.11), + python3-testtools +Standards-Version: 3.9.4 +Vcs-Browser: http://anonscm.debian.org/gitweb/?p=openstack/python-fixtures.git +Vcs-Git: git://anonscm.debian.org/openstack/python-fixtures.git +Homepage: http://pypi.python.org/pypi/fixtures Package: python-fixtures Architecture: all -Depends: python-testtools (>= 0.9.11), ${python:Depends}, ${misc:Depends} -Description: PyUnit extension for defining test fixtures outside of test cases +Depends: python-testtools (>= 0.9.11), ${misc:Depends}, ${python:Depends} +Description: PyUnit extension for defining test fixtures outside of test cases - Python 2.x A PyUnit extension for defining test fixtures outside of test cases. Each - fixture encapsulates creating, reusing and freeing some state - be that a + fixture encapsulates creating, reusing and freeing some state - be that a temporary directory on disk, SQL server connection, or just a particular object graph. This is extremely useful for testing and general resource management. . Fixtures ships with the base class, unittest glue and a number of precanned concrete fixtures. + . + This package provides the Python 2.x module. + +Package: python3-fixtures +Architecture: all +Depends: python3-testtools (>= 0.9.11), ${misc:Depends}, ${python3:Depends} +Description: PyUnit extension for defining test fixtures outside of test cases - Python 3.x + A PyUnit extension for defining test fixtures outside of test cases. Each + fixture encapsulates creating, reusing and freeing some state - be that a + temporary directory on disk, SQL server connection, or just a particular + object graph. This is extremely useful for testing and general resource + management. + . + Fixtures ships with the base class, unittest glue and a number of precanned + concrete fixtures. + . + This package provides the Python 3.x module. diff -Nru python-fixtures-0.3.6/debian/copyright python-fixtures-0.3.14/debian/copyright --- python-fixtures-0.3.6/debian/copyright 2014-07-19 23:30:23.000000000 +0000 +++ python-fixtures-0.3.14/debian/copyright 2014-01-16 15:46:55.000000000 +0000 @@ -1,22 +1,57 @@ -This package was originally debianized by Robert Collins - on Sep 13 2010. - -It was downloaded from http://launchpad.net/python-fixtures/. - -Upstream Authors: Robert Collins - -Copyright 2010 Robert Collins. - -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. - -On Debian systems, the full text of these licenses can be found in -/usr/share/common-licenses/Apache-2.0 and /usr/share/common-licenses/BSD. +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: fixtures +Upstream-Contact: Robert Collins +Source: http://pypi.python.org/pypi/fixtures + +Files: debian/* +Copyright: (c) 2010-2012, Robert Collins + (c) 2013, Thomas Goirand +License: Apache-2.0-or-BSD + +Files: * +Copyright: (c) 2010-2013, Robert Collins +License: Apache-2.0-or-BSD + +License: Apache-2.0-or-BSD + 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 the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + . + On Debian systems, the full text of the Apache license can be found in + /usr/share/common-licenses/Apache-2.0. + . + BSD License: + . + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + 3. Neither the name of Robert Collins nor the names of Subunit contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY ROBERT COLLINS AND SUBUNIT CONTRIBUTORS ``AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff -Nru python-fixtures-0.3.6/debian/gbp.conf python-fixtures-0.3.14/debian/gbp.conf --- python-fixtures-0.3.6/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/debian/gbp.conf 2014-01-16 15:46:55.000000000 +0000 @@ -0,0 +1,11 @@ +[DEFAULT] +upstream-branch = upstream-unstable +debian-branch = debian-unstable +pristine-tar = True + +[git-buildpackage] +export-dir = ../build-area/ +tarball-dir = ../tarballs/ + +[git-import-orig] +dch = False diff -Nru python-fixtures-0.3.6/debian/pycompat python-fixtures-0.3.14/debian/pycompat --- python-fixtures-0.3.6/debian/pycompat 2014-07-19 23:30:23.000000000 +0000 +++ python-fixtures-0.3.14/debian/pycompat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -2 diff -Nru python-fixtures-0.3.6/debian/pyversions python-fixtures-0.3.14/debian/pyversions --- python-fixtures-0.3.6/debian/pyversions 2014-07-19 23:30:23.000000000 +0000 +++ python-fixtures-0.3.14/debian/pyversions 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -2.4- diff -Nru python-fixtures-0.3.6/debian/rules python-fixtures-0.3.14/debian/rules --- python-fixtures-0.3.6/debian/rules 2014-07-19 23:30:23.000000000 +0000 +++ python-fixtures-0.3.14/debian/rules 2014-01-16 15:46:55.000000000 +0000 @@ -1,14 +1,26 @@ #!/usr/bin/make -f -include /usr/share/cdbs/1/rules/debhelper.mk -include /usr/share/cdbs/1/class/python-distutils.mk -include /usr/share/cdbs/1/rules/simple-patchsys.mk +PYTHONS:=$(shell pyversions -vr) +PYTHON3S:=$(shell py3versions -vr) -clean:: - -rm -rf build - -rm tests.log - find . -name "*.pyc" -print0 | xargs -0 rm -f +%: + dh $@ --buildsystem=python_distutils --with python2,python3 -# In the event of -common-post-build-indep:: - PYTHONPATH=lib python -m testtools.run fixtures.test_suite +override_dh_auto_install: + set -e && for pyvers in $(PYTHONS); do \ + python$$pyvers setup.py install --install-layout=deb \ + --root $(CURDIR)/debian/python-fixtures; \ + done + set -e && for pyvers in $(PYTHON3S); do \ + python$$pyvers setup.py install --install-layout=deb \ + --root $(CURDIR)/debian/python3-fixtures; \ + done + +override_dh_clean: + dh_clean -O--buildsystem=python_distutils + find . -iname '*.pyc' -delete + +ifeq (,$(findstring nocheck, $(DEB_BUILD_OPTIONS))) +override_dh_auto_test: + nosetests || true +endif diff -Nru python-fixtures-0.3.6/debian/source/format python-fixtures-0.3.14/debian/source/format --- python-fixtures-0.3.6/debian/source/format 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/debian/source/format 2014-01-16 15:46:55.000000000 +0000 @@ -0,0 +1 @@ +3.0 (quilt) diff -Nru python-fixtures-0.3.6/debian/watch python-fixtures-0.3.14/debian/watch --- python-fixtures-0.3.6/debian/watch 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/debian/watch 2014-01-16 15:46:55.000000000 +0000 @@ -0,0 +1,2 @@ +version=3 +http://pypi.python.org/packages/f/fixtures/fixtures-(.*)\.tar.gz diff -Nru python-fixtures-0.3.6/HACKING python-fixtures-0.3.14/HACKING --- python-fixtures-0.3.6/HACKING 2010-08-15 06:04:29.000000000 +0000 +++ python-fixtures-0.3.14/HACKING 2013-08-16 00:56:10.000000000 +0000 @@ -35,3 +35,17 @@ more specific modules, rather than becoming large and bloated itself. For instance, TestWithFixtures lives in fixtures.testcase, and is imported in the fixtures __init__.py. + +Releasing ++++++++++ + +1. Update the version number in __init__.py and setup.py and add a version to + NEWS. + +1. Upload to pypi, signed. + +1. commit, tag. + +1. Close bugs. + +1. Rename the next milestone, release it, and make a new one. diff -Nru python-fixtures-0.3.6/lib/fixtures/callmany.py python-fixtures-0.3.14/lib/fixtures/callmany.py --- python-fixtures-0.3.6/lib/fixtures/callmany.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/callmany.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,100 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2010, Robert Collins +# +# 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__ = [ + 'CallMany', + ] + +import sys + +from testtools.compat import ( + reraise, + ) +from testtools.helpers import try_import + + +class MultipleExceptions(Exception): + """Report multiple exc_info tuples in self.args.""" + +MultipleExceptions = try_import( + "testtools.MultipleExceptions", MultipleExceptions) + + +class CallMany(object): + """A stack of functions which will all be called on __call__. + + CallMany also acts as a context manager for convenience. + + Functions are called in last pushed first executed order. + + This is used by Fixture to manage its addCleanup feature. + """ + + def __init__(self): + self._cleanups = [] + + def push(self, cleanup, *args, **kwargs): + """Add a function to be called from __call__. + + On __call__ all functions are called - see __call__ for details on how + multiple exceptions are handled. + + :param cleanup: A callable to call during cleanUp. + :param *args: Positional args for cleanup. + :param kwargs: Keyword args for cleanup. + :return: None + """ + self._cleanups.append((cleanup, args, kwargs)) + + def __call__(self, raise_errors=True): + """Run all the registered functions. + + :param raise_errors: Deprecated parameter from before testtools gained + MultipleExceptions. raise_errors defaults to True. When True + if exception(s) are raised while running functions, they are + re-raised after all the functions have run. If multiple exceptions + are raised, they are all wrapped into a MultipleExceptions object, + and that is raised. + Thus, to cach a specific exception from a function run by __call__, + you need to catch both the exception and MultipleExceptions, and + then check within a MultipleExceptions instance for an occurance of + the type you wish to catch. + :return: Either None or a list of the exc_info() for each exception + that occured if raise_errors was False. + """ + cleanups = reversed(self._cleanups) + self._cleanups = [] + result = [] + for cleanup, args, kwargs in cleanups: + try: + cleanup(*args, **kwargs) + except Exception: + result.append(sys.exc_info()) + if result and raise_errors: + if 1 == len(result): + error = result[0] + reraise(error[0], error[1], error[2]) + else: + raise MultipleExceptions(*result) + if not raise_errors: + return result + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self() + return False # propogate exceptions from the with body. + diff -Nru python-fixtures-0.3.6/lib/fixtures/fixture.py python-fixtures-0.3.14/lib/fixtures/fixture.py --- python-fixtures-0.3.6/lib/fixtures/fixture.py 2011-06-23 07:47:38.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/fixture.py 2013-07-03 20:36:53.000000000 +0000 @@ -1,12 +1,12 @@ # fixtures: Fixtures with cleanups for testing and convenience. # # Copyright (c) 2010, Robert Collins -# +# # 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 @@ -23,13 +23,17 @@ import itertools import sys +from testtools.compat import ( + advance_iterator, + reraise, + ) from testtools.helpers import try_import -class MultipleExceptions(Exception): - """Report multiple exc_info tuples in self.args.""" - -MultipleExceptions = try_import( - "testtools.MultipleExceptions", MultipleExceptions) +from fixtures.callmany import ( + CallMany, + # Deprecated, imported for compatibility. + MultipleExceptions, + ) gather_details = try_import("testtools.testcase.gather_details") @@ -70,7 +74,7 @@ :param kwargs: Keyword args for cleanup. :return: None """ - self._cleanups.append((cleanup, args, kwargs)) + self._cleanups.push(cleanup, *args, **kwargs) def addDetail(self, name, content_object): """Add a detail to the Fixture. @@ -104,22 +108,10 @@ :return: A list of the exc_info() for each exception that occured if raise_first was False """ - cleanups = reversed(self._cleanups) - self._clear_cleanups() - result = [] - for cleanup, args, kwargs in cleanups: - try: - cleanup(*args, **kwargs) - except Exception: - result.append(sys.exc_info()) - if result and raise_first: - if 1 == len(result): - error = result[0] - raise error[0], error[1], error[2] - else: - raise MultipleExceptions(*result) - if not raise_first: - return result + try: + return self._cleanups(raise_errors=raise_first) + finally: + self._clear_cleanups() def _clear_cleanups(self): """Clean the cleanup queue without running them. @@ -130,7 +122,7 @@ This also clears the details dict. """ - self._cleanups = [] + self._cleanups = CallMany() self._details = {} self._detail_sources = [] @@ -139,7 +131,10 @@ return self def __exit__(self, exc_type, exc_val, exc_tb): - errors = self.cleanUp() + try: + self._cleanups() + finally: + self._clear_cleanups() return False # propogate exceptions from the with body. def getDetails(self): @@ -147,7 +142,7 @@ This does not return the internal dictionary: mutating it will have no effect. If you need to mutate it, just do so directly. - + :return: Dict from name -> content_object. """ result = dict(self._details) @@ -159,7 +154,7 @@ """Prepare the Fixture for use. This should be overridden by most concrete fixtures. When overriding - be sure to include self.addCleanup calls to restore the fixture to + be sure to include self.addCleanup calls to restore the fixture to an un-setUp state, so that a single Fixture instance can be reused. After setUp is called, the fixture will have one or more attributes @@ -199,7 +194,7 @@ # The child failed to come up, capture any details it has (copying # the content, it may go away anytime). if gather_details is not None: - gather_details(fixture, self) + gather_details(fixture.getDetails(), self._details) raise else: self.addCleanup(fixture.cleanUp) @@ -214,7 +209,7 @@ Typically used when an existing object or function interface exists but you wish to use it as a Fixture (e.g. because fixtures are in use in your test - suite and this will fit in better). + suite and this will fit in better). To adapt an object with differently named setUp and cleanUp methods: fixture = FunctionFixture(object.install, object.__class__.remove) diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/environ.py python-fixtures-0.3.14/lib/fixtures/_fixtures/environ.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/environ.py 2010-10-25 20:31:20.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/environ.py 2013-07-03 20:36:53.000000000 +0000 @@ -1,12 +1,12 @@ # fixtures: Fixtures with cleanups for testing and convenience. # -# Copyright (c) 2010, Robert Collins -# +# Copyright (c) 2010, 2011, Robert Collins +# # 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 @@ -14,6 +14,7 @@ # limitations under that license. __all__ = [ + 'EnvironmentVariable', 'EnvironmentVariableFixture' ] @@ -22,11 +23,11 @@ from fixtures import Fixture -class EnvironmentVariableFixture(Fixture): +class EnvironmentVariable(Fixture): """Isolate a specific environment variable.""" def __init__(self, varname, newvalue=None): - """Create an EnvironmentVariableFixture. + """Create an EnvironmentVariable fixture. :param varname: the name of the variable to isolate. :param newvalue: A value to set the variable to. If None, the variable @@ -35,12 +36,12 @@ During setup the variable will be deleted or assigned the requested value, and this will be restored in cleanUp. """ - Fixture.__init__(self) + super(EnvironmentVariable, self).__init__() self.varname = varname self.newvalue = newvalue - + def setUp(self): - Fixture.setUp(self) + super(EnvironmentVariable, self).setUp() varname = self.varname orig_value = os.environ.get(varname) if orig_value is not None: @@ -52,3 +53,6 @@ os.environ[varname] = self.newvalue else: os.environ.pop(varname, '') + + +EnvironmentVariableFixture = EnvironmentVariable diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/__init__.py python-fixtures-0.3.14/lib/fixtures/_fixtures/__init__.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/__init__.py 2011-06-23 05:36:48.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/__init__.py 2013-07-03 20:36:53.000000000 +0000 @@ -1,6 +1,6 @@ # fixtures: Fixtures with cleanups for testing and convenience. # -# Copyright (c) 2010, Robert Collins +# Copyright (c) 2010, 2011, Robert Collins # # 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 @@ -17,20 +17,58 @@ """Included fixtures.""" __all__ = [ + 'ByteStream', + 'DetailStream', + 'EnvironmentVariable', 'EnvironmentVariableFixture', + 'FakeLogger', + 'FakePopen', + 'LoggerFixture', + 'LogHandler', 'MonkeyPatch', + 'NestedTempfile', 'PackagePathEntry', 'PopenFixture', 'PythonPackage', 'PythonPathEntry', + 'StringStream', 'TempDir', + 'TempHomeDir', + 'Timeout', + 'TimeoutException', ] -from fixtures._fixtures.environ import EnvironmentVariableFixture +from fixtures._fixtures.environ import ( + EnvironmentVariable, + EnvironmentVariableFixture, + ) +from fixtures._fixtures.logger import ( + FakeLogger, + LoggerFixture, + LogHandler, + ) from fixtures._fixtures.monkeypatch import MonkeyPatch -from fixtures._fixtures.popen import PopenFixture +from fixtures._fixtures.popen import ( + FakePopen, + PopenFixture, + ) from fixtures._fixtures.packagepath import PackagePathEntry from fixtures._fixtures.pythonpackage import PythonPackage from fixtures._fixtures.pythonpath import PythonPathEntry -from fixtures._fixtures.tempdir import TempDir +from fixtures._fixtures.streams import ( + ByteStream, + DetailStream, + StringStream, + ) +from fixtures._fixtures.tempdir import ( + NestedTempfile, + TempDir, + ) +from fixtures._fixtures.temphomedir import ( + TempHomeDir, + ) +from fixtures._fixtures.timeout import ( + Timeout, + TimeoutException, + ) diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/logger.py python-fixtures-0.3.14/lib/fixtures/_fixtures/logger.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/logger.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/logger.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,109 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2011, Robert Collins +# +# 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 logging import StreamHandler, getLogger, INFO, Formatter + +from testtools.compat import _u + +from fixtures import Fixture +from fixtures._fixtures.streams import StringStream + +__all__ = [ + 'FakeLogger', + 'LoggerFixture', + 'LogHandler', + ] + + +class LogHandler(Fixture): + """Replace a logger's handlers.""" + + def __init__(self, handler, name="", level=None, nuke_handlers=True): + """Create a LogHandler fixture. + + :param handler: The handler to replace other handlers with. + If nuke_handlers is False, then added as an extra handler. + :param name: The name of the logger to replace. Defaults to "". + :param level: The log level to set, defaults to not changing the level. + :param nuke_handlers: If True remove all existing handles (prevents + existing messages going to e.g. stdout). Defaults to True. + """ + super(LogHandler, self).__init__() + self.handler = handler + self._name = name + self._level = level + self._nuke_handlers = nuke_handlers + + def setUp(self): + super(LogHandler, self).setUp() + logger = getLogger(self._name) + if self._level: + self.addCleanup(logger.setLevel, logger.level) + logger.setLevel(self._level) + if self._nuke_handlers: + for handler in reversed(logger.handlers): + self.addCleanup(logger.addHandler, handler) + logger.removeHandler(handler) + try: + logger.addHandler(self.handler) + finally: + self.addCleanup(logger.removeHandler, self.handler) + + +class FakeLogger(Fixture): + """Replace a logger and capture its output.""" + + def __init__(self, name="", level=INFO, format=None, nuke_handlers=True): + """Create a FakeLogger fixture. + + :param name: The name of the logger to replace. Defaults to "". + :param level: The log level to set, defaults to INFO. + :param format: Logging format to use. Defaults to capturing supplied + messages verbatim. + :param nuke_handlers: If True remove all existing handles (prevents + existing messages going to e.g. stdout). Defaults to True. + + Example: + + def test_log(self) + fixture = self.useFixture(LoggerFixture()) + logging.info('message') + self.assertEqual('message', fixture.output) + """ + super(FakeLogger, self).__init__() + self._name = name + self._level = level + self._format = format + self._nuke_handlers = nuke_handlers + + def setUp(self): + super(FakeLogger, self).setUp() + name = _u("pythonlogging:'%s'") % self._name + output = self.useFixture(StringStream(name)).stream + self._output = output + handler = StreamHandler(output) + if self._format: + handler.setFormatter(Formatter(self._format)) + self.useFixture( + LogHandler(handler, name=self._name, level=self._level, + nuke_handlers=self._nuke_handlers)) + + @property + def output(self): + self._output.seek(0) + return self._output.read() + + +LoggerFixture = FakeLogger diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/monkeypatch.py python-fixtures-0.3.14/lib/fixtures/_fixtures/monkeypatch.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/monkeypatch.py 2010-11-07 06:50:39.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/monkeypatch.py 2013-07-03 20:36:53.000000000 +0000 @@ -17,8 +17,6 @@ 'MonkeyPatch' ] -import os - from fixtures import Fixture diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/popen.py python-fixtures-0.3.14/lib/fixtures/_fixtures/popen.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/popen.py 2010-10-25 20:31:20.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/popen.py 2013-08-16 02:59:09.000000000 +0000 @@ -1,6 +1,6 @@ # fixtures: Fixtures with cleanups for testing and convenience. # -# Copyright (c) 2010, Robert Collins +# Copyright (c) 2010, 2011, Robert Collins # # 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 @@ -14,6 +14,7 @@ # limitations under that license. __all__ = [ + 'FakePopen', 'PopenFixture' ] @@ -32,10 +33,11 @@ self.stdout = info.get('stdout') self.stderr = info.get('stderr') self.pid = random.randint(0, 65536) + self._returncode = info.get('returncode', 0) self.returncode = None def communicate(self): - self.returncode = 0 + self.returncode = self._returncode if self.stdout: out = self.stdout.getvalue() else: @@ -47,10 +49,12 @@ return out, err def wait(self): + if self.returncode is None: + self.communicate() return self.returncode -class PopenFixture(Fixture): +class FakePopen(Fixture): """Replace subprocess.Popen. Primarily useful for testing, this fixture replaces subprocess.Popen with a @@ -59,27 +63,54 @@ :ivar procs: A list of the processes created by the fixture. """ + _unpassed = object() + def __init__(self, get_info=lambda _:{}): """Create a PopenFixture :param get_info: Optional callback to control the behaviour of the created process. This callback takes a kwargs dict for the Popen call, and should return a dict with any desired attributes. - e.g. return {'stdin': StringIO('foobar')} + Only parameters that are supplied to the Popen call are in the + dict, making it possible to detect the difference between 'passed + with a default value' and 'not passed at all'. + + e.g. + def get_info(proc_args): + self.assertEqual(subprocess.PIPE, proc_args['stdin']) + return {'stdin': StringIO('foobar')} + + The default behaviour if no get_info is supplied is for the return + process to have returncode of None, empty streams and a random pid. """ + super(FakePopen, self).__init__() self.get_info = get_info def setUp(self): - super(PopenFixture, self).setUp() + super(FakePopen, self).setUp() self.addCleanup(setattr, subprocess, 'Popen', subprocess.Popen) subprocess.Popen = self self.procs = [] - def __call__(self, args, bufsize=0, executable=None, stdin=None, - stdout=None, stderr=None): - proc_args = dict(args=args, bufsize=bufsize, executable=executable, - stdin=stdin, stdout=stdout, stderr=stderr) + # The method has the correct signature so we error appropriately if called + # wrongly. + def __call__(self, args, bufsize=_unpassed, executable=_unpassed, + stdin=_unpassed, stdout=_unpassed, stderr=_unpassed, + preexec_fn=_unpassed, close_fds=_unpassed, shell=_unpassed, + cwd=_unpassed, env=_unpassed, universal_newlines=_unpassed, + startupinfo=_unpassed, creationflags=_unpassed): + proc_args = dict(args=args) + local = locals() + for param in [ + "bufsize", "executable", "stdin", "stdout", "stderr", + "preexec_fn", "close_fds", "shell", "cwd", "env", + "universal_newlines", "startupinfo", "creationflags"]: + if local[param] is not FakePopen._unpassed: + proc_args[param] = local[param] proc_info = self.get_info(proc_args) result = FakeProcess(proc_args, proc_info) self.procs.append(result) return result + + +PopenFixture = FakePopen diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/pythonpackage.py python-fixtures-0.3.14/lib/fixtures/_fixtures/pythonpackage.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/pythonpackage.py 2010-11-07 06:50:39.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/pythonpackage.py 2013-07-03 20:36:53.000000000 +0000 @@ -55,7 +55,7 @@ os.mkdir(root) init_seen = not self.init for modulename, contents in self.modulelist: - stream = file(os.path.join(root, modulename), 'wb') + stream = open(os.path.join(root, modulename), 'wb') try: stream.write(contents) finally: @@ -63,4 +63,4 @@ if modulename == '__init__.py': init_seen = True if not init_seen: - file(os.path.join(root, '__init__.py'), 'wb').close() + open(os.path.join(root, '__init__.py'), 'wb').close() diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/streams.py python-fixtures-0.3.14/lib/fixtures/_fixtures/streams.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/streams.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/streams.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,97 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2012, Robert Collins +# +# 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__ = [ + 'ByteStream', + 'DetailStream', + 'StringStream', + ] + +import io +import sys + +from fixtures import Fixture +import testtools + + +class Stream(Fixture): + """Expose a file-like object as a detail. + + :attr stream: The file-like object. + """ + + def __init__(self, detail_name, stream_factory): + """Create a ByteStream. + + :param detail_name: Use this as the name of the stream. + :param stream_factory: Called to construct a pair of streams: + (write_stream, content_stream). + """ + self._detail_name = detail_name + self._stream_factory = stream_factory + + def setUp(self): + super(Stream, self).setUp() + write_stream, read_stream = self._stream_factory() + self.stream = write_stream + self.addDetail(self._detail_name, + testtools.content.content_from_stream(read_stream, seek_offset=0)) + + +def _byte_stream_factory(): + result = io.BytesIO() + return (result, result) + + +def ByteStream(detail_name): + """Provide a file-like object that accepts bytes and expose as a detail. + + :param detail_name: The name of the detail. + :return: A fixture which has an attribute `stream` containing the file-like + object. + """ + return Stream(detail_name, _byte_stream_factory) + + +def _string_stream_factory(): + lower = io.BytesIO() + upper = io.TextIOWrapper(lower, encoding="utf8") + # See http://bugs.python.org/issue7955 + upper._CHUNK_SIZE = 1 + # In theory, this is sufficient and correct, but on Python2, + # upper.write(_b('foo")) will whinge louadly. + if sys.version_info[0] < 3: + upper_write = upper.write + def safe_write(str_or_bytes): + if type(str_or_bytes) is str: + str_or_bytes = str_or_bytes.decode('utf8') + return upper_write(str_or_bytes) + upper.write = safe_write + return upper, lower + + +def StringStream(detail_name): + """Provide a file-like object that accepts strings and expose as a detail. + + :param detail_name: The name of the detail. + :return: A fixture which has an attribute `stream` containing the file-like + object. + """ + return Stream(detail_name, _string_stream_factory) + + +def DetailStream(detail_name): + """Deprecated alias for ByteStream.""" + return ByteStream(detail_name) diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/tempdir.py python-fixtures-0.3.14/lib/fixtures/_fixtures/tempdir.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/tempdir.py 2010-11-07 06:50:39.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/tempdir.py 2013-07-03 20:36:53.000000000 +0000 @@ -14,22 +14,57 @@ # limitations under that license. __all__ = [ - 'TempDir' + 'NestedTempfile', + 'TempDir', ] +import os import shutil import tempfile -from fixtures import Fixture +import fixtures -class TempDir(Fixture): +class TempDir(fixtures.Fixture): """Create a temporary directory. :ivar path: The path of the temporary directory. """ + def __init__(self, rootdir=None): + """Create a TempDir. + + :param rootdir: If supplied force the temporary directory to be a + child of rootdir. + """ + self.rootdir = rootdir + def setUp(self): - Fixture.setUp(self) - self.path = tempfile.mkdtemp() + super(TempDir, self).setUp() + self.path = tempfile.mkdtemp(dir=self.rootdir) self.addCleanup(shutil.rmtree, self.path, ignore_errors=True) + + def join(self, *children): + """Return an absolute path, given one relative to this ``TempDir``. + + WARNING: This does not do any checking of ``children`` to make sure + they aren't walking up the tree using path segments like '..' or + '/usr'. Use at your own risk. + """ + return os.path.abspath(os.path.join(self.path, *children)) + + +class NestedTempfile(fixtures.Fixture): + """Nest all temporary files and directories inside another directory. + + This temporarily monkey-patches the default location that the `tempfile` + package creates temporary files and directories in to be a new temporary + directory. This new temporary directory is removed when the fixture is torn + down. + """ + + def setUp(self): + super(NestedTempfile, self).setUp() + tempdir = self.useFixture(TempDir()).path + patch = fixtures.MonkeyPatch("tempfile.tempdir", tempdir) + self.useFixture(patch) diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/temphomedir.py python-fixtures-0.3.14/lib/fixtures/_fixtures/temphomedir.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/temphomedir.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/temphomedir.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,32 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2010, Canonical Ltd. +# +# 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__ = [ + 'TempHomeDir', + ] + +import fixtures +from fixtures._fixtures.tempdir import TempDir + + +class TempHomeDir(TempDir): + """Create a temporary directory and set it as $HOME + + :ivar path: the path of the temporary directory. + """ + + def setUp(self): + super(TempHomeDir, self).setUp() + self.useFixture(fixtures.EnvironmentVariable("HOME", self.path)) diff -Nru python-fixtures-0.3.6/lib/fixtures/_fixtures/timeout.py python-fixtures-0.3.14/lib/fixtures/_fixtures/timeout.py --- python-fixtures-0.3.6/lib/fixtures/_fixtures/timeout.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/_fixtures/timeout.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,68 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (C) 2011, Martin Pool +# +# 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. + + +"""Timeout fixture.""" + + +import signal + +import fixtures + +__all__ = [ + 'Timeout', + 'TimeoutException', + ] + + +class TimeoutException(Exception): + """Timeout expired""" + + +class Timeout(fixtures.Fixture): + """Fixture that aborts the contained code after a number of seconds. + + The interrupt can be either gentle, in which case TimeoutException is + raised, or not gentle, in which case the process will typically be aborted + by SIGALRM. + + Cautions: + * This has no effect on Windows. + * Only one Timeout can be used at any time per process. + """ + + def __init__(self, timeout_secs, gentle): + self.timeout_secs = timeout_secs + self.alarm_fn = getattr(signal, 'alarm', None) + self.gentle = gentle + + def signal_handler(self, signum, frame): + raise TimeoutException() + + def setUp(self): + super(Timeout, self).setUp() + if self.alarm_fn is None: + return # Can't run on Windows + if self.gentle: + # Install a handler for SIGARLM so we can raise an exception rather + # than the default handler executing, which kills the process. + old_handler = signal.signal(signal.SIGALRM, self.signal_handler) + # We add the slarm cleanup before the cleanup for the signal handler, + # otherwise there is a race condition where the signal handler is + # cleaned up but the alarm still fires. + self.addCleanup(lambda: self.alarm_fn(0)) + self.alarm_fn(self.timeout_secs) + if self.gentle: + self.addCleanup(lambda: signal.signal(signal.SIGALRM, old_handler)) diff -Nru python-fixtures-0.3.6/lib/fixtures/__init__.py python-fixtures-0.3.14/lib/fixtures/__init__.py --- python-fixtures-0.3.6/lib/fixtures/__init__.py 2011-06-23 08:18:42.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/__init__.py 2013-08-16 03:03:41.000000000 +0000 @@ -1,6 +1,6 @@ # fixtures: Fixtures with cleanups for testing and convenience. # -# Copyright (c) 2010, Robert Collins +# Copyright (c) 2010, 2011, Robert Collins # # 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 @@ -36,38 +36,65 @@ # 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, 6, 'final', 0) +__version__ = (0, 3, 14, 'final', 0) __all__ = [ + 'ByteStream', + 'DetailStream', + 'EnvironmentVariable', 'EnvironmentVariableFixture', + 'FakeLogger', + 'FakePopen', 'Fixture', 'FunctionFixture', + 'LoggerFixture', + 'LogHandler', 'MethodFixture', 'MonkeyPatch', + 'NestedTempfile', 'PackagePathEntry', 'PopenFixture', 'PythonPackage', 'PythonPathEntry', + 'StringStream', 'TempDir', + 'TempHomeDir', 'TestWithFixtures', + 'Timeout', + 'TimeoutException', ] -from fixtures.fixture import Fixture, FunctionFixture, MethodFixture +from fixtures.fixture import ( + Fixture, + FunctionFixture, + MethodFixture, + ) from fixtures._fixtures import ( + ByteStream, + DetailStream, + EnvironmentVariable, EnvironmentVariableFixture, + FakeLogger, + FakePopen, + LoggerFixture, + LogHandler, MonkeyPatch, + NestedTempfile, PackagePathEntry, PopenFixture, PythonPackage, PythonPathEntry, + StringStream, TempDir, + TempHomeDir, + Timeout, + TimeoutException, ) from fixtures.testcase import TestWithFixtures def test_suite(): - import unittest import fixtures.tests return fixtures.tests.test_suite() diff -Nru python-fixtures-0.3.6/lib/fixtures/testcase.py python-fixtures-0.3.14/lib/fixtures/testcase.py --- python-fixtures-0.3.6/lib/fixtures/testcase.py 2011-06-23 07:44:15.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/testcase.py 2013-08-16 00:50:11.000000000 +0000 @@ -26,6 +26,9 @@ """A TestCase with a helper function to use fixtures. Normally used as a mix-in class to add useFixture. + + Note that test classes such as testtools.TestCase which already have a + ``useFixture`` method do not need this mixed in. """ def useFixture(self, fixture): @@ -45,7 +48,7 @@ except: if use_details: # Capture the details now, in case the fixture goes away. - gather_details(fixture, self) + gather_details(fixture.getDetails(), self.getDetails()) raise else: self.addCleanup(fixture.cleanUp) diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/__init__.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/__init__.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/__init__.py 2011-06-23 05:35:26.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/__init__.py 2013-07-03 20:36:53.000000000 +0000 @@ -16,12 +16,16 @@ def load_tests(loader, standard_tests, pattern): test_modules = [ 'environ', + 'logger', 'monkeypatch', 'packagepath', 'popen', 'pythonpackage', 'pythonpath', + 'streams', 'tempdir', + 'temphomedir', + 'timeout', ] prefix = "fixtures.tests._fixtures.test_" test_mod_names = [prefix + test_module for test_module in test_modules] diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_environ.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_environ.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_environ.py 2010-10-25 20:31:20.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_environ.py 2013-07-03 20:36:53.000000000 +0000 @@ -1,6 +1,6 @@ # fixtures: Fixtures with cleanups for testing and convenience. # -# Copyright (c) 2010, Robert Collins +# Copyright (c) 2010, 2011, Robert Collins # # 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 @@ -17,59 +17,58 @@ import testtools -import fixtures -from fixtures import EnvironmentVariableFixture, TestWithFixtures +from fixtures import EnvironmentVariable, TestWithFixtures -class TestEnvironmentVariableFixture(testtools.TestCase, TestWithFixtures): +class TestEnvironmentVariable(testtools.TestCase, TestWithFixtures): def test_setup_ignores_missing(self): - fixture = EnvironmentVariableFixture('FIXTURES_TEST_VAR') + fixture = EnvironmentVariable('FIXTURES_TEST_VAR') os.environ.pop('FIXTURES_TEST_VAR', '') self.useFixture(fixture) self.assertEqual(None, os.environ.get('FIXTURES_TEST_VAR')) def test_setup_sets_when_missing(self): - fixture = EnvironmentVariableFixture('FIXTURES_TEST_VAR', 'bar') + fixture = EnvironmentVariable('FIXTURES_TEST_VAR', 'bar') os.environ.pop('FIXTURES_TEST_VAR', '') self.useFixture(fixture) self.assertEqual('bar', os.environ.get('FIXTURES_TEST_VAR')) def test_setup_deletes(self): - fixture = EnvironmentVariableFixture('FIXTURES_TEST_VAR') + fixture = EnvironmentVariable('FIXTURES_TEST_VAR') os.environ['FIXTURES_TEST_VAR'] = 'foo' self.useFixture(fixture) self.assertEqual(None, os.environ.get('FIXTURES_TEST_VAR')) def test_setup_overrides(self): - fixture = EnvironmentVariableFixture('FIXTURES_TEST_VAR', 'bar') + fixture = EnvironmentVariable('FIXTURES_TEST_VAR', 'bar') os.environ['FIXTURES_TEST_VAR'] = 'foo' self.useFixture(fixture) self.assertEqual('bar', os.environ.get('FIXTURES_TEST_VAR')) def test_cleanup_deletes_when_missing(self): - fixture = EnvironmentVariableFixture('FIXTURES_TEST_VAR') + fixture = EnvironmentVariable('FIXTURES_TEST_VAR') os.environ.pop('FIXTURES_TEST_VAR', '') with fixture: os.environ['FIXTURES_TEST_VAR'] = 'foo' self.assertEqual(None, os.environ.get('FIXTURES_TEST_VAR')) def test_cleanup_deletes_when_set(self): - fixture = EnvironmentVariableFixture('FIXTURES_TEST_VAR', 'bar') + fixture = EnvironmentVariable('FIXTURES_TEST_VAR', 'bar') os.environ.pop('FIXTURES_TEST_VAR', '') with fixture: os.environ['FIXTURES_TEST_VAR'] = 'foo' self.assertEqual(None, os.environ.get('FIXTURES_TEST_VAR')) def test_cleanup_restores_when_missing(self): - fixture = EnvironmentVariableFixture('FIXTURES_TEST_VAR') + fixture = EnvironmentVariable('FIXTURES_TEST_VAR') os.environ['FIXTURES_TEST_VAR'] = 'bar' with fixture: os.environ.pop('FIXTURES_TEST_VAR', '') self.assertEqual('bar', os.environ.get('FIXTURES_TEST_VAR')) def test_cleanup_restores_when_set(self): - fixture = EnvironmentVariableFixture('FIXTURES_TEST_VAR') + fixture = EnvironmentVariable('FIXTURES_TEST_VAR') os.environ['FIXTURES_TEST_VAR'] = 'bar' with fixture: os.environ['FIXTURES_TEST_VAR'] = 'quux' diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_logger.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_logger.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_logger.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_logger.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,168 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2011, Robert Collins +# +# 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. + +import logging + +from testtools import TestCase +from testtools.compat import StringIO + +from fixtures import ( + FakeLogger, + LogHandler, + TestWithFixtures, + ) + + +class FakeLoggerTest(TestCase, TestWithFixtures): + + def setUp(self): + super(FakeLoggerTest, self).setUp() + self.logger = logging.getLogger() + self.addCleanup(self.removeHandlers, self.logger) + + def removeHandlers(self, logger): + for handler in logger.handlers: + logger.removeHandler(handler) + + def test_output_property_has_output(self): + fixture = self.useFixture(FakeLogger()) + logging.info("some message") + self.assertEqual("some message\n", fixture.output) + + def test_replace_and_restore_handlers(self): + stream = StringIO() + logger = logging.getLogger() + logger.addHandler(logging.StreamHandler(stream)) + logger.setLevel(logging.INFO) + logging.info("one") + fixture = FakeLogger() + with fixture: + logging.info("two") + logging.info("three") + self.assertEqual("two\n", fixture.output) + self.assertEqual("one\nthree\n", stream.getvalue()) + + def test_preserving_existing_handlers(self): + stream = StringIO() + self.logger.addHandler(logging.StreamHandler(stream)) + self.logger.setLevel(logging.INFO) + fixture = FakeLogger(nuke_handlers=False) + with fixture: + logging.info("message") + self.assertEqual("message\n", fixture.output) + self.assertEqual("message\n", stream.getvalue()) + + def test_logging_level_restored(self): + self.logger.setLevel(logging.DEBUG) + fixture = FakeLogger(level=logging.WARNING) + with fixture: + # The fixture won't capture this, because the DEBUG level + # is lower than the WARNING one + logging.debug("debug message") + self.assertEqual(logging.WARNING, self.logger.level) + self.assertEqual("", fixture.output) + self.assertEqual(logging.DEBUG, self.logger.level) + + def test_custom_format(self): + fixture = FakeLogger(format="%(module)s") + self.useFixture(fixture) + logging.info("message") + self.assertEqual("test_logger\n", fixture.output) + + def test_logging_output_included_in_details(self): + fixture = FakeLogger() + detail_name = "pythonlogging:''" + with fixture: + content = fixture.getDetails()[detail_name] + # Output after getDetails is called is included. + logging.info('some message') + self.assertEqual("some message\n", content.as_text()) + # The old content object returns the old usage after cleanUp (not + # strictly needed but convenient). Note that no guarantee is made that + # it will work after setUp is called again. [It does on Python 2.x, not + # on 3.x] + self.assertEqual("some message\n", content.as_text()) + with fixture: + # A new one returns new output: + self.assertEqual("", fixture.getDetails()[detail_name].as_text()) + # The original content object may either fail, or return the old + # content (it must not have been reset..). + try: + self.assertEqual("some message\n", content.as_text()) + except AssertionError: + raise + except: + pass + + +class LogHandlerTest(TestCase, TestWithFixtures): + + class CustomHandler(logging.Handler): + + def __init__(self, *args, **kwargs): + """Create the instance, and add a records attribute.""" + logging.Handler.__init__(self, *args, **kwargs) + self.msgs = [] + + def emit(self, record): + self.msgs.append(record.msg) + + def setUp(self): + super(LogHandlerTest, self).setUp() + self.logger = logging.getLogger() + self.addCleanup(self.removeHandlers, self.logger) + + def removeHandlers(self, logger): + for handler in logger.handlers: + logger.removeHandler(handler) + + def test_captures_logging(self): + fixture = self.useFixture(LogHandler(self.CustomHandler())) + logging.info("some message") + self.assertEqual(["some message"], fixture.handler.msgs) + + def test_replace_and_restore_handlers(self): + stream = StringIO() + logger = logging.getLogger() + logger.addHandler(logging.StreamHandler(stream)) + logger.setLevel(logging.INFO) + logging.info("one") + fixture = LogHandler(self.CustomHandler()) + with fixture: + logging.info("two") + logging.info("three") + self.assertEqual(["two"], fixture.handler.msgs) + self.assertEqual("one\nthree\n", stream.getvalue()) + + def test_preserving_existing_handlers(self): + stream = StringIO() + self.logger.addHandler(logging.StreamHandler(stream)) + self.logger.setLevel(logging.INFO) + fixture = LogHandler(self.CustomHandler(), nuke_handlers=False) + with fixture: + logging.info("message") + self.assertEqual(["message"], fixture.handler.msgs) + self.assertEqual("message\n", stream.getvalue()) + + def test_logging_level_restored(self): + self.logger.setLevel(logging.DEBUG) + fixture = LogHandler(self.CustomHandler(), level=logging.WARNING) + with fixture: + # The fixture won't capture this, because the DEBUG level + # is lower than the WARNING one + logging.debug("debug message") + self.assertEqual(logging.WARNING, self.logger.level) + self.assertEqual([], fixture.handler.msgs) + self.assertEqual(logging.DEBUG, self.logger.level) diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_monkeypatch.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_monkeypatch.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_monkeypatch.py 2010-11-07 06:50:39.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_monkeypatch.py 2013-07-03 20:36:53.000000000 +0000 @@ -15,11 +15,10 @@ import testtools -import fixtures from fixtures import MonkeyPatch, TestWithFixtures reference = 23 - + class TestMonkeyPatch(testtools.TestCase, TestWithFixtures): def test_patch_and_restore(self): @@ -36,7 +35,6 @@ def test_patch_missing_attribute(self): fixture = MonkeyPatch( 'fixtures.tests._fixtures.test_monkeypatch.new_attr', True) - sentinel = object() self.assertFalse('new_attr' in globals()) fixture.setUp() try: @@ -61,7 +59,6 @@ fixture = MonkeyPatch( 'fixtures.tests._fixtures.test_monkeypatch.new_attr', MonkeyPatch.delete) - sentinel = object() self.assertFalse('new_attr' in globals()) fixture.setUp() try: diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_packagepath.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_packagepath.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_packagepath.py 2011-06-23 05:51:43.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_packagepath.py 2013-07-03 20:36:53.000000000 +0000 @@ -13,8 +13,6 @@ # license you chose for the specific language governing permissions and # limitations under that license. -import sys - import testtools import fixtures diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_popen.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_popen.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_popen.py 2010-10-25 20:31:20.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_popen.py 2013-08-16 03:03:01.000000000 +0000 @@ -1,6 +1,6 @@ # fixtures: Fixtures with cleanups for testing and convenience. # -# Copyright (c) 2010, Robert Collins +# Copyright (c) 2010, 2011, Robert Collins # # 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 @@ -13,20 +13,22 @@ # license you chose for the specific language governing permissions and # limitations under that license. -import StringIO import subprocess import testtools +from testtools.compat import ( + _b, + BytesIO, + ) -import fixtures -from fixtures import PopenFixture, TestWithFixtures +from fixtures import FakePopen, TestWithFixtures from fixtures._fixtures.popen import FakeProcess -class TestPopenFixture(testtools.TestCase, TestWithFixtures): +class TestFakePopen(testtools.TestCase, TestWithFixtures): def test_installs_restores_global(self): - fixture = PopenFixture() + fixture = FakePopen() popen = subprocess.Popen fixture.setUp() try: @@ -36,7 +38,7 @@ self.assertEqual(subprocess.Popen, popen) def test___call___is_recorded(self): - fixture = self.useFixture(PopenFixture()) + fixture = self.useFixture(FakePopen()) proc = fixture(['foo', 'bar'], 1, None, 'in', 'out', 'err') self.assertEqual(1, len(fixture.procs)) self.assertEqual(dict(args=['foo', 'bar'], bufsize=1, executable=None, @@ -45,10 +47,31 @@ def test_inject_content_stdout(self): def get_info(args): return {'stdout': 'stdout'} - fixture = self.useFixture(PopenFixture(get_info)) + fixture = self.useFixture(FakePopen(get_info)) proc = fixture(['foo']) self.assertEqual('stdout', proc.stdout) + def test_handles_all_2_7_args(self): + all_args = dict( + args="args", bufsize="bufsize", executable="executable", + stdin="stdin", stdout="stdout", stderr="stderr", + preexec_fn="preexec_fn", close_fds="close_fds", shell="shell", + cwd="cwd", env="env", universal_newlines="universal_newlines", + startupinfo="startupinfo", creationflags="creationflags") + def get_info(proc_args): + self.assertEqual(all_args, proc_args) + return {} + fixture = self.useFixture(FakePopen(get_info)) + proc = fixture(**all_args) + + def test_custom_returncode(self): + def get_info(proc_args): + return dict(returncode=1) + proc = self.useFixture(FakePopen(get_info))(['foo']) + self.assertEqual(None, proc.returncode) + self.assertEqual(1, proc.wait()) + self.assertEqual(1, proc.returncode) + class TestFakeProcess(testtools.TestCase): @@ -63,6 +86,6 @@ self.assertEqual(0, proc.returncode) def test_communicate_with_out(self): - proc = FakeProcess({}, {'stdout': StringIO.StringIO('foo')}) - self.assertEqual(('foo', ''), proc.communicate()) + proc = FakeProcess({}, {'stdout': BytesIO(_b('foo'))}) + self.assertEqual((_b('foo'), ''), proc.communicate()) self.assertEqual(0, proc.returncode) diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_pythonpackage.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_pythonpackage.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_pythonpackage.py 2010-11-07 06:50:39.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_pythonpackage.py 2013-07-03 20:36:53.000000000 +0000 @@ -16,11 +16,11 @@ import os.path import testtools +from testtools.compat import _b + +from fixtures import PythonPackage, TestWithFixtures -import fixtures -from fixtures import PythonPackage, TempDir, TestWithFixtures - class TestPythonPackage(testtools.TestCase, TestWithFixtures): def test_has_tempdir(self): @@ -32,18 +32,18 @@ fixture.cleanUp() def test_writes_package(self): - fixture = PythonPackage('foo', [('bar.py', 'woo')]) + fixture = PythonPackage('foo', [('bar.py', _b('woo'))]) fixture.setUp() try: - self.assertEqual('', file(os.path.join(fixture.base, 'foo', + self.assertEqual('', open(os.path.join(fixture.base, 'foo', '__init__.py')).read()) - self.assertEqual('woo', file(os.path.join(fixture.base, 'foo', + self.assertEqual('woo', open(os.path.join(fixture.base, 'foo', 'bar.py')).read()) finally: fixture.cleanUp() def test_no__init__(self): - fixture = PythonPackage('foo', [('bar.py', 'woo')], init=False) + fixture = PythonPackage('foo', [('bar.py', _b('woo'))], init=False) fixture.setUp() try: self.assertFalse(os.path.exists(os.path.join(fixture.base, 'foo', diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_pythonpath.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_pythonpath.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_pythonpath.py 2011-03-19 08:12:47.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_pythonpath.py 2013-07-03 20:36:53.000000000 +0000 @@ -17,7 +17,6 @@ import testtools -import fixtures from fixtures import ( PythonPathEntry, TempDir, diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_streams.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_streams.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_streams.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_streams.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,105 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2012, Robert Collins +# +# 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 testtools.compat import ( + _b, + _u, + ) +from testtools.matchers import Contains + +from fixtures import ( + ByteStream, + DetailStream, + StringStream, + ) + + +class DetailStreamTest(TestCase): + + def test_doc_mentions_deprecated(self): + self.assertThat(DetailStream.__doc__, Contains('Deprecated')) + + +class TestByteStreams(TestCase): + + def test_empty_detail_stream(self): + detail_name = 'test' + fixture = ByteStream(detail_name) + with fixture: + content = fixture.getDetails()[detail_name] + self.assertEqual(_u(""), content.as_text()) + + def test_stream_content_in_details(self): + detail_name = 'test' + fixture = ByteStream(detail_name) + with fixture: + stream = fixture.stream + content = fixture.getDetails()[detail_name] + # Output after getDetails is called is included. + stream.write(_b("testing 1 2 3")) + self.assertEqual("testing 1 2 3", content.as_text()) + + def test_stream_content_reset(self): + detail_name = 'test' + fixture = ByteStream(detail_name) + with fixture: + stream = fixture.stream + content = fixture.getDetails()[detail_name] + stream.write(_b("testing 1 2 3")) + with fixture: + # The old content object returns the old usage + self.assertEqual(_u("testing 1 2 3"), content.as_text()) + content = fixture.getDetails()[detail_name] + # A new fixture returns the new output: + stream = fixture.stream + stream.write(_b("1 2 3 testing")) + self.assertEqual(_u("1 2 3 testing"), content.as_text()) + + +class TestStringStreams(TestCase): + + def test_empty_detail_stream(self): + detail_name = 'test' + fixture = StringStream(detail_name) + with fixture: + content = fixture.getDetails()[detail_name] + self.assertEqual(_u(""), content.as_text()) + + def test_stream_content_in_details(self): + detail_name = 'test' + fixture = StringStream(detail_name) + with fixture: + stream = fixture.stream + content = fixture.getDetails()[detail_name] + # Output after getDetails is called is included. + stream.write(_u("testing 1 2 3")) + self.assertEqual("testing 1 2 3", content.as_text()) + + def test_stream_content_reset(self): + detail_name = 'test' + fixture = StringStream(detail_name) + with fixture: + stream = fixture.stream + content = fixture.getDetails()[detail_name] + stream.write(_u("testing 1 2 3")) + with fixture: + # The old content object returns the old usage + self.assertEqual(_u("testing 1 2 3"), content.as_text()) + content = fixture.getDetails()[detail_name] + # A new fixture returns the new output: + stream = fixture.stream + stream.write(_u("1 2 3 testing")) + self.assertEqual(_u("1 2 3 testing"), content.as_text()) diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_tempdir.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_tempdir.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_tempdir.py 2010-11-07 06:50:39.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_tempdir.py 2013-07-03 20:36:53.000000000 +0000 @@ -14,14 +14,18 @@ # limitations under that license. import os +import tempfile import testtools +from testtools.matchers import StartsWith -import fixtures -from fixtures import TempDir, TestWithFixtures +from fixtures import ( + NestedTempfile, + TempDir, + ) - -class TestTempDir(testtools.TestCase, TestWithFixtures): + +class TestTempDir(testtools.TestCase): def test_basic(self): fixture = TempDir() @@ -34,3 +38,59 @@ finally: fixture.cleanUp() self.assertFalse(os.path.isdir(path)) + + def test_under_dir(self): + root = self.useFixture(TempDir()).path + fixture = TempDir(root) + fixture.setUp() + with fixture: + self.assertThat(fixture.path, StartsWith(root)) + + def test_join(self): + temp_dir = self.useFixture(TempDir()) + root = temp_dir.path + relpath = 'foo/bar/baz' + self.assertEqual( + os.path.join(root, relpath), temp_dir.join(relpath)) + + def test_join_multiple_children(self): + temp_dir = self.useFixture(TempDir()) + root = temp_dir.path + self.assertEqual( + os.path.join(root, 'foo', 'bar', 'baz'), + temp_dir.join('foo', 'bar', 'baz')) + + def test_join_naughty_children(self): + temp_dir = self.useFixture(TempDir()) + root = temp_dir.path + self.assertEqual( + os.path.abspath(os.path.join(root, '..', 'bar', 'baz')), + temp_dir.join('..', 'bar', 'baz')) + + +class NestedTempfileTest(testtools.TestCase): + """Tests for `NestedTempfile`.""" + + def test_normal(self): + # The temp directory is removed when the context is exited. + starting_tempdir = tempfile.gettempdir() + with NestedTempfile(): + self.assertEqual(tempfile.tempdir, tempfile.gettempdir()) + self.assertNotEqual(starting_tempdir, tempfile.tempdir) + self.assertTrue(os.path.isdir(tempfile.tempdir)) + nested_tempdir = tempfile.tempdir + self.assertEqual(tempfile.tempdir, tempfile.gettempdir()) + self.assertEqual(starting_tempdir, tempfile.tempdir) + self.assertFalse(os.path.isdir(nested_tempdir)) + + def test_exception(self): + # The temp directory is removed when the context is exited, even if + # the code running in context raises an exception. + class ContrivedException(Exception): + pass + try: + with NestedTempfile(): + nested_tempdir = tempfile.tempdir + raise ContrivedException + except ContrivedException: + self.assertFalse(os.path.isdir(nested_tempdir)) diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_temphomedir.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_temphomedir.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_temphomedir.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_temphomedir.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,46 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2011 Canonical Ltd. +# +# 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. + +import os + +import testtools +from testtools.matchers import StartsWith + +from fixtures import ( + TempDir, + TempHomeDir, + ) + +class TestTempDir(testtools.TestCase): + + def test_basic(self): + fixture = TempHomeDir() + sentinel = object() + self.assertEqual(sentinel, getattr(fixture, 'path', sentinel)) + fixture.setUp() + try: + path = fixture.path + self.assertTrue(os.path.isdir(path)) + self.assertEqual(path, os.environ.get("HOME")) + finally: + fixture.cleanUp() + self.assertFalse(os.path.isdir(path)) + + def test_under_dir(self): + root = self.useFixture(TempDir()).path + fixture = TempHomeDir(root) + fixture.setUp() + with fixture: + self.assertThat(fixture.path, StartsWith(root)) diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_timeout.py python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_timeout.py --- python-fixtures-0.3.6/lib/fixtures/tests/_fixtures/test_timeout.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/_fixtures/test_timeout.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,66 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (C) 2011, Martin Pool +# +# 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. + +import signal +import time + +import testtools +from testtools.testcase import ( + TestSkipped, + ) + +import fixtures + + +def sample_timeout_passes(): + with fixtures.Timeout(100, gentle=True): + pass # Timeout shouldn't fire + +def sample_long_delay_with_gentle_timeout(): + with fixtures.Timeout(1, gentle=True): + time.sleep(100) # Expected to be killed here. + +def sample_long_delay_with_harsh_timeout(): + with fixtures.Timeout(1, gentle=False): + time.sleep(100) # Expected to be killed here. + + +class TestTimeout(testtools.TestCase, fixtures.TestWithFixtures): + + def requireUnix(self): + if getattr(signal, 'alarm', None) is None: + raise TestSkipped("no alarm() function") + + def test_timeout_passes(self): + # This can pass even on Windows - the test is skipped. + sample_timeout_passes() + + def test_timeout_gentle(self): + self.requireUnix() + self.assertRaises( + fixtures.TimeoutException, + sample_long_delay_with_gentle_timeout) + + def test_timeout_harsh(self): + self.requireUnix() + # This will normally kill the whole process, which would be + # inconvenient. Let's hook the alarm here so we can observe it. + self.got_alarm = False + def sigalrm_handler(signum, frame): + self.got_alarm = True + old_handler = signal.signal(signal.SIGALRM, sigalrm_handler) + self.addCleanup(signal.signal, signal.SIGALRM, old_handler) + sample_long_delay_with_harsh_timeout() + self.assertTrue(self.got_alarm) diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/__init__.py python-fixtures-0.3.14/lib/fixtures/tests/__init__.py --- python-fixtures-0.3.6/lib/fixtures/tests/__init__.py 2010-10-25 20:31:20.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/__init__.py 2013-07-03 20:36:53.000000000 +0000 @@ -21,7 +21,6 @@ def test_suite(): - result = unittest.TestSuite() standard_tests = unittest.TestSuite() loader = unittest.TestLoader() return load_tests(loader, standard_tests, None) @@ -29,14 +28,20 @@ def load_tests(loader, standard_tests, pattern): test_modules = [ + 'callmany', 'fixture', 'testcase', ] prefix = "fixtures.tests.test_" test_mod_names = [prefix + test_module for test_module in test_modules] standard_tests.addTests(loader.loadTestsFromNames(test_mod_names)) - standard_tests.addTests(fixtures.tests._fixtures.load_tests( - loader, loader.loadTestsFromName('fixtures.tests._fixtures'), pattern)) + if sys.version_info >= (2, 7): + # 2.7 calls load_tests for us + standard_tests.addTests(loader.loadTestsFromName('fixtures.tests._fixtures')) + else: + # We need to call it ourselves. + standard_tests.addTests(fixtures.tests._fixtures.load_tests( + loader, loader.loadTestsFromName('fixtures.tests._fixtures'), pattern)) doctest.set_unittest_reportflags(doctest.REPORT_ONLY_FIRST_FAILURE) standard_tests.addTest(doctest.DocFileSuite("../../../README")) return standard_tests diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/test_callmany.py python-fixtures-0.3.14/lib/fixtures/tests/test_callmany.py --- python-fixtures-0.3.6/lib/fixtures/tests/test_callmany.py 1970-01-01 00:00:00.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/test_callmany.py 2013-07-03 20:36:53.000000000 +0000 @@ -0,0 +1,68 @@ +# fixtures: Fixtures with cleanups for testing and convenience. +# +# Copyright (c) 2010, Robert Collins +# +# 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. + +import types + +import testtools + +from fixtures.callmany import CallMany + + +class TestCallMany(testtools.TestCase): + + def test__call__raise_errors_false_callsall_returns_exceptions(self): + calls = [] + def raise_exception1(): + calls.append('1') + raise Exception('woo') + def raise_exception2(): + calls.append('2') + raise Exception('woo') + call = CallMany() + call.push(raise_exception2) + call.push(raise_exception1) + exceptions = call(raise_errors=False) + self.assertEqual(['1', '2'], calls) + # There should be two exceptions + self.assertEqual(2, len(exceptions)) + # They should be a sys.exc_info tuple. + self.assertEqual(3, len(exceptions[0])) + type, value, tb = exceptions[0] + self.assertEqual(Exception, type) + self.assertIsInstance(value, Exception) + self.assertEqual(('woo',), value.args) + self.assertIsInstance(tb, types.TracebackType) + + def test_exit_propogates_exceptions(self): + call = CallMany() + call.__enter__() + self.assertEqual(False, call.__exit__(None, None, None)) + + def test_exit_runs_all_raises_first_exception(self): + calls = [] + def raise_exception1(): + calls.append('1') + raise Exception('woo') + def raise_exception2(): + calls.append('2') + raise Exception('hoo') + call = CallMany() + call.push(raise_exception2) + call.push(raise_exception1) + call.__enter__() + exc = self.assertRaises(Exception, call.__exit__, None, None, None) + self.assertEqual(('woo',), exc.args[0][1].args) + self.assertEqual(('hoo',), exc.args[1][1].args) + self.assertEqual(['1', '2'], calls) diff -Nru python-fixtures-0.3.6/lib/fixtures/tests/test_fixture.py python-fixtures-0.3.14/lib/fixtures/tests/test_fixture.py --- python-fixtures-0.3.6/lib/fixtures/tests/test_fixture.py 2011-06-23 07:52:27.000000000 +0000 +++ python-fixtures-0.3.14/lib/fixtures/tests/test_fixture.py 2013-07-03 20:36:53.000000000 +0000 @@ -13,7 +13,6 @@ # license you chose for the specific language governing permissions and # limitations under that license. -import sys import types import testtools @@ -29,6 +28,8 @@ "gather_details() is not available.") +# Note: the cleanup related tests are strictly speaking redundant, IFF they are +# replaced with contract tests for correct use of CallMany. class TestFixture(testtools.TestCase): def test_resetCallsSetUpCleanUp(self): @@ -102,7 +103,7 @@ self.addCleanup(raise_exception2) self.addCleanup(raise_exception1) fixture = FixtureWithException() - ctx = fixture.__enter__() + fixture.__enter__() exc = self.assertRaises(Exception, fixture.__exit__, None, None, None) self.assertEqual(('woo',), exc.args[0][1].args) self.assertEqual(('hoo',), exc.args[1][1].args) @@ -163,6 +164,18 @@ child.addDetail('foo', 'content') self.assertEqual({}, parent.getDetails()) + def test_duplicate_details_are_disambiguated(self): + parent = fixtures.Fixture() + with parent: + parent.addDetail('foo', 'parent-content') + child = fixtures.Fixture() + parent.useFixture(child) + # Note that we add the detail *after* using the fixture: the parent + # has to query just-in-time. + child.addDetail('foo', 'child-content') + self.assertEqual({'foo': 'parent-content', + 'foo-1': 'child-content',}, parent.getDetails()) + def test_addDetail(self): fixture = fixtures.Fixture() with fixture: diff -Nru python-fixtures-0.3.6/NEWS python-fixtures-0.3.14/NEWS --- python-fixtures-0.3.6/NEWS 2011-06-23 08:14:47.000000000 +0000 +++ python-fixtures-0.3.14/NEWS 2013-08-16 03:03:21.000000000 +0000 @@ -3,8 +3,139 @@ ---------------------- -IN DEVELOPMENT -~~~~~~~~~~~~~~ +NEXT +~~~~ + +0.3.14 +~~~~~~ + +CHANGES +------- + +* ``FakePopen`` can now override the returncode attribute. + (Robert Collins) + +0.3.13 +~~~~~~ + +CHANGES +------- + +* Documentation hopefully covers ``TestWithFixtures`` a little better. + (Robert Collins, #1102688) + +* ``FakePopen`` now accepts all the parameters available in Python 2.7. + (Robert Collins) + +* ``FakePopen`` now only passes parameters to the get_info routine if the + caller supplied them. (Robert Collins) + +* ``setup.py`` now lists the ``testtools`` dependency which was missing. + (Robert Collins, #1103823) + +0.3.12 +~~~~~~ + +Brown bag fix up of StringStream from 0.3.11. + +0.3.11 +~~~~~~ + +CHANGES +------- + +* ``DetailStream`` was ambiguous about whether it handled bytes or characters, + which matters a lot for Python3. It now is deprecated with ByteStream and + StringStream replacing it. (Robert Collins) + +* Fixtures is now Python3 compatible. (Robert Collins) + +* ``FakeLogger`` has been split out into a ``LogHandler`` fixture that can + inject arbitrary handlers, giving more flexability. (Jonathan Lange) + +* pydoc is recommended as a source of info about fixtures. + (Robert Collins, #812845) + +* The docs for fixtures have been updated to cover the full API. + (Robert Collins, #1071649) + +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 + to a temporary directory. (Jonathan Lange) + +* 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 +~~~~~ + +New ``TempHomeDir`` fixture and more log output included in ``FakeLogger``. + +CHANGES: + +* New TempHomeDir fixture to create and activate a temporary home directory. + (James Westby) + +* ``FakeLogger`` now includes the output from python logging - the .output + attribute as a content object in getDetails, so the logs will automatically + be included in failed test output (or other similar circumstances). + (Francesco Banconi) + +0.3.8 +~~~~~ + +Simpler names for a number of fixtures, and two new fixtures NestedTempfile and +Timeout. See the manual for more information. + +CHANGES: + +* EnvironmentVariable now upcalls via super(). + (Jonathan Lange, #881120) + +* EnvironmentVariableFixture, LoggerFixture, PopenFixture renamed to + EnvironmentVariable, FakeLogger and FakePopen respectively. All are still + available under their old, deprecated names. (Jonathan Lange, #893539) + +* gather_details fixed to handle the case where two child fixtures have the + same detail name. (Jonathan Lange, #895652) + +* ``NestedTempfile`` which will change the default path for tempfile temporary + file / directory creation. (Gavin Panella) + +* New Timeout fixture. (Martin Pool) + +0.3.7 +~~~~~ + +CHANGES: + +* New fixture LoggerFixture which replaces a logging module logger. + (Free Ekanayaka) + +* On Python 2.7 and above the _fixtures tests are no longer run twice. + (Robert Collins) + +* Python 3 now supported. (Jonathan Lange, #816665) + +* ``TempDir`` supports creating the temporary directory under a specific path. + An example of where this is useful would be if you have some specific long + lived temporary items and need to avoid running afoul of tmpreaper. + (Robert Collins, #830757) + +* Updated to match the changed ``gather_details`` API in testtools. See #801027. + This is an incompatible change in testtools and requires testtools 0.9.12. + (Jonathan Lange) 0.3.6 ~~~~~ @@ -25,7 +156,7 @@ useFixture. (RobertCollins, #780806) * New fixture ``PackagePathEntry`` which patches the path of an existing - package, allowing importing part of it from aonther directory. + package, allowing importing part of it from another directory. (Robert Collins) * New fixture ``PythonPathEntry`` which patches sys.path. diff -Nru python-fixtures-0.3.6/PKG-INFO python-fixtures-0.3.14/PKG-INFO --- python-fixtures-0.3.6/PKG-INFO 2011-06-23 08:23:27.000000000 +0000 +++ python-fixtures-0.3.14/PKG-INFO 2013-08-16 03:04:44.000000000 +0000 @@ -1,6 +1,6 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: fixtures -Version: 0.3.6 +Version: 0.3.14 Summary: Fixtures, reusable state for writing clean tests and more. Home-page: https://launchpad.net/python-fixtures Author: Robert Collins @@ -33,17 +33,17 @@ Dependencies ============ - * Python 2.4+ + * Python 2.6+ This is the base language fixtures is written in and for. - * testtools 0.9.8 or newer. + * 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). For use in a unit test suite using the included glue, one of: - * Python 2.7 + * Python 2.7+ * unittest2 @@ -78,6 +78,9 @@ specific to the fixture. For instance, a fixture representing a directory that can be used for temporary files might have a attribute 'path'. + Most fixtures have complete ``pydoc`` documentation, so be sure to check + ``pydoc fixtures`` for usage information. + Creating Fixtures ================= @@ -95,6 +98,25 @@ This will initialize frobnozzle when setUp is called, and when cleanUp is called get rid of the frobnozzle attribute. + If your fixture has diagnostic data - for instance the log file of an + application server, or log messages, it can expose that by creating a content + object (``testtools.content.Content``) and calling ``addDetail``. + + >>> from testtools.content import text_content + >>> class WithLog(fixtures.Fixture): + ... def setUp(self): + ... super(WithLog, self).setUp() + ... self.addDetail('message', text_content('foo bar baz')) + + The method ``useFixture`` will use another fixture, call ``setUp`` on it, call + ``self.addCleanup(thefixture.cleanUp)``, attach any details from it and return + the fixture. This allows simple composition of different fixtures. + + >>> class ReusingFixture(fixtures.Fixture): + ... def setUp(self): + ... super(ReusingFixture, self).setUp() + ... self.noddy = self.useFixture(NoddyFixture()) + There is a helper for adapting a function or function pair into Fixtures. it puts the result of the function in fn_result:: @@ -107,7 +129,7 @@ ... shutil.rmtree(fixture) >>> fixture = fixtures.FunctionFixture(setup_function, teardown_function) >>> fixture.setUp() - >>> print os.path.isdir(fixture.fn_result) + >>> print (os.path.isdir(fixture.fn_result)) True >>> fixture.cleanUp() @@ -115,11 +137,11 @@ >>> fixture = fixtures.FunctionFixture(tempfile.mkdtemp, shutil.rmtree) >>> fixture.setUp() - >>> print os.path.isdir(fixture.fn_result) + >>> print (os.path.isdir(fixture.fn_result)) True >>> fixture.cleanUp() - Another variation is is MethodFixture which is useful for adapting alternate + Another variation is MethodFixture which is useful for adapting alternate fixture implementations to Fixture:: >>> class MyServer: @@ -159,7 +181,10 @@ >>> import unittest Note that we use testtools TestCase here as we need to guarantee a - TestCase.addCleanup method. + TestCase.addCleanup method in this doctest. Unittest2 - Python2.7 and above - + also have ``addCleanup``. testtools has it's own implementation of + ``useFixture`` so there is no need to use ``fixtures.TestWithFixtures`` with + ``testtools.TestCase``. >>> class NoddyTest(testtools.TestCase, fixtures.TestWithFixtures): ... def test_example(self): @@ -167,14 +192,14 @@ ... self.assertEqual(42, fixture.frobnozzle) >>> result = unittest.TestResult() >>> _ = NoddyTest('test_example').run(result) - >>> print result.wasSuccessful() + >>> print (result.wasSuccessful()) True Fixtures implement the context protocol, so you can also use a fixture as a context manager:: >>> with fixtures.FunctionFixture(setup_function, teardown_function) as fixture: - ... print os.path.isdir(fixture.fn_result) + ... print (os.path.isdir(fixture.fn_result)) True When multiple cleanups error, fixture.cleanUp() will raise a wrapper exception @@ -193,8 +218,16 @@ ... fixture.cleanUp() ... except MultipleExceptions: ... exc_info = sys.exc_info() - >>> print exc_info[1].args[0][0] - + >>> print (exc_info[1].args[0][0].__name__) + ZeroDivisionError + + Fixtures often expose diagnostic details that can be useful for tracking down + issues. The ``getDetails`` method will return a dict of all the attached + details. Each detail object is an instance of ``testtools.content.Content``. + + >>> with WithLog() as l: + ... print(l.getDetails()['message'].as_text()) + foo bar baz Shared Dependencies +++++++++++++++++++ @@ -274,13 +307,43 @@ 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. - EnvironmentVariableFixture - ++++++++++++++++++++++++++ + ByteStream + ++++++++++ + + Trivial adapter to make a BytesIO (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.StringStream('my-content') + >>> fixture.setUp() + >>> with fixtures.MonkeyPatch('sys.something', fixture.stream): + ... pass + >>> fixture.cleanUp() + + EnvironmentVariable + +++++++++++++++++++ Isolate your code from environmental variables, delete them or set them to a new value. - >>> fixture = fixtures.EnvironmentVariableFixture('HOME') + >>> fixture = fixtures.EnvironmentVariable('HOME') + + FakeLogger + ++++++++++ + + Isolate your code from an external logging configuration - so that your test + gets the output from logged messages, but they don't go to e.g. the console. + + >>> fixture = fixtures.FakeLogger() + + FakePopen + +++++++++ + + Pretend to run an external command rather than needing it to be present to run + tests. + + >>> from testtools.compat import BytesIO + >>> fixture = fixtures.FakePopen(lambda _:{'stdout': BytesIO('foobar')}) MonkeyPatch +++++++++++ @@ -291,6 +354,16 @@ ... pass >>> fixture = fixtures.MonkeyPatch('__builtin__.open', fake_open) + NestedTempfile + ++++++++++++++ + + Change the default directory that the tempfile module places temporary files + and directories in. This can be useful for containing the noise created by + code which doesn't clean up its temporary files. This does not affect + temporary file creation where an explicit containing directory was provided. + + >>> fixture = fixtures.NestedTempfile() + PackagePathEntry ++++++++++++++++ @@ -300,15 +373,6 @@ >>> fixture = fixtures.PackagePathEntry('package/name', '/foo/bar') - PopenFixture - ++++++++++++ - - Pretend to run an external command rather than needing it to be present to run - tests. - - >>> from StringIO import StringIO - >>> fixture = fixtures.PopenFixture(lambda _:{'stdout': StringIO('foobar')}) - PythonPackage +++++++++++++ @@ -326,6 +390,19 @@ >>> fixture = fixtures.PythonPathEntry('/foo/bar') + StringStream + ++++++++++++ + + 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.StringStream('stdout') + >>> fixture.setUp() + >>> with fixtures.MonkeyPatch('sys.stdout', fixture.stream): + ... pass + >>> fixture.cleanUp() + TempDir +++++++ @@ -336,6 +413,38 @@ The created directory is stored in the ``path`` attribute of the fixture after setUp. + TempHomeDir + +++++++++++ + + Create a temporary directory and set it as $HOME in the environment. + + >>> fixture = fixtures.TempHomeDir() + + The created directory is stored in the ``path`` attribute of the fixture after + setUp. + + The environment will now have $HOME set to the same path, and the value + will be returned to its previous value after tearDown. + + Timeout + +++++++ + + Aborts if the covered code takes more than a specified number of whole wall-clock + seconds. + + There are two possibilities, controlled by the 'gentle' argument: when gentle, + an exception will be raised and the test (or other covered code) will fail. + When not gentle, the entire process will be terminated, which is less clean, + but more likely to break hangs where no Python code is running. + + *Caution:* Only one timeout can be active at any time across all threads in a + single process. Using more than one has undefined results. (This could be + improved by chaining alarms.) + + *Note:* Currently supported only on Unix because it relies on the ``alarm`` + system call. + +Keywords: fixture fixtures unittest contextmanager Platform: UNKNOWN Classifier: Development Status :: 6 - Mature Classifier: Intended Audience :: Developers @@ -343,5 +452,7 @@ Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Quality Assurance Classifier: Topic :: Software Development :: Testing +Requires: testtools diff -Nru python-fixtures-0.3.6/README python-fixtures-0.3.14/README --- python-fixtures-0.3.6/README 2011-06-23 05:53:39.000000000 +0000 +++ python-fixtures-0.3.14/README 2013-08-16 00:48:54.000000000 +0000 @@ -25,17 +25,17 @@ Dependencies ============ -* Python 2.4+ +* Python 2.6+ This is the base language fixtures is written in and for. -* testtools 0.9.8 or newer. +* 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). For use in a unit test suite using the included glue, one of: -* Python 2.7 +* Python 2.7+ * unittest2 @@ -70,6 +70,9 @@ specific to the fixture. For instance, a fixture representing a directory that can be used for temporary files might have a attribute 'path'. +Most fixtures have complete ``pydoc`` documentation, so be sure to check +``pydoc fixtures`` for usage information. + Creating Fixtures ================= @@ -87,6 +90,25 @@ This will initialize frobnozzle when setUp is called, and when cleanUp is called get rid of the frobnozzle attribute. +If your fixture has diagnostic data - for instance the log file of an +application server, or log messages, it can expose that by creating a content +object (``testtools.content.Content``) and calling ``addDetail``. + + >>> from testtools.content import text_content + >>> class WithLog(fixtures.Fixture): + ... def setUp(self): + ... super(WithLog, self).setUp() + ... self.addDetail('message', text_content('foo bar baz')) + +The method ``useFixture`` will use another fixture, call ``setUp`` on it, call +``self.addCleanup(thefixture.cleanUp)``, attach any details from it and return +the fixture. This allows simple composition of different fixtures. + + >>> class ReusingFixture(fixtures.Fixture): + ... def setUp(self): + ... super(ReusingFixture, self).setUp() + ... self.noddy = self.useFixture(NoddyFixture()) + There is a helper for adapting a function or function pair into Fixtures. it puts the result of the function in fn_result:: @@ -99,7 +121,7 @@ ... shutil.rmtree(fixture) >>> fixture = fixtures.FunctionFixture(setup_function, teardown_function) >>> fixture.setUp() - >>> print os.path.isdir(fixture.fn_result) + >>> print (os.path.isdir(fixture.fn_result)) True >>> fixture.cleanUp() @@ -107,11 +129,11 @@ >>> fixture = fixtures.FunctionFixture(tempfile.mkdtemp, shutil.rmtree) >>> fixture.setUp() - >>> print os.path.isdir(fixture.fn_result) + >>> print (os.path.isdir(fixture.fn_result)) True >>> fixture.cleanUp() -Another variation is is MethodFixture which is useful for adapting alternate +Another variation is MethodFixture which is useful for adapting alternate fixture implementations to Fixture:: >>> class MyServer: @@ -151,7 +173,10 @@ >>> import unittest Note that we use testtools TestCase here as we need to guarantee a -TestCase.addCleanup method. +TestCase.addCleanup method in this doctest. Unittest2 - Python2.7 and above - +also have ``addCleanup``. testtools has it's own implementation of +``useFixture`` so there is no need to use ``fixtures.TestWithFixtures`` with +``testtools.TestCase``. >>> class NoddyTest(testtools.TestCase, fixtures.TestWithFixtures): ... def test_example(self): @@ -159,14 +184,14 @@ ... self.assertEqual(42, fixture.frobnozzle) >>> result = unittest.TestResult() >>> _ = NoddyTest('test_example').run(result) - >>> print result.wasSuccessful() + >>> print (result.wasSuccessful()) True Fixtures implement the context protocol, so you can also use a fixture as a context manager:: >>> with fixtures.FunctionFixture(setup_function, teardown_function) as fixture: - ... print os.path.isdir(fixture.fn_result) + ... print (os.path.isdir(fixture.fn_result)) True When multiple cleanups error, fixture.cleanUp() will raise a wrapper exception @@ -185,8 +210,16 @@ ... fixture.cleanUp() ... except MultipleExceptions: ... exc_info = sys.exc_info() - >>> print exc_info[1].args[0][0] - + >>> print (exc_info[1].args[0][0].__name__) + ZeroDivisionError + +Fixtures often expose diagnostic details that can be useful for tracking down +issues. The ``getDetails`` method will return a dict of all the attached +details. Each detail object is an instance of ``testtools.content.Content``. + + >>> with WithLog() as l: + ... print(l.getDetails()['message'].as_text()) + foo bar baz Shared Dependencies +++++++++++++++++++ @@ -266,13 +299,43 @@ 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. -EnvironmentVariableFixture -++++++++++++++++++++++++++ +ByteStream +++++++++++ + +Trivial adapter to make a BytesIO (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.StringStream('my-content') + >>> fixture.setUp() + >>> with fixtures.MonkeyPatch('sys.something', fixture.stream): + ... pass + >>> fixture.cleanUp() + +EnvironmentVariable ++++++++++++++++++++ Isolate your code from environmental variables, delete them or set them to a new value. - >>> fixture = fixtures.EnvironmentVariableFixture('HOME') + >>> fixture = fixtures.EnvironmentVariable('HOME') + +FakeLogger +++++++++++ + +Isolate your code from an external logging configuration - so that your test +gets the output from logged messages, but they don't go to e.g. the console. + + >>> fixture = fixtures.FakeLogger() + +FakePopen ++++++++++ + +Pretend to run an external command rather than needing it to be present to run +tests. + + >>> from testtools.compat import BytesIO + >>> fixture = fixtures.FakePopen(lambda _:{'stdout': BytesIO('foobar')}) MonkeyPatch +++++++++++ @@ -283,6 +346,16 @@ ... pass >>> fixture = fixtures.MonkeyPatch('__builtin__.open', fake_open) +NestedTempfile +++++++++++++++ + +Change the default directory that the tempfile module places temporary files +and directories in. This can be useful for containing the noise created by +code which doesn't clean up its temporary files. This does not affect +temporary file creation where an explicit containing directory was provided. + + >>> fixture = fixtures.NestedTempfile() + PackagePathEntry ++++++++++++++++ @@ -292,15 +365,6 @@ >>> fixture = fixtures.PackagePathEntry('package/name', '/foo/bar') -PopenFixture -++++++++++++ - -Pretend to run an external command rather than needing it to be present to run -tests. - - >>> from StringIO import StringIO - >>> fixture = fixtures.PopenFixture(lambda _:{'stdout': StringIO('foobar')}) - PythonPackage +++++++++++++ @@ -318,6 +382,19 @@ >>> fixture = fixtures.PythonPathEntry('/foo/bar') +StringStream +++++++++++++ + +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.StringStream('stdout') + >>> fixture.setUp() + >>> with fixtures.MonkeyPatch('sys.stdout', fixture.stream): + ... pass + >>> fixture.cleanUp() + TempDir +++++++ @@ -327,3 +404,34 @@ The created directory is stored in the ``path`` attribute of the fixture after setUp. + +TempHomeDir ++++++++++++ + +Create a temporary directory and set it as $HOME in the environment. + + >>> fixture = fixtures.TempHomeDir() + +The created directory is stored in the ``path`` attribute of the fixture after +setUp. + +The environment will now have $HOME set to the same path, and the value +will be returned to its previous value after tearDown. + +Timeout ++++++++ + +Aborts if the covered code takes more than a specified number of whole wall-clock +seconds. + +There are two possibilities, controlled by the 'gentle' argument: when gentle, +an exception will be raised and the test (or other covered code) will fail. +When not gentle, the entire process will be terminated, which is less clean, +but more likely to break hangs where no Python code is running. + +*Caution:* Only one timeout can be active at any time across all threads in a +single process. Using more than one has undefined results. (This could be +improved by chaining alarms.) + +*Note:* Currently supported only on Unix because it relies on the ``alarm`` +system call. diff -Nru python-fixtures-0.3.6/setup.py python-fixtures-0.3.14/setup.py --- python-fixtures-0.3.6/setup.py 2011-06-23 08:21:00.000000000 +0000 +++ python-fixtures-0.3.14/setup.py 2013-08-16 03:04:31.000000000 +0000 @@ -3,11 +3,12 @@ from distutils.core import setup import os.path -description = file(os.path.join(os.path.dirname(__file__), 'README'), 'rb').read() +description = open(os.path.join(os.path.dirname(__file__), 'README'), 'rt').read() setup(name="fixtures", - version="0.3.6", + version="0.3.14", 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", @@ -22,7 +23,11 @@ 'License :: OSI Approved :: Apache Software License', 'Operating System :: OS Independent', 'Programming Language :: Python', + 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Quality Assurance', 'Topic :: Software Development :: Testing', ], + requires = [ + 'testtools', + ], ) diff -Nru python-fixtures-0.3.6/.testr.conf python-fixtures-0.3.14/.testr.conf --- python-fixtures-0.3.6/.testr.conf 2014-07-19 23:30:23.000000000 +0000 +++ python-fixtures-0.3.14/.testr.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -[DEFAULT] -test_command=PYTHONPATH=lib python -m subunit.run fixtures.test_suite