Python string.translate抛出字符串格式(ddd)ddd-dddd的类型错误

时间:2014-03-14 16:03:03

标签: python django unit-testing unicode

我需要格式化一些电话号码,我想要的格式为'(ddd)ddd-dddd'。我偷了Python: removing characters except digits from string的代码,并一如既往地投票。它在大多数情况下工作正常,但有些事情我不明白。

我有一个名为CustomerStudent的Django模型,它有一个cell_phonebusiness_phone字段。我的保存方法:

def save(self, *args, **kwargs):
    self.cell_phone = format_phone(self.cell_phone)
    self.business_phone = format_phone(self.business_phone)
    super(CustomerStudent, self).save(*args, **kwargs)

format_phone方法位于我的util.py文件中。

def format_phone(str=None):
    if str is None:
        return str
    all = string.maketrans('', '')
    nodigs=all.translate(all, string.digits)
    raw_phone = str.translate(all, nodigs)
    if len(raw_phone) == 10:
        pass
    elif len(raw_phone) == 7:
        raw_phone = '000' + raw_phone
    else:
        return None
    return '(%s)%s-%s' % (raw_phone[0:3:1], raw_phone[3:6:1], raw_phone[6::1])

当我遇到这个问题时,我正在编写测试来检查这个模型。

使用以下值构建测试模型:

cell_phone = '5555555555'
business_phone = '999-9999'

tests.py

s = CustomerStudent.objects.get(pk=1)
self.assertEqual(s.cell_phone, '(555)555-5555') # Passes
self.assertEqual(s.business_phone, '(000)999-9999') # Passes
s.cell_phone = 'a5-55l7i77(7/7e7p7-)'
s.save()
self.assertEqual(s.cell_phone, '(555)777-7777') # Passes
self.assertEqual(s.business_phone, '(000)999-9999') # Fails

错误消息:

Creating test database for alias 'default'...
.........E............
======================================================================
ERROR: test_customer_student (training.tests.TrainingTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/app/tests.py", line 281, in test_customer_student
s.save()
File "/path/to/app/models.py", line 149, in save
self.business_phone = format_phone(self.business_phone)
File "path/to/app/util.py", line 16, in format_phone
raw_phone = str.translate(all, nodigs)
TypeError: translate() takes exactly one argument (2 given)

----------------------------------------------------------------------
Ran 22 tests in 0.968s

FAILED (errors=1)
Destroying test database for alias 'default'...

我知道Unicode的行为有所不同,但我确保新电话号码中存在格式正确的电话号码中的所有字符。我决定抓住TypeError并返回None

def format_phone(str=None):
    if str is None:
        return str
    all = string.maketrans('', '')
    nodigs=all.translate(all, string.digits)
    try:
        raw_phone = str.translate(all, nodigs)
    except TypeError:
        return None
    if len(raw_phone) == 10:
        pass
    elif len(raw_phone) == 7:
        raw_phone = '000' + raw_phone
    else:
        return None
    return '(%s)%s-%s' % (raw_phone[0:3:1], raw_phone[3:6:1], raw_phone[6::1])

现在我运行测试时:

Creating test database for alias 'default'...
.........F............
======================================================================
FAIL: test_customer_student (training.tests.TrainingTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/app/tests.py", line 283, in  test_customer_student
self.assertEqual(s.business_phone, '(000)999-9999')
AssertionError: None != '(000)999-9999'

----------------------------------------------------------------------
Ran 22 tests in 0.954s

FAILED (failures=1)
Destroying test database for alias 'default'...

现在提出问题。为什么在数字未更改时会发生这种情况?我认为它与Unicode有关,但新的cell_number中包含相同的字符,并且正确地运行format_phone

我可以通过检查保存方法中的电话号码是否已更改来解决这个问题,但这似乎是可以避免的开销。建议?

1 个答案:

答案 0 :(得分:1)

您可以强制使用常规字符串:

def format_phone(phone_str=None):
    phone_str = phone_str.encode('ascii', 'ignore')
    [...]

如图所示here