При использовании метода конструктора tuple () вместо определения типа по умолчанию для создания одностроковых кортежей важно соблюдать осторожность. Вот скрипт Nose2 / Unittest, который вы можете использовать для решения проблемы:
#!/usr/bin/env python
# vim: ts=4 sw=4 sts=4 et
from __future__ import print_function
# global
import unittest
import os
import sys
import logging
import pprint
import shutil
# module-level logger
logger = logging.getLogger(__name__)
# module-global test-specific imports
# where to put test output data for compare.
testdatadir = os.path.join('.', 'test', 'test_data')
rawdata_dir = os.path.join(os.path.expanduser('~'), 'Downloads')
testfiles = (
'bogus.data',
)
purge_results = False
output_dir = os.path.join('test_data', 'example_out')
def cleanPath(path):
'''cleanPath
Recursively removes everything below a path
:param path:
the path to clean
'''
for root, dirs, files in os.walk(path):
for fn in files:
logger.debug('removing {}'.format(fn))
os.unlink(os.path.join(root, fn))
for dn in dirs:
# recursive
try:
logger.debug('recursive del {}'.format(dn))
shutil.rmtree(os.path.join(root, dn))
except Exception:
# for now, halt on all. Override with shutil onerror
# callback and ignore_errors.
raise
class TestChangeMe(unittest.TestCase):
'''
TestChangeMe
'''
testdatadir = None
rawdata_dir = None
testfiles = None
output_dir = output_dir
def __init__(self, *args, **kwargs):
self.testdatadir = os.path.join(os.path.dirname(
os.path.abspath(__file__)), testdatadir)
super(TestChangeMe, self).__init__(*args, **kwargs)
# check for kwargs
# this allows test control by instance
self.testdatadir = kwargs.get('testdatadir', testdatadir)
self.rawdata_dir = kwargs.get('rawdata_dir', rawdata_dir)
self.testfiles = kwargs.get('testfiles', testfiles)
self.output_dir = kwargs.get('output_dir', output_dir)
def setUp(self):
'''setUp
pre-test setup called before each test
'''
logging.debug('setUp')
if not os.path.exists(self.testdatadir):
os.mkdir(self.testdatadir)
else:
self.assertTrue(os.path.isdir(self.testdatadir))
self.assertTrue(os.path.exists(self.testdatadir))
cleanPath(self.output_dir)
def tearDown(self):
'''tearDown
post-test cleanup, if required
'''
logging.debug('tearDown')
if purge_results:
cleanPath(self.output_dir)
def tupe_as_arg(self, tuple1, tuple2, tuple3, tuple4):
'''test_something_0
auto-run tests sorted by ascending alpha
'''
# for testing, recreate strings and lens
string1 = 'string number 1'
len_s1 = len(string1)
string2 = 'string number 2'
len_s2 = len(string2)
# run the same tests...
# should test as type = string
self.assertTrue(type(tuple1) == str)
self.assertFalse(type(tuple1) == tuple)
self.assertEqual(len_s1, len_s2, len(tuple1))
self.assertEqual(len(tuple2), 1)
# this will fail
# self.assertEqual(len(tuple4), 1)
self.assertEqual(len(tuple3), 2)
self.assertTrue(type(string1) == str)
self.assertTrue(type(string2) == str)
self.assertTrue(string1 == tuple1)
# should test as type == tuple
self.assertTrue(type(tuple2) == tuple)
self.assertTrue(type(tuple4) == tuple)
self.assertFalse(type(tuple1) == type(tuple2))
self.assertFalse(type(tuple1) == type(tuple4))
# this will fail
# self.assertFalse(len(tuple4) == len(tuple1))
self.assertFalse(len(tuple2) == len(tuple1))
def default_test(self):
'''testFileDetection
Tests all data files for type and compares the results to the current
stored results.
'''
# test 1
__import__('pudb').set_trace()
string1 = 'string number 1'
len_s1 = len(string1)
string2 = 'string number 2'
len_s2 = len(string2)
tuple1 = (string1)
tuple2 = (string1,)
tuple3 = (string1, string2)
tuple4 = tuple(string1,)
# should test as type = string
self.assertTrue(type(tuple1) == str)
self.assertFalse(type(tuple1) == tuple)
self.assertEqual(len_s1, len_s2, len(tuple1))
self.assertEqual(len(tuple2), 1)
# this will fail
# self.assertEqual(len(tuple4), 1)
self.assertEqual(len(tuple3), 2)
self.assertTrue(type(string1) == str)
self.assertTrue(type(string2) == str)
self.assertTrue(string1 == tuple1)
# should test as type == tuple
self.assertTrue(type(tuple2) == tuple)
self.assertTrue(type(tuple4) == tuple)
self.assertFalse(type(tuple1) == type(tuple2))
self.assertFalse(type(tuple1) == type(tuple4))
# this will fail
# self.assertFalse(len(tuple4) == len(tuple1))
self.assertFalse(len(tuple2) == len(tuple1))
self.tupe_as_arg(tuple1, tuple2, tuple3, tuple4)
# stand-alone test execution
if __name__ == '__main__':
import nose2
nose2.main(
argv=[
'fake',
'--log-capture',
'TestChangeMe.default_test',
])
Вы заметите, что (почти) идентичный код, вызывающий кортеж (string1,), показан как тип кортежа, но длина будет равна длине строки, и все члены будут одиночными символами.
Это приведет к тому, что утверждения в строках # 137, # 147, # 104 и # 115 потерпят неудачу, даже если они кажутся идентичными пропущенным.
(примечание: у меня есть точка останова PUDB в коде в строке # 124, это отличный инструмент отладки, но вы можете удалить ее, если хотите. В противном случае просто используйте pip install pudb
, чтобы использовать ее.)