You are not logged in.

Change Language:

Freelancer? Consultant? Check out: WorkTrail - Time Tracking made easy
Board » General Category » General Discussion » Validating GB telephone numbers in Django forms.

I see that there are routines for validating telephone numbers in forms in Django for several countries.

The code for that can usually be found in the forms.py file located in the various country folders here:
https://github.com/django/django/tree/master/django/contrib/localflavor

So far, there is nothing for GB numbers, here:
https://github.com/django/django/tree/master/django/contrib/localflavor/gb

I've written a bunch of RegEx patterns to get this functionality started. The patterns are 100% fully tested.

All that's needed is a few lines of python logic to string them together.

The details can be found at:
https://github.com/django/django/pull/324/files
https://github.com/g1smd/django/blob/master/django/contrib/localflavor/gb/forms.py

My python foo is almost zero. Anyone care to have a go at getting this to work?

RegEx 1 checks the user entered something that looks like a GB telephone number:
020 3000 5555
02075 567 234
0114 223 4567
01145 345 567
+44 1213 456 789
00 44 (0) 1697 73555
011 44 11 4890 2345
and several other formats, without worrying if the format is correct for this particular number (but read on). It allows for national or international format, even for two common international dial prefixes. What is most important is that the user enters the right number of digits. Don't constrain the user to use a particular format for entry.
"Be lenient in what you accept, be strict in what you send." (Postel's Law)

RegEx 2 extracts the NSN part of the number in $2, with "44" or NULL in $1 (so you know if international or national format was used on input), and any extension in $3. Store $1 and $3 for later. Send $2 on to RegEx 3.

RegEx 3 tests the NSN part of the number is in a valid range and has the right number of digits for that range (GB numbers can be 9 or 10 digits long). This RegEx pattern is very detailed. You can say that a number is possible or is invalid with this RegEx.

RegEx Group 4. Here, there's a bunch of RegEx patterns that specify how a GB number should be formatted, detailed by number length and initial digits. These rules cover all GB numbers.

The last bit is to add the 0 or +44 back on, and append the original extension number (if present) and present it back to the user.

020 3000 5555 => Valid: 020 3000 5555
02075 567 234 => Valid: 020 7556 7234
0114 223 4567 => Valid: 0114 223 4567
01145 345 567 => Valid: 0114 534 5567
+44 1213 456 789 => Valid: +44 121 345 6789
00 44 (0) 1697 73555 => Valid: +44 16977 3555
011 44 11 4890 2345 => Valid: +44 114 890 2345
025 4555 6777 => NOT VALID
0119 456 4567 => NOT VALID
0623 111 3456 => NOT VALID
0756 334556 => NOT VALID


The RegEx patterns and outline python code can be found here:
https://github.com/django/django/pull/324/files
https://github.com/g1smd/django/blob/master/django/contrib/localflavor/gb/forms.py



--- Last Edited by g1smd at 2012-10-10 01:19:49 ---
This is now also filed as ticket #18903 at https://code.djangoproject.com/ticket/18903
Hurrah!

We have a volunteer. Coding continues at:

https://github.com/django/django/pull/356
https://github.com/g1smd/django
and
https://github.com/g1smd/django-localflavor-GB-forms


--- Last Edited by g1smd at 2012-09-12 05:43:10 ---
Code finished. Documentation and tests added.

django / django / contrib / localflavor / gb / forms.py
(version: 2012-09-22)
"""
GB-specific Form helpers
"""

from __future__ import absolute_import, unicode_literals

import re

from django.contrib.localflavor.gb.gb_regions import GB_NATIONS_CHOICES, GB_REGION_CHOICES
from django.core.validators import EMPTY_VALUES
from django.forms.fields import CharField, Select
from django.forms import ValidationError
from django.utils.translation import ugettext_lazy as _


class GBPostcodeField(CharField):
    """
    A form field that validates its input is a UK postcode.

    The regular expression used is sourced from the schema for British Standard
    BS7666 address types: http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd

    The value is uppercased and a space added in the correct place, if required.
    """
    default_error_messages = {
        'invalid': _('Enter a valid postcode.'),
    }
    outcode_pattern = 'A-PR-UWYZ(0-9{1,2}|(A-HIK-Y0-9(|0-9|ABEHMNPRVWXY))|0-9A-HJKSTUW)'
    incode_pattern = '0-9ABD-HJLNP-UW-Z{2}'
    postcode_regex = re.compile(r'^(GIR 0AA|%s %s)$' % (outcode_pattern, incode_pattern))
    space_regex = re.compile(r' *(%s)$' % incode_pattern)

    def clean(self, value):
        value = super(GBPostcodeField, self).clean(value)
        if value in EMPTY_VALUES:
            return ''
        postcode = value.upper().strip()
        # Put a single space before the incode (second part).
        postcode = self.space_regex.sub(r' \1', postcode)
        if not self.postcode_regex.search(postcode):
            raise ValidationError(self.error_messages['invalid'])
        return postcode


class GBCountySelect(Select):
    """
    A Select widget that uses a list of UK Counties/Regions as its choices.
    """
    def __init__(self, attrs=None):
        super(GBCountySelect, self).__init__(attrs, choices=GB_REGION_CHOICES)


class GBNationSelect(Select):
    """
    A Select widget that uses a list of UK Nations as its choices.
    """
    def __init__(self, attrs=None):
        super(GBNationSelect, self).__init__(attrs, choices=GB_NATIONS_CHOICES)


class GBPhoneNumberField(CharField):
    """
     ==ACCEPTS==
     This table lists the valid accepted input formats for GB numbers.
     International:
        +          44_        null      20_3000_5000        null
       (+          44_(       0)_       20)_3000_5000       #5555
        00_        44)_       0)_(      121_555_7777       _#5555
        00_(       44)_(      0_        121)_555_7777       #555
       (00)_                  0_(       1750_615_777       _#555
       (00)_(                           1750)_615_777
       (00_                             19467_55555
        011_                            19467)_55555
        011_(                           1750_62555
       (011)_                           1750)_62555
       (011)_(                          16977_3555
       (011_                            16977)_3555
                                        500_777_888
                                        500)_777_888
     National:
        ->         ->         0         ^as above           ^as above
        ->         ->        (0         ^                   ^
     Pick one item from each column. Underscores represent spaces or hyphens.
     All number formats can also be matched without spaces or hyphens. The
     '#' character can also be an 'x'.

     "Be conservative in what you do, be liberal in what you accept from
      others."
     (Postel's Law)

     ==REJECTS==
     The following inputs are rejected:
     - international format numbers that do not begin with an item from column
       1 above,
     - international format numbers with country code other than 44,
     - national format numbers that do not begin with item in column 3 above,
     - numbers with more than 10 digits in NSN part,
     - numbers with less than 9 digits in NSN part (except for two special
       cases),
     - numbers with incorrect number of digits in NSN for number range,
     - numbers in ranges with NSN beginning 4 or 6 and other such non-valid
       ranges,
     - numbers with obviously non-GB formatting,
     - numbers with multiple contiguous spaces,
     - entries with letters and/or punctuation other than hyphens or brackets,
     - 116xxx, 118xxx, 1xx, 999.

     ==OUTPUTS==
     Irrespective of the format used for input, all valid numbers are output
     with a +44 prefix followed by a space and the 10 or 9 digit national
     number arranged in the correct 2+8, 3+7, 4+6, 4+5, 5+5, 5+4 or 3+6 format.
    """
    default_error_messages = {
        'number_format': _('Not a valid format and/or number length.'),
        'number_range': _('Not a valid range or not a valid number length for '
                         'this range')
    }

    def clean(self, value):
        super(GBPhoneNumberField, self).clean(value)
        if value in EMPTY_VALUES:
            return ''

        number_parts = {'prefix': '+44 ', 'NSN': '', 'extension': None}

        valid_gb_pattern = re.compile(r"""
        ^\(?
            (?:         # leading 00, 011 or + before 44 with optional (0)
                        # parentheses, hyphens and spaces optional
                (?:0(?:0|11)\)?[\s-]?\(?|\+)44\)?[\s-]?\(?(?:0\)?[\s-]?\(?)?
                |
                0                                            # leading 0
            )
            (?:
                \d{5}\)?[\s-]?\d{4,5}                        # [5+4][5+5]
                |
                \d{4}\)?[\s-]?(?:\d{5}|\d{3}[\s-]?\d{3})     # [4+5][4+6]
                |
                \d{3}\)?[\s-]?\d{3}[\s-]?\d{3,4}             # [3+6][3+7]
                |
                \d{2}\)?[\s-]?\d{4}[\s-]?\d{4}               # [2+8]
                |
                8(?:00[\s-]?11[\s-]?11|45[\s-]?46[\s-]?4\d)  # [0+7]
            )
            (?:
                (?:[\s-]?(?:x|ext\.?|\#)\d+)?    # optional extension number
            )
        $""", re.X)

        gb_number_parts = re.compile(r"""
        ^\(?
            (?:         # leading 00, 011 or + before 44 with optional (0)
                        # parentheses, hyphens and spaces optional
                (?:0(?:0|11)\)?[\s-]?\(?|\+)(44)\)?[\s-]?\(?(?:0\)?[\s-]?\(?)?
                |
                0                           # leading 0
            )
            (
                1-9\d{1,4}\)?[\s\d-]+     # NSN
            )
            (?:
                ((?:x|ext\.?|\#)\d+)?       # optional extension number
            )
        $""", re.X)

        # Check if number entered matches a valid format
        if not re.search(valid_gb_pattern, value):
            raise ValidationError(self.default_error_messages['number_format'])

        # Extract number parts: prefix, NSN, extension
        # group(1) contains "44" or None depending on whether number entered in
        # international or national format
        # group(2) contains NSN
        # group(3) contains extension
        m = re.search(gb_number_parts, value)
        if m.group:
            # Extract NSN part of GB number
            if m.group(2):
                # Trim NSN and remove space, hyphen or ')' if present
                translate_table = dict((ord(char), u'') for char in u')- ')
                number_parts['NSN'] = m.group(2).translate(
                    translate_table).strip()

                # Extract extension
                if m.group(3):
                    # Add a # and remove the x
                    number_parts['extension'] = '#' + m.group(3)[1:]
        if not number_parts:
            raise ValidationError(self.default_error_messages['number_format'])

        phone_number_nsn = number_parts['NSN']
        # Check if NSN entered is in a valid range
        if not valid_gb_phone_range(phone_number_nsn):
            raise ValidationError(self.default_error_messages['number_range'])

        return format_gb_phone_number(number_parts)


def valid_gb_phone_range(phone_number_nsn):
    """
    Verifies that phone_number_nsn is a valid UK phone number range by initial
    digits and length. Tests the NSN part for length and number range. Based on
    http://www.aa-asterisk.org.uk/index.php/Number_format
    http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_UK_Telephone_Numbers
    @param string phone_number_nsn
    @return boolean Returns boolean False if the phone number is not valid.
    """
    return re.match(re.compile(r"""
    ^(       # 2d with 10 digits [2+8] Landlines
        2(?:001378|30189|4017|80-46-9|9012)\d{7}
        |    # 11d, 1d1 with 10 digits [3+7] Landlines
        1(?:(?:1(?:30-48|460-4|5012789|70-49|801349)|210-7|310-8|4591\d|610-46-9))\d{6}
        |    # 1ddd (and 1dddd) with 10 digits [4+6][5+5] Landlines
        1(?:2(?:0024-9|23-9|33-79|41-689|5802-9|60-4789|7013-9|9\d)|3(?:0\d|2502-9|302-579|4680-46-9|71235679|924578)|4(?:003-9|202-5789|37\d|402-69|50-8|690-79|80-5789)|5(?:01235-9|2024-9|30145689|402-9|503-9|6\d|70-35-9|80-468|90-5789)|6(?:0034689|20-689|38013-9|41-467|50-69|613-9|70-8|90124578)|7(?:00246-9|2\d|3023678|403-9|50-46-9|6013-9|70-35-9|8024-9|902-9)|8(?:035-9|21-5789|302-578|40-578|5124-9|62-69|7\d|802-9|902569)|9(?:002-589|202-689|31-5789|42-9|50-579|6234789|70124578|8\d|92-57))\d{6}
        |    # 1ddd with 9 digits [4+5] Landlines
        1(?:2(?:0(?:461-4|872-9)|5451-79|76(?:2\d|31-8|61-6)|9(?:7(?:20-4|32-5)|8(?:22-8|70-4789|8345)))|3(?:6382-5|64723|8(?:4704-9|64015789))|4(?:0441-7|20(?:223|8\d)|6(?:0(?:30|52-57|61-8|72-8)|140)|8(?:052|87123))|5(?:24(?:32-79|6\d)|276\d|6(?:2606-9|686))|6(?:06(?:4\d|74-79)|295567|3534\d|47(?:24|61)|59(?:508|667|74)|9550-4)|7(?:26(?:613-9|70-7)|442\d|50(?:20-3|3-682|76))|8(?:2756\d|37(?:52-5|8239)|84(?:32-58))|9(?:0(?:0(?:61-8|85)|52\d)|3583|4(?:661-8|9(?:201|81))|63(?:23|31-4)|9561))\d{3}
        |    # 1ddd with 9 digits [4+5] Landlines (special case)
        176888234678\d{2}
        |    # 1dddd with 9 digits [5+4] Landlines
        1697723\d{3}
        |    # 7ddd (including 7624) (not 70, 76) with 10 digits [4+6] Mobile phones
        7(?:1-4\d\d|5(?:00-8|13-9\d|20-35-9)|624|7(?:01-9|1-7\d|802-9|90-689)|8(?:014-9\d|230-8)|9(?:04-9\d|102-9|20-35-9|30-689))\d{6}
        |    # 76 (excluding 7624) with 10 digits [2+8] Pagers
        76(?:0012|2356|40134|549|60-369|77|81|939)\d{6}
        |    # 800 with 9 or 10 digits, 808 with 10 digits, 500 with 9 digits [3+7][3+6] Freephone
        80(?:0\d{6,7}|8\d{7})|500\d{6}
        |    # 871, 872, 873, 90d, 91d, 980, 981, 982, 983 with 10 digits [3+7] Premium rate
        (?:87123|9(?:01\d|80-3))\d{7}
        |     # 842, 843, 844, 845, 870 with 10 digits [3+7] Business rate
        8(?:42-5|70)\d{7}
        |    # 70 with 10 digits [2+8] Personal numbers
        70\d{8}
        |    # 56 with 10 digits [2+8] LIECS&VoIP
        56\d{8}
        |    # 30d, 33d, 34d, 37d, 55 with 10 digits [3+7] UAN and [2+8] Corporate
        (?:30347|55)\d{8}
        |    # 800 1111, 845 46 4d with 7 digits [3+4] Freephone helplines
        8(?:001111|45464\d)
    )$
    """, re.X), phone_number_nsn)


def format_gb_nsn(phone_number_nsn):
    """
    Format GB phone numbers in correct format per number range. Based on
    http://www.aa-asterisk.org.uk/index.php/Number_format
    http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_UK_Telephone_Numbers
    created by @g1smd
    @param string phone_number_nsn Must be the 10 or 9 digit NSN part of the
        number.
    @return string phone_number_nsn Returns correctly formatted NSN by length
        and range.
    """
    nsn_length = len(phone_number_nsn)
    # RegEx patterns to define formatting by length and initial digits
    # [2+8] 2d, 55, 56, 70, 76 (not 7624) with 10 digits
    pattern28 = re.compile(r"^(?:2|556|7(?:0|6(?:013-9|20-35-9)))")
    capture28 = re.compile(r"^(\d{2})(\d{4})(\d{4})$")
    # [3+7] 11d, 1d1, 3dd, 80d, 84d, 87d, 9dd with 10 digits
    pattern37 = re.compile(r"^(?:1(?:1|\d1)|3|8(?:008|42-5|70-3)|9018)")
    capture37 = re.compile(r"^(\d{3})(\d{3})(\d{4})$")
    # [5+5] 1dddd (12 areas) with 10 digits
    pattern55 = re.compile(r"^(?:1(?:3873|5(?:242|39456)|697347|768347|9467))")
    capture55 = re.compile(r"^(\d{5})(\d{5})")
    # [5+4] 1dddd (1 area) with 9 digits
    pattern54 = re.compile(r"^(?:1697723)")
    capture54 = re.compile(r"^(\d{5})(\d{4})$")
    # [4+6] 1ddd, 7ddd (inc 7624) (not 70, 76) with 10 digits
    pattern46 = re.compile(r"^(?:1|7(?:1-5789|624))")
    capture46 = re.compile(r"^(\d{4})(\d{6})$")
    # [4+5] 1ddd (40 areas) with 9 digits
    pattern45 = re.compile(r"^(?:1(?:2(?:048|54|76|978)|3(?:634|846)|4(?:04|20|601|808)|5(?:247|626)|6(?:06|29|35|47|59|95)|7(?:26|44|50|68)|8(?:27|37|84)|9(?:005|35|469|63|95)))")
    capture45 = re.compile(r"^(\d{4})(\d{5})$")
    # [3+6] 500, 800 with 9 digits
    pattern36 = re.compile(r"^(?:5800)")
    capture36 = re.compile(r"^(\d{3})(\d{6})$")
    # [3+4] 8001111, 845464d with 7 digits
    pattern34 = re.compile(r"^(?:8(?:001111|45464\d))")
    capture34 = re.compile(r"^(\d{3})(\d{4})$")
    # Format numbers by leading digits and length
    if nsn_length is 10 and re.match(pattern28, phone_number_nsn):
        m = (re.search(capture28, phone_number_nsn))
        if m.group:
            phone_number_nsn = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3)
    elif nsn_length is 10 and re.match(pattern37, phone_number_nsn):
        m = (re.search(capture37, phone_number_nsn))
        if m.group:
            phone_number_nsn = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3)
    elif nsn_length is 10 and re.match(pattern55, phone_number_nsn):
        m = (re.search(capture55, phone_number_nsn))
        if m.group:
            phone_number_nsn = m.group(1) + ' ' + m.group(2)
    elif nsn_length is 9 and re.match(pattern54, phone_number_nsn):
        m = (re.search(capture54, phone_number_nsn))
        if m.group:
            phone_number_nsn = m.group(1) + ' ' + m.group(2)
    elif nsn_length is 10 and re.match(pattern46, phone_number_nsn):
        m = (re.search(capture46, phone_number_nsn))
        if m.group:
            phone_number_nsn = m.group(1) + ' ' + m.group(2)
    elif nsn_length is 9 and re.match(pattern45, phone_number_nsn):
        m = (re.search(capture45, phone_number_nsn))
        if m.group:
            phone_number_nsn = m.group(1) + ' ' + m.group(2)
    elif nsn_length is 9 and re.match(pattern36, phone_number_nsn):
        m = (re.search(capture36, phone_number_nsn))
        if m.group:
            phone_number_nsn = m.group(1) + ' ' + m.group(2)
    elif nsn_length is 7 and re.match(pattern34, phone_number_nsn):
        m = (re.search(capture34, phone_number_nsn))
        if m.group:
            phone_number_nsn = m.group(1) + ' ' + m.group(2)
    elif nsn_length > 5:
        # Default format for non-valid numbers (shouldn't ever get here)
        m = (re.search("^(\d)(\d{4})(\d*)$", phone_number_nsn))
        if m.group:
            phone_number_nsn = m.group(1) + ' ' + m.group(2) + ' ' + m.group(3)

    return phone_number_nsn


def format_gb_phone_number(number_parts):
    """
    Convert a valid United Kingdom phone number into standard +44 20 3000 5555
    #0001, +44 121 555 7788, +44 1970 223344, +44 1750 62555, +44 19467 55555
    or +44 16977 2333 international format or into national format with 0,
    according to entry format. Accepts a wide range of input formats and
    prefixes and re-formats the number taking into account the required 2+8,
    3+7, 4+6, 4+5, 5+5, 5+4 and 3+6 formats by number range.

    @param dict number_parts must be a valid nine or ten-digit number split
        into its constituent parts
    @return string phone_number
    """
    phone_number = number_parts['prefix'] + number_parts['NSN'] + \
        str(number_parts['extension'])

    if number_parts:
        # Grab the NSN part of GB number
        phone_number_nsn = number_parts['NSN']
        if not phone_number_nsn:
            return phone_number

        # Set prefix (will be +44 or 0)
        if 'prefix' in number_parts and number_parts['prefix'] is not None:
            phone_number = number_parts['prefix']

        # Remove spaces, hyphens, and brackets from NSN part of GB number
        translate_table = dict((ord(char), u'') for char in u')- ')
        phone_number_nsn = phone_number_nsn.translate(translate_table).strip()
        # Format NSN part of GB number
        phone_number += format_gb_nsn(phone_number_nsn)

        # Grab extension and trim it
        if 'extension' in number_parts and \
                number_parts['extension'] is not None:
            phone_number += ' ' + number_parts['extension'].strip()

    return phone_number



--- Last Edited by g1smd at 2012-10-10 01:23:33 ---
jango / tests / regressiontests / localflavor / gb / tests.py
(version: 2012-09-22)
from __future__ import unicode_literals

from django.contrib.localflavor.gb.forms import (
    GBPostcodeField, GBPhoneNumberField
)

from django.test import SimpleTestCase


class GBLocalFlavorTests(SimpleTestCase):
    def test_GBPostcodeField(self):
        error_invalid = ['Enter a valid postcode.']
        valid = {
            'BT32 4PX': 'BT32 4PX',
            'GIR 0AA': 'GIR 0AA',
            'BT324PX': 'BT32 4PX',
            ' so11aa ': 'SO1 1AA',
            ' so1  1aa ': 'SO1 1AA',
            'G2 3wt': 'G2 3WT',
            'EC1A 1BB': 'EC1A 1BB',
            'Ec1a1BB': 'EC1A 1BB',
        }
        invalid = {
            '1NV 4L1D': error_invalid,
            '1NV4L1D': error_invalid,
            ' b0gUS': error_invalid,
        }
        self.assertFieldOutput(GBPostcodeField, valid, invalid)
        valid = {}
        invalid = {
            '1NV 4L1D': ['Enter a postcode!'],
        }
        kwargs = {'error_messages': {'invalid': 'Enter a postcode!'}}
        self.assertFieldOutput(GBPostcodeField, valid, invalid, field_kwargs=kwargs)

    def test_GBPhoneNumberField(self):
        valid = {
            '020 3000 5555': '+44 20 3000 5555',
            '(020) 3000 5555': '+44 20 3000 5555',
            '+44 20 3000 5555': '+44 20 3000 5555',
            '0203 000 5555': '+44 20 3000 5555',
            '(0203) 000 5555': '+44 20 3000 5555',
            '02030 005 555': '+44 20 3000 5555',
            '+44 (0) 20 3000 5555': '+44 20 3000 5555',
            '+44(0)203 000 5555': '+44 20 3000 5555',
            '00 (44) 2030 005 555': '+44 20 3000 5555',
            '(+44 203) 000 5555': '+44 20 3000 5555',
            '(+44) 203 000 5555': '+44 20 3000 5555',
            '011 44 203 000 5555': '+44 20 3000 5555',
            '020-3000-5555': '+44 20 3000 5555',
            '(020)-3000-5555': '+44 20 3000 5555',
            '+44-20-3000-5555': '+44 20 3000 5555',
            '0203-000-5555': '+44 20 3000 5555',
            '(0203)-000-5555': '+44 20 3000 5555',
            '02030-005-555': '+44 20 3000 5555',
            '+44-(0)-20-3000-5555': '+44 20 3000 5555',
            '+44(0)203-000-5555': '+44 20 3000 5555',
            '00-(44)-2030-005-555': '+44 20 3000 5555',
            '(+44-203)-000-5555': '+44 20 3000 5555',
            '(+44)-203-000-5555': '+44 20 3000 5555',
            '011-44-203-000-5555': '+44 20 3000 5555',
            '0114 223 4567': '+44 114 223 4567',
            '01142 345 567': '+44 114 234 5567',
            '01415 345 567': '+44 141 534 5567',
            '+44 1213 456 789': '+44 121 345 6789',
            '00 44 (0) 1697 73555': '+44 16977 3555',
            '011 44 14 1890 2345': '+44 141 890 2345',
            '011 44 11 4345 2345': '+44 114 345 2345',
            '020 3000 5000': '+44 20 3000 5000',
            '0121 555 7777': '+44 121 555 7777',
            '01750 615777': '+44 1750 615777',
            '019467 55555': '+44 19467 55555',
            '01750 62555': '+44 1750 62555',
            '016977 3555': '+44 16977 3555',
            '0500 777888': '+44 500 777888',
            '020 7000 9000 x4567': '+44 20 7000 9000 #4567',
            '020 7000 9000 #4567': '+44 20 7000 9000 #4567'
        }
        errors = GBPhoneNumberField.default_error_messages
        messages = {
            'number_format': [errors['number_format'].translate('gb')],
            'number_range': [errors['number_range'].translate('gb')]
        }
        invalid = {
            '011 44 203 000 5555 5': messages['number_format'],
            '+44 20 300 5555': messages['number_format'],
            '025 4555 6777': messages['number_range'],
            '0119 456 4567': messages['number_range'],
            '0623 111 3456': messages['number_range'],
            '0756 334556': messages['number_range'],
            '020 5000 5000': messages['number_range'],
            '0171 555 7777': messages['number_range'],
            '01999 777888': messages['number_range'],
            '01750 61777': messages['number_range'],
            '020 7000 9000 ext. 4567': messages['number_format']
        }
        self.assertFieldOutput(GBPhoneNumberField, valid, invalid)


--- Last Edited by g1smd at 2012-10-10 01:42:58 ---





Powered by Sphene Community Tools