I'm creating class which behaves like list(), but you can add strings to it and these strings will be splitted by spaces on words and these words will be added to the class instance. Same with substraction: substraction removes words from class instance (if any).
I faced with strange behavior in nose tests: behavior changes when I'm simply changing order of assertions.
Here is test:
from nose.tools import *
def test_isub_str(self):
u = params()
u += "1 2 3 4"
u -= "2 3"
ok_("1" in u, u)
ok_("2" not in u, u)
ok_("3" not in u, u)
ok_("4" in u, u)
This test fails with following output:
Traceback (most recent call last):
File "tests.py", line 71, in test_isub_str
ok_("4" in u, u)
assert expr, msg
AssertionError: 1 4
Strange, the "u" is dumped as "1 4", but "4" wasn't found in "u" during assertion testing. And the most interesting happens when I change the order of assertions to following:
ok_("1" in u, u)
ok_("4" in u, u)
ok_("2" not in u, u)
ok_("3" not in u, u)
Then tests are passing OK and this is correct, expected behavior. It looks like "not in" statement changes behavior of following "in" statements. I'm surprized.
Finally, here is my class:
class params():
def __init__(self):
self.index = 0 # iterator index
self.values = [] # list of stored values
def __iadd__(self, addvalues):
if isinstance(addvalues, str):
addvalues = addvalues.split(" ")
# add all values to this instance if they are list() or params()
# and not exist in current instance
if isinstance(addvalues, params) or isinstance(addvalues, list):
for value in addvalues:
if isinstance(value, str) and value not in self.values:
self.values.append(value)
else:
raise TypeError
return self
else:
raise TypeError
def __isub__(self, subvalues):
if isinstance(subvalues, str):
subvalues = subvalues.split(" ")
# substract all values from this instance if they are list() or params()
# and existing in current instance
if isinstance(subvalues, params) or isinstance(subvalues, list):
for value in subvalues:
if isinstance(value, str) and value in self.values:
self.values.remove(value)
else:
raise TypeError
return self
else:
raise TypeError
def __iter__(self):
return self
def next(self):
if self.index >= len(self.values):
raise StopIteration
else:
self.index += 1
return self.values[self.index - 1]
def __str__(self):
return " ".join(self.values)
So question is: why such strange behavior happens? I missed something in iterator functionality? Or this nosetests bug?