Ticket #3988: patch.4.diff

File patch.4.diff, 13.3 KB (added by ttarabula, 17 years ago)

Forgot to do an svn add before the svn diff

  • django/contrib/localflavor/ca/ca_provinces.py

     
     1"""
     2An alphabetical list of provinces and territories for use as `choices`
     3in a formfield., and a mapping of province misspellings/abbreviations to
     4normalized abbreviations
     5
     6Source: http://www.canada.gc.ca/othergov/prov_e.html
     7
     8This exists in this standalone file so that it's only imported into memory
     9when explicitly needed.
     10"""
     11
     12PROVINCE_CHOICES = (
     13    ('AB', 'Alberta'),
     14    ('BC', 'British Columbia'),
     15    ('MB', 'Manitoba'),
     16    ('NB', 'New Brunswick'),
     17    ('NF', 'Newfoundland and Labrador'),
     18    ('NT', 'Northwest Territories'),
     19    ('NS', 'Nova Scotia'),
     20    ('NU', 'Nunavut'),
     21    ('ON', 'Ontario'),
     22    ('PE', 'Prince Edward Island'),
     23    ('QC', 'Quebec'),
     24    ('SK', 'Saskatchewan'),
     25    ('YK', 'Yukon')
     26)
     27
     28PROVINCES_NORMALIZED = {
     29    'ab': 'AB',
     30    'alberta': 'AB',
     31    'bc': 'BC',
     32    'b.c.': 'BC',
     33    'british columbia': 'BC',
     34    'mb': 'MB',
     35    'manitoba': 'MB',
     36    'nf': 'NF',
     37    'newfoundland': 'NF',
     38    'newfoundland and labrador': 'NF',
     39    'nt': 'NT',
     40    'northwest territories': 'NT',
     41    'ns': 'NS',
     42    'nova scotia': 'NS',
     43    'nu': 'NU',
     44    'nunavut': 'NU',
     45    'on': 'ON',
     46    'ontario': 'ON',
     47    'pe': 'PE',
     48    'pei': 'PE',
     49    'p.e.i.': 'PE',
     50    'prince edward island': 'PE',
     51    'qc': 'QC',
     52    'quebec': 'QC',
     53    'sk': 'SK',
     54    'saskatchewan': 'SK',
     55    'yk': 'YK',
     56    'yukon': 'YK',
     57}
     58 No newline at end of file
  • django/contrib/localflavor/ca/forms.py

     
     1"""
     2Canada-specific Form helpers
     3"""
     4 
     5from django.newforms import ValidationError
     6from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
     7from django.newforms.util import smart_unicode
     8from django.utils.translation import gettext, ugettext
     9import re
     10 
     11phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
     12sin_re = re.compile(r"^(\d{3})-(\d{3})-(\d{3})$")
     13 
     14class CAPostalCodeField(RegexField):
     15    """Canadian postal code field."""
     16    def __init__(self, *args, **kwargs):
     17        super(CAPostalCodeField, self).__init__(r'^[ABCEGHJKLMNPRSTVXYZ]\d[A-Z] \d[A-Z]\d$',
     18            max_length=None, min_length=None,
     19            error_message=gettext(u'Enter a postal code in the format XXX XXX.'),
     20            *args, **kwargs)
     21 
     22class CAPhoneNumberField(Field):
     23    """Canadian phone number field."""
     24    def clean(self, value):
     25        """Validate a phone number.
     26        """
     27        super(CAPhoneNumberField, self).clean(value)
     28        if value in EMPTY_VALUES:
     29            return u''
     30        value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
     31        m = phone_digits_re.search(value)
     32        if m:
     33            return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
     34        raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.')
     35
     36class CAProvinceField(Field):
     37    """
     38    A form field that validates its input is a Canadian province name or abbreviation.
     39    It normalizes the input to the standard two-leter postal service
     40    abbreviation for the given province.
     41    """
     42    def clean(self, value):
     43        from ca_provinces import PROVINCES_NORMALIZED
     44        super(CAProvinceField, self).clean(value)
     45        if value in EMPTY_VALUES:
     46            return u''
     47        try:
     48            value = value.strip().lower()
     49        except AttributeError:
     50            pass
     51        else:
     52            try:
     53                return PROVINCES_NORMALIZED[value.strip().lower()].decode('ascii')
     54            except KeyError:
     55                pass
     56        raise ValidationError(u'Enter a Canadian province or territory.')
     57 
     58class CAProvinceSelect(Select):
     59    """
     60    A Select widget that uses a list of Canadian provinces and
     61    territories as its choices.
     62    """
     63    def __init__(self, attrs=None):
     64        from ca_provinces import PROVINCE_CHOICES # relative import
     65        super(CAProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
     66           
     67class CASocialInsuranceNumberField(Field):
     68    """
     69    A Canadian Social Insurance Number (SIN).
     70
     71    Checks the following rules to determine whether the number is valid:
     72
     73        * Conforms to the XXX-XXX-XXXX format.
     74        * Passes the check digit process "Luhn Algorithm"
     75             See: http://en.wikipedia.org/wiki/Social_Insurance_Number
     76    """
     77    def clean(self, value):
     78        super(CASocialInsuranceNumberField, self).clean(value)
     79        if value in EMPTY_VALUES:
     80            return u''
     81        msg = ugettext('Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.')
     82        match = re.match(sin_re, value)
     83        if not match:
     84            raise ValidationError(msg)
     85           
     86        number = u'%s-%s-%s' % (match.group(1), match.group(2), match.group(3))   
     87        check_number = u'%s%s%s' % (match.group(1), match.group(2), match.group(3))
     88        if not self.luhn_checksum_is_valid(check_number):
     89            raise ValidationError(msg)
     90        return number
     91       
     92    def luhn_checksum_is_valid(self, number):
     93        """
     94        Checks to make sure that the SIN passes a luhn mod-10 checksum
     95        See: http://en.wikipedia.org/wiki/Luhn_algorithm
     96        """
     97
     98        sum = 0
     99        num_digits = len(number)
     100        oddeven = num_digits & 1
     101
     102        for count in range(0, num_digits):
     103            digit = int(number[count])
     104
     105            if not (( count & 1 ) ^ oddeven ):
     106                digit = digit * 2
     107            if digit > 9:
     108                digit = digit - 9
     109
     110            sum = sum + digit
     111
     112        return ( (sum % 10) == 0 )
     113 No newline at end of file
  • tests/regressiontests/forms/localflavor.py

     
    18181818u''
    18191819>>> f.clean(u'')
    18201820u''
     1821
     1822# CAPostalCodeField ##############################################################
     1823
     1824CAPostalCodeField validates that the data is a six-character Canadian postal code.
     1825>>> from django.contrib.localflavor.ca.forms import CAPostalCodeField
     1826>>> f = CAPostalCodeField()
     1827>>> f.clean('T2S 2H7')
     1828u'T2S 2H7'
     1829>>> f.clean('T2S 2H')
     1830Traceback (most recent call last):
     1831...
     1832ValidationError: [u'Enter a postal code in the format XXX XXX.']
     1833>>> f.clean('2T6 H8I')
     1834Traceback (most recent call last):
     1835...
     1836ValidationError: [u'Enter a postal code in the format XXX XXX.']
     1837>>> f.clean('T2S2H')
     1838Traceback (most recent call last):
     1839...
     1840ValidationError: [u'Enter a postal code in the format XXX XXX.']
     1841>>> f.clean(90210)
     1842Traceback (most recent call last):
     1843...
     1844ValidationError: [u'Enter a postal code in the format XXX XXX.']
     1845>>> f.clean(None)
     1846Traceback (most recent call last):
     1847...
     1848ValidationError: [u'This field is required.']
     1849>>> f.clean('')
     1850Traceback (most recent call last):
     1851...
     1852ValidationError: [u'This field is required.']
     1853>>> f = CAPostalCodeField(required=False)
     1854>>> f.clean('T2S 2H7')
     1855u'T2S 2H7'
     1856>>> f.clean('T2S2H7')
     1857Traceback (most recent call last):
     1858...
     1859ValidationError: [u'Enter a postal code in the format XXX XXX.']
     1860>>> f.clean('T2S 2H')
     1861Traceback (most recent call last):
     1862...
     1863ValidationError: [u'Enter a postal code in the format XXX XXX.']
     1864>>> f.clean('2T6 H8I')
     1865Traceback (most recent call last):
     1866...
     1867ValidationError: [u'Enter a postal code in the format XXX XXX.']
     1868>>> f.clean('T2S2H')
     1869Traceback (most recent call last):
     1870...
     1871ValidationError: [u'Enter a postal code in the format XXX XXX.']
     1872>>> f.clean(90210)
     1873Traceback (most recent call last):
     1874...
     1875ValidationError: [u'Enter a postal code in the format XXX XXX.']
     1876>>> f.clean(None)
     1877u''
     1878>>> f.clean('')
     1879u''
     1880
     1881# CAPhoneNumberField ##########################################################
     1882
     1883CAPhoneNumberField validates that the data is a valid Canadian phone number,
     1884including the area code. It's normalized to XXX-XXX-XXXX format.
     1885Note: This test is exactly the same as the USPhoneNumberField except using a real
     1886Candian area code
     1887
     1888>>> from django.contrib.localflavor.ca.forms import CAPhoneNumberField
     1889>>> f = CAPhoneNumberField()
     1890>>> f.clean('403-555-1212')
     1891u'403-555-1212'
     1892>>> f.clean('4035551212')
     1893u'403-555-1212'
     1894>>> f.clean('403 555-1212')
     1895u'403-555-1212'
     1896>>> f.clean('(403) 555-1212')
     1897u'403-555-1212'
     1898>>> f.clean('403 555 1212')
     1899u'403-555-1212'
     1900>>> f.clean('403.555.1212')
     1901u'403-555-1212'
     1902>>> f.clean('403.555-1212')
     1903u'403-555-1212'
     1904>>> f.clean(' (403) 555.1212 ')
     1905u'403-555-1212'
     1906>>> f.clean('555-1212')
     1907Traceback (most recent call last):
     1908...
     1909ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
     1910>>> f.clean('403-55-1212')
     1911Traceback (most recent call last):
     1912...
     1913ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
     1914>>> f.clean(None)
     1915Traceback (most recent call last):
     1916...
     1917ValidationError: [u'This field is required.']
     1918>>> f.clean('')
     1919Traceback (most recent call last):
     1920...
     1921ValidationError: [u'This field is required.']
     1922
     1923>>> f = CAPhoneNumberField(required=False)
     1924>>> f.clean('403-555-1212')
     1925u'403-555-1212'
     1926>>> f.clean('4035551212')
     1927u'403-555-1212'
     1928>>> f.clean('403 555-1212')
     1929u'403-555-1212'
     1930>>> f.clean('(403) 555-1212')
     1931u'403-555-1212'
     1932>>> f.clean('403 555 1212')
     1933u'403-555-1212'
     1934>>> f.clean('403.555.1212')
     1935u'403-555-1212'
     1936>>> f.clean('403.555-1212')
     1937u'403-555-1212'
     1938>>> f.clean(' (403) 555.1212 ')
     1939u'403-555-1212'
     1940>>> f.clean('555-1212')
     1941Traceback (most recent call last):
     1942...
     1943ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
     1944>>> f.clean('403-55-1212')
     1945Traceback (most recent call last):
     1946...
     1947ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
     1948>>> f.clean(None)
     1949u''
     1950>>> f.clean('')
     1951u''
     1952
     1953# CAProvinceField ################################################################
     1954
     1955CAProvinceField validates that the data is either an abbreviation or name of a
     1956Canadian province.
     1957>>> from django.contrib.localflavor.ca.forms import CAProvinceField
     1958>>> f = CAProvinceField()
     1959>>> f.clean('ab')
     1960u'AB'
     1961>>> f.clean('BC')
     1962u'BC'
     1963>>> f.clean('nova scotia')
     1964u'NS'
     1965>>> f.clean('  manitoba ')
     1966u'MB'
     1967>>> f.clean('T2S 2H7')
     1968Traceback (most recent call last):
     1969...
     1970ValidationError: [u'Enter a Canadian province or territory.']
     1971>>> f.clean(None)
     1972Traceback (most recent call last):
     1973...
     1974ValidationError: [u'This field is required.']
     1975>>> f.clean('')
     1976Traceback (most recent call last):
     1977...
     1978ValidationError: [u'This field is required.']
     1979
     1980>>> f = CAProvinceField(required=False)
     1981>>> f.clean('ab')
     1982u'AB'
     1983>>> f.clean('BC')
     1984u'BC'
     1985>>> f.clean('nova scotia')
     1986u'NS'
     1987>>> f.clean('  manitoba ')
     1988u'MB'
     1989>>> f.clean('T2S 2H7')
     1990Traceback (most recent call last):
     1991...
     1992ValidationError: [u'Enter a Canadian province or territory.']
     1993>>> f.clean(None)
     1994u''
     1995>>> f.clean('')
     1996u''
     1997
     1998# CAProvinceSelect ###############################################################
     1999
     2000CAProvinceSelect is a Select widget that uses a list of Canadian provinces/territories
     2001as its choices.
     2002>>> from django.contrib.localflavor.ca.forms import CAProvinceSelect
     2003>>> w = CAProvinceSelect()
     2004>>> print w.render('province', 'AB')
     2005<select name="province">
     2006<option value="AB" selected="selected">Alberta</option>
     2007<option value="BC">British Columbia</option>
     2008<option value="MB">Manitoba</option>
     2009<option value="NB">New Brunswick</option>
     2010<option value="NF">Newfoundland and Labrador</option>
     2011<option value="NT">Northwest Territories</option>
     2012<option value="NS">Nova Scotia</option>
     2013<option value="NU">Nunavut</option>
     2014<option value="ON">Ontario</option>
     2015<option value="PE">Prince Edward Island</option>
     2016<option value="QC">Quebec</option>
     2017<option value="SK">Saskatchewan</option>
     2018<option value="YK">Yukon</option>
     2019</select>
     2020
     2021# CASocialInsuranceNumberField #################################################
     2022>>> from django.contrib.localflavor.ca.forms import CASocialInsuranceNumberField
     2023>>> f = CASocialInsuranceNumberField()
     2024>>> f.clean('046-454-286')
     2025u'046-454-286'
     2026>>> f.clean('046-454-287')
     2027Traceback (most recent call last):
     2028...
     2029ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
     2030>>> f.clean('046 454 286')
     2031Traceback (most recent call last):
     2032...
     2033ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
     2034>>> f.clean('046-44-286')
     2035Traceback (most recent call last):
     2036...
     2037ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
     2038
    18212039"""
  • AUTHORS

     
    274274    Swaroop C H <http://www.swaroopch.info>
    275275    Aaron Swartz <http://www.aaronsw.com/>
    276276    Ville Säävuori <http://www.unessa.net/>
     277    Tyler Tarabula <tyler.tarabula@gmail.com>
    277278    Tyson Tate <tyson@fallingbullets.com>
    278279    Frank Tegtmeyer <fte@fte.to>
    279280    thebjorn <bp@datakortet.no>
Back to Top