Extended PhoneNumber class to have format attributes

This commit is contained in:
Vesa Uimonen
2013-03-26 10:33:38 +02:00
parent 3a5b80ea5e
commit ee4cdde590
2 changed files with 89 additions and 13 deletions

View File

@@ -11,6 +11,52 @@ from sqlalchemy.sql.expression import desc, asc
from sqlalchemy import types
class PhoneNumber(phonenumbers.phonenumber.PhoneNumber):
'''
Extends a PhoneNumber class from `Python phonenumbers library`_. Adds
different phone number formats to attributes, so they can be easily used
in templates. Phone number validation method is also implemented.
Takes the raw phone number and country code as params and parses them
into a PhoneNumber object.
.. _Python phonenumbers library:
https://github.com/daviddrysdale/python-phonenumbers
:param raw_number:
String representation of the phone number.
:param country_code:
Country code of the phone number.
'''
def __init__(self, raw_number, country_code=None):
self._phone_number = phonenumbers.parse(raw_number, country_code)
super(PhoneNumber, self).__init__(
country_code=self._phone_number.country_code,
national_number=self._phone_number.national_number,
extension=self._phone_number.extension,
italian_leading_zero=self._phone_number.italian_leading_zero,
raw_input=self._phone_number.raw_input,
country_code_source=self._phone_number.country_code_source,
preferred_domestic_carrier_code=
self._phone_number.preferred_domestic_carrier_code
)
self.national = phonenumbers.format_number(
self._phone_number,
phonenumbers.PhoneNumberFormat.NATIONAL
)
self.international = phonenumbers.format_number(
self._phone_number,
phonenumbers.PhoneNumberFormat.INTERNATIONAL
)
self.e164 = phonenumbers.format_number(
self._phone_number,
phonenumbers.PhoneNumberFormat.E164
)
def is_valid_number(self):
return phonenumbers.is_valid_number(self._phone_number)
class PhoneNumberType(types.TypeDecorator):
"""
Changes PhoneNumber objects to a string representation on the way in and
@@ -18,7 +64,7 @@ class PhoneNumberType(types.TypeDecorator):
as storing format, no country code is needed for parsing the database
value to PhoneNumber object.
"""
STORE_FORMAT = phonenumbers.PhoneNumberFormat.E164
STORE_FORMAT = 'e164'
impl = types.Unicode(20)
def __init__(self, country_code='US', max_length=20, *args, **kwargs):
@@ -27,18 +73,10 @@ class PhoneNumberType(types.TypeDecorator):
self.impl = types.Unicode(max_length)
def process_bind_param(self, value, dialect):
return phonenumbers.format_number(
value,
self.STORE_FORMAT
)
return getattr(value, self.STORE_FORMAT)
def process_result_value(self, value, dialect):
if self.STORE_FORMAT == phonenumbers.PhoneNumberFormat.E164:
return phonenumbers.parse(value)
return phonenumbers.parse(
value,
self.country_code
)
return PhoneNumber(value, self.country_code)
class InstrumentedList(_InstrumentedList):

View File

@@ -1,4 +1,3 @@
import phonenumbers
import sqlalchemy as sa
from sqlalchemy import create_engine
@@ -9,6 +8,7 @@ from sqlalchemy_utils import (
escape_like,
sort_query,
InstrumentedList,
PhoneNumber,
PhoneNumberType,
merge
)
@@ -120,10 +120,48 @@ class TestSortQuery(TestCase):
assert 'category.name ASC' in str(sorted_query)
class TestPhoneNumber(object):
def setup_method(self, method):
self.valid_phone_numbers = [
'040 1234567',
'+358 401234567',
'09 2501234',
'+358 92501234',
'0800 939393',
'09 4243 0456',
'0600 900 500'
]
self.invalid_phone_numbers = [
'abc',
'+040 1234567',
'0111234567',
'358'
]
def test_valid_phone_numbers(self):
for raw_number in self.valid_phone_numbers:
phone_number = PhoneNumber(raw_number, 'FI')
assert phone_number.is_valid_number()
def test_invalid_phone_numbers(self):
for raw_number in self.invalid_phone_numbers:
try:
phone_number = PhoneNumber(raw_number, 'FI')
assert not phone_number.is_valid_number()
except:
pass
def test_phone_number_attributes(self):
phone_number = PhoneNumber('+358401234567')
assert phone_number.e164 == u'+358401234567'
assert phone_number.international == u'+358 40 1234567'
assert phone_number.national == u'040 1234567'
class TestPhoneNumberType(TestCase):
def setup_method(self, method):
super(TestPhoneNumberType, self).setup_method(method)
self.phone_number = phonenumbers.parse(
self.phone_number = PhoneNumber(
'040 1234567',
'FI'
)