python unittest failing assertion with overloaded __repr__ - python

In my code, I've defined a class with its own repr method. The representation of the class should be a list.
def __repr__(self):
if self.front <= self.tail:
q = self._queue[self.front:self.tail+1]
elif self.front > self.tail:
q = self._queue[self.front:]
q.extend(self._queue[:self.tail + 1])
return (q.__repr__())
I've written the following unittest to test this method.
def test_enqueue(self):
q = BoundedQueue(1)
q.enqueue(1)
self.assertEqual(q, [1])
However, I end up with an assertion error:
Traceback (most recent call last):
File "test_internmatch_queue.py", line 13, in test_enqueue
self.assertEqual(q, [1])
AssertionError: [1] != [1]
I'm not sure what the problem is... to my human eyes, [1]==[1]! I've tried several other variations in my repr method (below), and they all returned errors as well.
return repr(q)
return str(q)

q is a BoundedQueue. [1] is a list. They can't be equal unless you override __eq__. repr is not used for equality testing.

As recursive states, __repr__ isn't used to detect whether two values are equal.
You have several options:
Define __eq__ which is what python calls to check equality. I don't recommend this as I don't really see a BoundedQueue as being equal to a list
Define an items() method which returns the list. Then check for equality against the list
Add a way to build a BoundedQueue from a list. Then write __eq__ to check for equality between two BoundedQueues.

Related

Python 2 assertItemsEqual incorrect result

I ran into an interesting situation with the unittest.TestCase.assertItemsEqual function under Python 2; posting my findings here for posterity.
The following unit test breaks under Python 2 when it should succeed:
import unittest
class Foo(object):
def __init__(self, a=1, b=2):
self.a = a
self.b = b
def __repr__(self):
return '({},{})'.format(self.a, self.b)
def __eq__(self, other):
return self.a == other.a and self.b == other.b
def __lt__(self, other):
return (self.a, self.b) < (other.a, other.b)
class Test(unittest.TestCase):
def test_foo_eq(self):
self.assertEqual(sorted([Foo()]), sorted([Foo()]))
self.assertItemsEqual([Foo()], [Foo()])
unittest.main()
Here is the output:
======================================================================
FAIL: test_foo_eq (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/tsanders/scripts/one_offs/test_unittest_assert_items_equal2.py", line 17, in test_foo_eq
self.assertItemsEqual([Foo()], [Foo()])
AssertionError: Element counts were not equal:
First has 1, Second has 0: (1,2)
First has 0, Second has 1: (1,2)
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
This is pretty confusing since the docs state:
It [assertItemsEqual] is the equivalent of assertEqual(sorted(expected), sorted(actual)) but it works with sequences of unhashable objects as well.
The same test passes under Python 3 (after swapping self.assertItemsEqual for self.assertCountEqual, since the name has changed).
EDIT: After posting this question, I did find this other question that covers the situation where neither __eq__ nor __hash__ is defined.
To get the test passing under both Python 2 and 3, I had to add the line __hash__ = None to Foo.
The assertItemsEqual/assertCountEqual function takes different code paths depending on whether or not the items in each list are hashable. And according to the docs:
If a class does not define a __cmp__() or __eq__() method it should not define a __hash__() operation either; if it defines __cmp__() or __eq__() but not __hash__(), its instances will not be usable in hashed collections.
With that in mind, Python 2 and 3 have different behavior with regard to __hash__ when __eq__ is defined:
In Python 2, defining __eq__ does not affect the default-provided __hash__, but trying to use the item in a hashed container results in implementation-defined behavior (e.g. keys may be duplicated because they have different hashes, even if __eq__ would return True).
In Python 3, defining __eq__ sets __hash__ to None.
As of Python 2.6, __hash__ can be explicitly set to None to make a class unhashable. In my case, this was required to get assertItemsEqual to use the correct comparison algorithm that relies on __eq__ instead of __hash__.

What is assertEqual in Python UnitTest supposed to do?

assertEqual(a, b) checks if a == b and return True or False,
The documentation says,
Test that first and second are equal. If the values do not compare
equal, the test will fail.
I'm running three tests with assertEqual on a simple class,
The class on test
class Car:
def __init__(self, name):
self.name = name
The TestCase
class CarTest(unittest.TestCase):
def test_diff_equal(self):
car1 = Car('Ford')
car2 = Car('Hyundai')
self.assertEqual(car1, car2)
def test_name_equal(self):
car1 = Car('Ford')
car2 = Car('Ford')
self.assertEqual(car1, car2)
def test_instance_equal(self):
car1 = Car('Ford')
self.assertEqual(car1, car1)
The results are
F.F
======================================================================
FAIL: test_diff_equal (cartest.CarTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "cartest.py", line 10, in test_diff_equal
self.assertEqual(car1, car2)
AssertionError: <car.Car instance at 0x7f499ec12ef0> != <car.Car instance at 0x7f499ec12f38>
======================================================================
FAIL: test_name_equal (cartest.CarTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "cartest.py", line 15, in test_name_equal
self.assertEqual(car1, car2)
AssertionError: <car.Car instance at 0x7f499ec12fc8> != <car.Car instance at 0x7f499ec12f38>
----------------------------------------------------------------------
Ran 3 tests in 0.000s
FAILED (failures=2)
Is assertEqual used to check if both the instances are same? Or is anything wrong in my setup? Why did test_name_equal() fail?
Your test is working absolutely fine, and it's found a bug. Hurray!
Your two Car objects may have the same name, but why would that mean that they are the same car? Nothing in your code makes that so.
If you want that to be the case, implement __eq__ on the Car class:
def __eq__(self, other):
"""Return True if other is also a car and has the same name as
this one."""
return isinstance(other, Car) and self.name == other.name
Then that test should pass.
The whole question is reducible to "How Python compare objects" what is precisely defined in Section 5.9: Comparisons of official documentation.
Quoting from the official documentation (emphasis mine) to clarify on aspects you're asking of.
Most other objects of built-in types compare unequal unless they are
the same object; the choice whether one object is considered smaller
or larger than another one is made arbitrarily but consistently within
one execution of a program.
That's what's covered by test_instance_equal and what essentially is:
o1 = object()
o1 == o1 # will always be True
The operators <, >, ==, >=, <=, and != compare the values of two
objects. The objects need not have the same type. If both are numbers,
they are converted to a common type. Otherwise, objects of different
types always compare unequal, and are ordered consistently but
arbitrarily. You can control comparison behavior of objects of
non-built-in types by defining a cmp method or rich comparison
methods like gt, described in section Special method names.*
Quoting from special method names:
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
New in version 2.1.
These are the so-called “rich comparison” methods, and are called for
comparison operators in preference to __cmp__() below. The
correspondence between operator symbols and method names is as
follows: (...) x==y calls x.__eq__(y), (...)
That's what test_diff_equal and test_name_equal shows. There isn't any __eq__ magic method defined, and therefore it falls back to the default implementation (they compare unequal unless they are the same object).
The question has nothing to do with unit testing a module.
Adding to what's been already said: For the example given, you'll need to directly compare the attributes of the objects, and not the objects themselves, for unittest.TestCase.assertEqual to work.
class CarTest(unittest.TestCase):
def test_diff_equal(self):
car1 = Car('Ford')
car2 = Car('Hyundai')
self.assertEqual(car1.name, car2.name)
def test_name_equal(self):
car1 = Car('Ford')
car2 = Car('Ford')
self.assertEqual(car1.name, car2.name)
def test_instance_equal(self):
car1 = Car('Ford')
self.assertEqual(car1.name, car1.name)
This should now work (and fail) as expected.

In Python, is object() equal to anything besides itself?

If I have the code my_object = object() in Python, will my_object be equal to anything except for itself?
I suspect the answer lies in the __eq__ method of the default object returned by object(). What is the implementation of __eq__ for this default object?
EDIT: I'm using Python 2.7, but am also interested in Python 3 answers. Please clarify whether your answer applies to Python 2, 3, or both.
object().__eq__ returns the NotImplemented singleton:
print(object().__eq__(3))
NotImplemented
By the reflexive rules of rich comparisons, when NotImplemented is returned, the "reflected" operation is tried. So if you have an object on the RHS that returns True for that comparison, then you can get a True response even though the LHS did not implement the comparison.
class EqualToEverything(object):
def __eq__(self,other):
return True
ete = EqualToEverything()
ete == object() # we implemented `ete.__eq__`, so this is obviously True
Out[74]: True
object() == ete # still True due to the reflexive rules of rich comparisons
Out[75]: True
python 2 specific bit: if neither object implements __eq__, then python moves on to check if either implement __cmp__. Equivalent reflexive rules apply here.
class ComparableToEverything(object):
def __cmp__(self,other):
return 0
cte = ComparableToEverything()
cte == object()
Out[5]: True
object() == cte
Out[6]: True
__cmp__ is gone in python 3.
In both python 2 and 3, when we exhaust all of these comparison operators and all are NotImplemented, the final fallback is checking identity. (a is b)
object doesn't implement __eq__, so falls back on the default comparison id(x) == id(y), i.e. are they the same object instance (x is y)?
As a new instance is created every time you call object(), my_object will never* compare equal to anything except itself.
This applies to both 2.x and 3.x:
# 3.4.0
>>> object().__eq__(object())
NotImplemented
# 2.7.6
>>> object().__eq__(object())
Traceback (most recent call last):
File "<pyshell#60>", line 1, in <module>
object().__eq__(object())
AttributeError: 'object' object has no attribute '__eq__'
* or rather, as roippi's answer points out, hardly ever, assuming sensible __eq__ implementations elsewhere.

how does python class specical method work?

I have a Cell class
class Cell :
def __init__(self,char):
self.char=char
self.image='_'
def __str__(self):
return self.image
def __eq__(self,other):
return self.image == other.image
def __ne__(self,other):
return not self.image == other.image
then I have two Cell objects a and b, why I can use expression like "if a != b:" to compare these two object. How does b get inside of a and call the eq method to make the comparison
b doesn't get inside. When an operator is used, Python first looks for the magic method on the left-hand argument. If the appropriate magic method is defined there, it is called. If it doesn't return NotImplemented, then that's the result. If the method doesn't exist (or it returns NotImplemented), then the magic method is called on the right-hand argument. (For arithmetic operators, the right-hand arguments gets a separate method, __radd__ being the right-hand version pf __add__, __rsub__ for __sub__, etc.).
So in your version, it calls __ne__ on a and that's it. The magic method is never called on b.
This behavior is described in the documentation.
Saying if a == b is equivalent to if a.__eq__(b).
Likewise, saying if a != b is really if a.__ne__(b). Both methods return boolean values.
Each class inherits default special methods for comparing equality and inequality, but these can be overridden if explicitly defined.
The other answers are the proper answer.
I just wanted to mention that __ne__ has a bug related to precedence. It should be defined as:
return not (self.image == other.image)
Which is best expressed as:
return not (self == other)
Don't Repeat Yourself.

Propagation of NaN through calculations

Normally, NaN (not a number) propagates through calculations, so I don't need to check for NaN in each step. This works almost always, but apparently there are exceptions. For example:
>>> nan = float('nan')
>>> pow(nan, 0)
1.0
I found the following comment on this:
The propagation of quiet NaNs through arithmetic operations allows
errors to be detected at the end of a sequence of operations without
extensive testing during intermediate stages. However, note that
depending on the language and the function, NaNs can silently be
removed in expressions that would give a constant result for all other
floating-point values e.g. NaN^0, which may be defined as 1, so in
general a later test for a set INVALID flag is needed to detect all
cases where NaNs are introduced.
To satisfy those wishing a more strict interpretation of how the power
function should act, the 2008 standard defines two additional power
functions; pown(x, n) where the exponent must be an integer, and
powr(x, y) which returns a NaN whenever a parameter is a NaN or the
exponentiation would give an indeterminate form.
Is there a way to check the INVALID flag mentioned above through Python? Alternatively, is there any other approach to catch cases where NaN does not propagate?
Motivation: I decided to use NaN for missing data. In my application, missing inputs should result in missing result. It works great, with the exception I described.
I realise that a month has passed since this was asked, but I've come across a similar problem (i.e. pow(float('nan'), 1) throws an exception in some Python implementations, e.g. Jython 2.52b2), and I found the above answers weren't quite what I was looking for.
Using a MissingData type as suggested by 6502 seems like the way to go, but I needed a concrete example. I tried Ethan Furman's NullType class but found that that this didn't work with any arithmetic operations as it doesn't coerce data types (see below), and I also didn't like that it explicitly named each arithmetic function that was overriden.
Starting with Ethan's example and tweaking code I found here, I arrived at the class below. Although the class is heavily commented you can see that it actually only has a handful of lines of functional code in it.
The key points are:
1. Use coerce() to return two NoData objects for mixed type (e.g. NoData + float) arithmetic operations, and two strings for string based (e.g. concat) operations.
2. Use getattr() to return a callable NoData() object for all other attribute/method access
3. Use call() to implement all other methods of the NoData() object: by returning a NoData() object
Here's some examples of its use.
>>> nd = NoData()
>>> nd + 5
NoData()
>>> pow(nd, 1)
NoData()
>>> math.pow(NoData(), 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: nb_float should return float object
>>> nd > 5
NoData()
>>> if nd > 5:
... print "Yes"
... else:
... print "No"
...
No
>>> "The answer is " + nd
'The answer is NoData()'
>>> "The answer is %f" % (nd)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: float argument required, not instance
>>> "The answer is %s" % (nd)
'The answer is '
>>> nd.f = 5
>>> nd.f
NoData()
>>> nd.f()
NoData()
I noticed that using pow with NoData() calls the ** operator and hence works with NoData, but using math.pow does not as it first tries to convert the NoData() object to a float. I'm happy using the non math pow - hopefully 6502 etc were using math.pow when they had problems with pow in their comments above.
The other issue I can't think of a way of solving is the use with the format (%f) operator... No methods of NoData are called in this case, the operator just fails if you don't provide a float. Anyway here's the class itself.
class NoData():
"""NoData object - any interaction returns NoData()"""
def __str__(self):
#I want '' returned as it represents no data in my output (e.g. csv) files
return ''
def __unicode__(self):
return ''
def __repr__(self):
return 'NoData()'
def __coerce__(self, other_object):
if isinstance(other_object, str) or isinstance(other_object, unicode):
#Return string objects when coerced with another string object.
#This ensures that e.g. concatenation operations produce strings.
return repr(self), other_object
else:
#Otherwise return two NoData objects - these will then be passed to the appropriate
#operator method for NoData, which should then return a NoData object
return self, self
def __nonzero__(self):
#__nonzero__ is the operation that is called whenever, e.g. "if NoData:" occurs
#i.e. as all operations involving NoData return NoData, whenever a
#NoData object propagates to a test in branch statement.
return False
def __hash__(self):
#prevent NoData() from being used as a key for a dict or used in a set
raise TypeError("Unhashable type: " + self.repr())
def __setattr__(self, name, value):
#This is overridden to prevent any attributes from being created on NoData when e.g. "NoData().f = x" is called
return None
def __call__(self, *args, **kwargs):
#if a NoData object is called (i.e. used as a method), return a NoData object
return self
def __getattr__(self,name):
#For all other attribute accesses or method accesses, return a NoData object.
#Remember that the NoData object can be called (__call__), so if a method is called,
#a NoData object is first returned and then called. This works for operators,
#so e.g. NoData() + 5 will:
# - call NoData().__coerce__, which returns a (NoData, NoData) tuple
# - call __getattr__, which returns a NoData object
# - call the returned NoData object with args (self, NoData)
# - this call (i.e. __call__) returns a NoData object
#For attribute accesses NoData will be returned, and that's it.
#print name #(uncomment this line for debugging purposes i.e. to see that attribute was accessed/method was called)
return self
Why using NaN that already has another semantic instead of using an instance of a class MissingData defined by yourself?
Defining operations on MissingData instances to get propagation should be easy...
If it's just pow() giving you headaches, you can easily redefine it to return NaN under whatever circumstances you like.
def pow(x, y):
return x ** y if x == x else float("NaN")
If NaN can be used as an exponent you'd also want to check for that; this raises a ValueError exception except when the base is 1 (apparently on the theory that 1 to any power, even one that's not a number, is 1).
(And of course pow() actually takes three operands, the third optional, which omission I'll leave as an exercise...)
Unfortunately the ** operator has the same behavior, and there's no way to redefine that for built-in numeric types. A possibility to catch this is to write a subclass of float that implements __pow__() and __rpow__() and use that class for your NaN values.
Python doesn't seem to provide access to any flags set by calculations; even if it did, it's something you'd have to check after each individual operation.
In fact, on further consideration, I think the best solution might be to simply use an instance of a dummy class for missing values. Python will choke on any operation you try to do with these values, raising an exception, and you can catch the exception and return a default value or whatever. There's no reason to proceed with the rest of the calculation if a needed value is missing, so an exception should be fine.
To answer your question: No, there is no way to check the flags using normal floats. You can use the Decimal class, however, which provides much more control . . . but is a bit slower.
Your other option is to use an EmptyData or Null class, such as this one:
class NullType(object):
"Null object -- any interaction returns Null"
def _null(self, *args, **kwargs):
return self
__eq__ = __ne__ = __ge__ = __gt__ = __le__ = __lt__ = _null
__add__ = __iadd__ = __radd__ = _null
__sub__ = __isub__ = __rsub__ = _null
__mul__ = __imul__ = __rmul__ = _null
__div__ = __idiv__ = __rdiv__ = _null
__mod__ = __imod__ = __rmod__ = _null
__pow__ = __ipow__ = __rpow__ = _null
__and__ = __iand__ = __rand__ = _null
__xor__ = __ixor__ = __rxor__ = _null
__or__ = __ior__ = __ror__ = _null
__divmod__ = __rdivmod__ = _null
__truediv__ = __itruediv__ = __rtruediv__ = _null
__floordiv__ = __ifloordiv__ = __rfloordiv__ = _null
__lshift__ = __ilshift__ = __rlshift__ = _null
__rshift__ = __irshift__ = __rrshift__ = _null
__neg__ = __pos__ = __abs__ = __invert__ = _null
__call__ = __getattr__ = _null
def __divmod__(self, other):
return self, self
__rdivmod__ = __divmod__
if sys.version_info[:2] >= (2, 6):
__hash__ = None
else:
def __hash__(yo):
raise TypeError("unhashable type: 'Null'")
def __new__(cls):
return cls.null
def __nonzero__(yo):
return False
def __repr__(yo):
return '<null>'
def __setattr__(yo, name, value):
return None
def __setitem___(yo, index, value):
return None
def __str__(yo):
return ''
NullType.null = object.__new__(NullType)
Null = NullType()
You may want to change the __repr__ and __str__ methods. Also, be aware that Null cannot be used as a dictionary key, nor stored in a set.

Categories