I have this strange behavior where when I run a function that only changes class values that value is being passed instead of a default value to a constructor
Here's the constructor:
def __init__(self, key, *, name=None, id=None, oldInfo={}, newInfo={},
priority=Priority.DEFAULT):
self._key = key
self._name = name
self._id = id
self._oldInfo = oldInfo
self._newInfo = newInfo
self._priority = priority
assert(not self._oldInfo or type(self._oldInfo) is dict)
assert(not self._newInfo or type(self._newInfo) is dict)
assert(type(self._priority) is Priority)
self._appendix = None
Then I have some basic test cases. Here's a simple sequence that produces the issue (note: the Z's are there to force these test cases after all others)
class ZZZZBeforeCombineTestSuite(unittest.TestCase):
def testDefaultsBroken(self):
self.assertEqual(Info('key').string(), "key: for 'None'")
class ZZZZCombineTestSuite(unittest.TestCase):
def testCombine(self):
infoA = Info('A', oldInfo={'v1': 1})
infoB = Info('B', newInfo={'v2': 2})
infoA.combine(infoB)
# self.assertEqual(infoA._oldInfo, {'v1': 1})
# self.assertEqual(infoA._newInfo, {'v2': 2})
class ZZZZPostCombineTestSuite(unittest.TestCase):
def testDefaultsBroken(self):
self.assertEqual(Info('key').string(), "key: added '2' under 'v2' for 'None'")
def testDefaultsFixed(self):
self.assertEqual(Info('key', newInfo={}).string(), "key: for 'None'")
The combine method is defined as:
def combine(self, other):
for key, value in other._oldInfo.items():
self._oldInfo[key] = value
for key, value in other._newInfo.items():
self._newInfo[key] = value
All these test cases pass, which means:
- first only _key is being set to 'key' and produces the string "key: for 'None'"
- then calling combine using two separate classes, in a separate TestCase
- in a third class, Info::init has {'v2': 2} as the arg for newInfo (verified in debug)
- but when an empty dict is explicitly passed to the constructor it's fine
Why would (and how could) Info::init be getting newInfo={'v2': 2} when that value is never being set on the instance and is only being set on a completely different instance <note: the behavior goes away if infoA.combine(infoB) is removed; it only happens after that function call, which loops over values in two unrelated classes>
Is it at least safe to say this an artifact of the unittest module and won't effect the code when running elsewhere?