[Python-checkins] r79132 - in python/trunk: Doc/library/unittest.rst Doc/whatsnew/2.7.rst Lib/test/test_cgi.py Lib/test/test_unittest.py Lib/unittest/case.py Lib/unittest/util.py
michael.foord
python-checkins at python.org
Sat Mar 20 04:00:34 CET 2010
Author: michael.foord
Date: Sat Mar 20 04:00:34 2010
New Revision: 79132
Log:
Issue 7832: renaming unittest.TestCase.assertSameElements to assertItemsEqual and changing behaviour
Modified:
python/trunk/Doc/library/unittest.rst
python/trunk/Doc/whatsnew/2.7.rst
python/trunk/Lib/test/test_cgi.py
python/trunk/Lib/test/test_unittest.py
python/trunk/Lib/unittest/case.py
python/trunk/Lib/unittest/util.py
Modified: python/trunk/Doc/library/unittest.rst
==============================================================================
--- python/trunk/Doc/library/unittest.rst (original)
+++ python/trunk/Doc/library/unittest.rst Sat Mar 20 04:00:34 2010
@@ -786,7 +786,7 @@
will be included in the error message. This method is used by default
when comparing Unicode strings with :meth:`assertEqual`.
- If specified *msg* will be used as the error message on failure.
+ If specified, *msg* will be used as the error message on failure.
.. versionadded:: 2.7
@@ -807,22 +807,24 @@
Tests that *first* is or is not in *second* with an explanatory error
message as appropriate.
- If specified *msg* will be used as the error message on failure.
+ If specified, *msg* will be used as the error message on failure.
.. versionadded:: 2.7
- .. method:: assertSameElements(actual, expected, msg=None)
+ .. method:: assertItemsEqual(actual, expected, msg=None)
Test that sequence *expected* contains the same elements as *actual*,
- regardless of their order. When they don't, an error message listing
- the differences between the sequences will be generated.
+ regardless of their order. When they don't, an error message listing the
+ differences between the sequences will be generated.
- Duplicate elements are ignored when comparing *actual* and *expected*.
- It is the equivalent of ``assertEqual(set(expected), set(actual))``
- but it works with sequences of unhashable objects as well.
+ Duplicate elements are *not* ignored when comparing *actual* and
+ *expected*. It verifies if each element has the same count in both
+ sequences. It is the equivalent of ``assertEqual(sorted(expected),
+ sorted(actual))`` but it works with sequences of unhashable objects as
+ well.
- If specified *msg* will be used as the error message on failure.
+ If specified, *msg* will be used as the error message on failure.
.. versionadded:: 2.7
@@ -836,7 +838,7 @@
Fails if either of *set1* or *set2* does not have a :meth:`set.difference`
method.
- If specified *msg* will be used as the error message on failure.
+ If specified, *msg* will be used as the error message on failure.
.. versionadded:: 2.7
@@ -848,7 +850,7 @@
method will be used by default to compare dictionaries in
calls to :meth:`assertEqual`.
- If specified *msg* will be used as the error message on failure.
+ If specified, *msg* will be used as the error message on failure.
.. versionadded:: 2.7
@@ -859,7 +861,7 @@
superset of those in *expected*. If not, an error message listing
the missing keys and mismatched values is generated.
- If specified *msg* will be used as the error message on failure.
+ If specified, *msg* will be used as the error message on failure.
.. versionadded:: 2.7
@@ -873,7 +875,7 @@
These methods are used by default when comparing lists or tuples with
:meth:`assertEqual`.
- If specified *msg* will be used as the error message on failure.
+ If specified, *msg* will be used as the error message on failure.
.. versionadded:: 2.7
@@ -885,7 +887,7 @@
be raised. If the sequences are different an error message is
constructed that shows the difference between the two.
- If specified *msg* will be used as the error message on failure.
+ If specified, *msg* will be used as the error message on failure.
This method is used to implement :meth:`assertListEqual` and
:meth:`assertTupleEqual`.
Modified: python/trunk/Doc/whatsnew/2.7.rst
==============================================================================
--- python/trunk/Doc/whatsnew/2.7.rst (original)
+++ python/trunk/Doc/whatsnew/2.7.rst Sat Mar 20 04:00:34 2010
@@ -1086,7 +1086,7 @@
* :meth:`assertIn` and :meth:`assertNotIn` tests whether
*first* is or is not in *second*.
-* :meth:`assertSameElements` tests whether two provided sequences
+* :meth:`assertItemsEqual` tests whether two provided sequences
contain the same elements.
* :meth:`assertSetEqual` compares whether two sets are equal, and
Modified: python/trunk/Lib/test/test_cgi.py
==============================================================================
--- python/trunk/Lib/test/test_cgi.py (original)
+++ python/trunk/Lib/test/test_cgi.py Sat Mar 20 04:00:34 2010
@@ -135,18 +135,18 @@
if isinstance(expect, dict):
# test dict interface
self.assertEqual(len(expect), len(fcd))
- self.assertSameElements(expect.keys(), fcd.keys())
- self.assertSameElements(expect.values(), fcd.values())
- self.assertSameElements(expect.items(), fcd.items())
+ self.assertItemsEqual(expect.keys(), fcd.keys())
+ self.assertItemsEqual(expect.values(), fcd.values())
+ self.assertItemsEqual(expect.items(), fcd.items())
self.assertEqual(fcd.get("nonexistent field", "default"), "default")
self.assertEqual(len(sd), len(fs))
- self.assertSameElements(sd.keys(), fs.keys())
+ self.assertItemsEqual(sd.keys(), fs.keys())
self.assertEqual(fs.getvalue("nonexistent field", "default"), "default")
# test individual fields
for key in expect.keys():
expect_val = expect[key]
self.assertTrue(fcd.has_key(key))
- self.assertSameElements(fcd[key], expect[key])
+ self.assertItemsEqual(fcd[key], expect[key])
self.assertEqual(fcd.get(key, "default"), fcd[key])
self.assertTrue(fs.has_key(key))
if len(expect_val) > 1:
@@ -162,11 +162,11 @@
self.assertTrue(single_value)
self.assertEqual(val, expect_val[0])
self.assertEqual(fs.getvalue(key), expect_val[0])
- self.assertSameElements(sd.getlist(key), expect_val)
+ self.assertItemsEqual(sd.getlist(key), expect_val)
if single_value:
- self.assertSameElements(sd.values(),
+ self.assertItemsEqual(sd.values(),
first_elts(expect.values()))
- self.assertSameElements(sd.items(),
+ self.assertItemsEqual(sd.items(),
first_second_elts(expect.items()))
def test_weird_formcontentdict(self):
@@ -178,7 +178,7 @@
self.assertEqual(d[k], v)
for k, v in d.items():
self.assertEqual(expect[k], v)
- self.assertSameElements(expect.values(), d.values())
+ self.assertItemsEqual(expect.values(), d.values())
def test_log(self):
cgi.log("Testing")
Modified: python/trunk/Lib/test/test_unittest.py
==============================================================================
--- python/trunk/Lib/test/test_unittest.py (original)
+++ python/trunk/Lib/test/test_unittest.py Sat Mar 20 04:00:34 2010
@@ -2575,9 +2575,9 @@
class SadSnake(object):
"""Dummy class for test_addTypeEqualityFunc."""
s1, s2 = SadSnake(), SadSnake()
- self.assertFalse(s1 == s2)
+ self.assertNotEqual(s1, s2)
def AllSnakesCreatedEqual(a, b, msg=None):
- return type(a) == type(b) == SadSnake
+ return type(a) is type(b) is SadSnake
self.addTypeEqualityFunc(SadSnake, AllSnakesCreatedEqual)
self.assertEqual(s1, s2)
# No this doesn't clean up and remove the SadSnake equality func
@@ -2745,21 +2745,51 @@
self.assertRaises(self.failureException, self.assertDictEqual, [], d)
self.assertRaises(self.failureException, self.assertDictEqual, 1, 1)
- self.assertSameElements([1, 2, 3], [3, 2, 1])
- self.assertSameElements([1, 2] + [3] * 100, [1] * 100 + [2, 3])
- self.assertSameElements(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo'])
- self.assertRaises(self.failureException, self.assertSameElements,
+ def testAssertItemsEqual(self):
+ a = object()
+ self.assertItemsEqual([1, 2, 3], [3, 2, 1])
+ self.assertItemsEqual(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo'])
+ self.assertItemsEqual([a, a, 2, 2, 3], (a, 2, 3, a, 2))
+ self.assertItemsEqual([1, "2", "a", "a"], ["a", "2", True, "a"])
+ self.assertRaises(self.failureException, self.assertItemsEqual,
+ [1, 2] + [3] * 100, [1] * 100 + [2, 3])
+ self.assertRaises(self.failureException, self.assertItemsEqual,
+ [1, "2", "a", "a"], ["a", "2", True, 1])
+ self.assertRaises(self.failureException, self.assertItemsEqual,
[10], [10, 11])
- self.assertRaises(self.failureException, self.assertSameElements,
+ self.assertRaises(self.failureException, self.assertItemsEqual,
[10, 11], [10])
+ self.assertRaises(self.failureException, self.assertItemsEqual,
+ [10, 11, 10], [10, 11])
# Test that sequences of unhashable objects can be tested for sameness:
- self.assertSameElements([[1, 2], [3, 4]], [[3, 4], [1, 2]])
-
- self.assertSameElements([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}])
- self.assertRaises(self.failureException, self.assertSameElements,
+ self.assertItemsEqual([[1, 2], [3, 4], 0], [False, [3, 4], [1, 2]])
+ with test_support.check_warnings(quiet=True) as w:
+ # hashable types, but not orderable
+ self.assertRaises(self.failureException, self.assertItemsEqual,
+ [], [divmod, 'x', 1, 5j, 2j, frozenset()])
+ # comparing dicts raises a py3k warning
+ self.assertItemsEqual([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}])
+ # comparing heterogenous non-hashable sequences raises a py3k warning
+ self.assertItemsEqual([1, 'x', divmod, []], [divmod, [], 'x', 1])
+ self.assertRaises(self.failureException, self.assertItemsEqual,
+ [], [divmod, [], 'x', 1, 5j, 2j, set()])
+ # fail the test if warnings are not silenced
+ if w.warnings:
+ self.fail('assertItemsEqual raised a warning: ' +
+ str(w.warnings[0]))
+ self.assertRaises(self.failureException, self.assertItemsEqual,
[[1]], [[2]])
+ # Same elements, but not same sequence length
+ self.assertRaises(self.failureException, self.assertItemsEqual,
+ [1, 1, 2], [2, 1])
+ self.assertRaises(self.failureException, self.assertItemsEqual,
+ [1, 1, "2", "a", "a"], ["2", "2", True, "a"])
+ self.assertRaises(self.failureException, self.assertItemsEqual,
+ [1, {'b': 2}, None, True], [{'b': 2}, True, None])
+
+
def testAssertSetEqual(self):
set1 = set()
set2 = set()
@@ -3009,13 +3039,14 @@
Do not use these methods. They will go away in 3.3.
"""
- self.failIfEqual(3, 5)
- self.failUnlessEqual(3, 3)
- self.failUnlessAlmostEqual(2.0, 2.0)
- self.failIfAlmostEqual(3.0, 5.0)
- self.failUnless(True)
- self.failUnlessRaises(TypeError, lambda _: 3.14 + u'spam')
- self.failIf(False)
+ with test_support.check_warnings():
+ self.failIfEqual(3, 5)
+ self.failUnlessEqual(3, 3)
+ self.failUnlessAlmostEqual(2.0, 2.0)
+ self.failIfAlmostEqual(3.0, 5.0)
+ self.failUnless(True)
+ self.failUnlessRaises(TypeError, lambda _: 3.14 + u'spam')
+ self.failIf(False)
def testDeepcopy(self):
# Issue: 5660
@@ -3355,8 +3386,8 @@
"^Missing: 'key'$",
"^Missing: 'key' : oops$"])
- def testAssertSameElements(self):
- self.assertMessages('assertSameElements', ([], [None]),
+ def testAssertItemsEqual(self):
+ self.assertMessages('assertItemsEqual', ([], [None]),
[r"\[None\]$", "^oops$",
r"\[None\]$",
r"\[None\] : oops$"])
Modified: python/trunk/Lib/unittest/case.py
==============================================================================
--- python/trunk/Lib/unittest/case.py (original)
+++ python/trunk/Lib/unittest/case.py Sat Mar 20 04:00:34 2010
@@ -8,8 +8,9 @@
import warnings
from . import result
-from .util import strclass, safe_repr, sorted_list_difference
-
+from .util import (
+ strclass, safe_repr, sorted_list_difference, unorderable_list_difference
+)
class SkipTest(Exception):
"""
@@ -686,10 +687,9 @@
msg: Optional message to use on failure instead of a list of
differences.
- For more general containership equality, assertSameElements will work
- with things other than sets. This uses ducktyping to support
- different types of sets, and is optimized for sets specifically
- (parameters must support a difference method).
+ assertSetEqual uses ducktyping to support different types of sets, and
+ is optimized for sets specifically (parameters must support a
+ difference method).
"""
try:
difference1 = set1.difference(set2)
@@ -784,42 +784,48 @@
self.fail(self._formatMessage(msg, standardMsg))
- def assertSameElements(self, expected_seq, actual_seq, msg=None):
- """An unordered sequence specific comparison.
+ def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
+ """An unordered sequence / set specific comparison. It asserts that
+ expected_seq and actual_seq contain the same elements. It is
+ the equivalent of::
+
+ self.assertEqual(sorted(expected_seq), sorted(actual_seq))
Raises with an error message listing which elements of expected_seq
are missing from actual_seq and vice versa if any.
- Duplicate elements are ignored when comparing *expected_seq* and
- *actual_seq*. It is the equivalent of ``assertEqual(set(expected),
- set(actual))`` but it works with sequences of unhashable objects as
- well.
+ Asserts that each element has the same count in both sequences.
+ Example:
+ - [0, 1, 1] and [1, 0, 1] compare equal.
+ - [0, 0, 1] and [0, 1] compare unequal.
"""
with warnings.catch_warnings():
if sys.py3kwarning:
# Silence Py3k warning raised during the sorting
for _msg in ["dict inequality comparisons",
- "builtin_function_or_method order comparisons",
- "comparing unequal types"]:
+ "builtin_function_or_method order comparisons",
+ "comparing unequal types"]:
warnings.filterwarnings("ignore", _msg, DeprecationWarning)
try:
- expected = set(expected_seq)
- actual = set(actual_seq)
- missing = sorted(expected.difference(actual))
- unexpected = sorted(actual.difference(expected))
- except TypeError:
- # Fall back to slower list-compare if any of the objects are
- # not hashable.
expected = sorted(expected_seq)
actual = sorted(actual_seq)
- missing, unexpected = sorted_list_difference(expected, actual)
+ except TypeError:
+ # Unsortable items (example: set(), complex(), ...)
+ expected = list(expected_seq)
+ actual = list(actual_seq)
+ missing, unexpected = unorderable_list_difference(
+ expected, actual, ignore_duplicate=False
+ )
+ else:
+ return self.assertSequenceEqual(expected, actual, msg=msg)
+
errors = []
if missing:
errors.append('Expected, but missing:\n %s' %
- safe_repr(missing))
+ safe_repr(missing))
if unexpected:
errors.append('Unexpected, but present:\n %s' %
- safe_repr(unexpected))
+ safe_repr(unexpected))
if errors:
standardMsg = '\n'.join(errors)
self.fail(self._formatMessage(msg, standardMsg))
Modified: python/trunk/Lib/unittest/util.py
==============================================================================
--- python/trunk/Lib/unittest/util.py (original)
+++ python/trunk/Lib/unittest/util.py Sat Mar 20 04:00:34 2010
@@ -48,3 +48,40 @@
unexpected.extend(actual[j:])
break
return missing, unexpected
+
+
+def unorderable_list_difference(expected, actual, ignore_duplicate=False):
+ """Same behavior as sorted_list_difference but
+ for lists of unorderable items (like dicts).
+
+ As it does a linear search per item (remove) it
+ has O(n*n) performance.
+ """
+ missing = []
+ unexpected = []
+ while expected:
+ item = expected.pop()
+ try:
+ actual.remove(item)
+ except ValueError:
+ missing.append(item)
+ if ignore_duplicate:
+ for lst in expected, actual:
+ try:
+ while True:
+ lst.remove(item)
+ except ValueError:
+ pass
+ if ignore_duplicate:
+ while actual:
+ item = actual.pop()
+ unexpected.append(item)
+ try:
+ while True:
+ actual.remove(item)
+ except ValueError:
+ pass
+ return missing, unexpected
+
+ # anything left in actual is unexpected
+ return missing, actual
More information about the Python-checkins
mailing list