diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2013-05-17 12:46:27 +0200 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2013-06-08 14:45:39 +0200 |
commit | 2259cbb09e419e56c355efdbd865f99127d559c5 (patch) | |
tree | 736b02f87d6f1240ae14a5dba118a617cb0b688b | |
parent | 07c66e13b3928fb92fd0e537e23d3c5be2ad8956 (diff) |
Implement validate() for Spanish numbers
-rw-r--r-- | stdnum/es/cif.py | 71 | ||||
-rw-r--r-- | stdnum/es/dni.py | 36 | ||||
-rw-r--r-- | stdnum/es/nie.py | 40 | ||||
-rw-r--r-- | stdnum/es/nif.py | 57 |
4 files changed, 134 insertions, 70 deletions
diff --git a/stdnum/es/cif.py b/stdnum/es/cif.py index 679e596..eeb0e72 100644 --- a/stdnum/es/cif.py +++ b/stdnum/es/cif.py @@ -1,7 +1,7 @@ # cif.py - functions for handling Spanish fiscal numbers # coding: utf-8 # -# Copyright (C) 2012 Arthur de Jong +# Copyright (C) 2012, 2013 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -24,25 +24,32 @@ The CIF is a tax identification number for legal entities. It has 9 digits where the first digit is a letter (denoting the type of entity) and the last is a check digit (which may also be a letter). ->>> compact('J-99216582') +>>> validate('J99216582') 'J99216582' ->>> is_valid('J99216582') -True ->>> is_valid('J99216583') # invalid check digit -False ->>> is_valid('M-1234567-L') -True ->>> is_valid('O-1234567-L') # invalid first character -False +>>> validate('J99216583') # invalid check digit +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> validate('J992165831') # too long +Traceback (most recent call last): + ... +InvalidLength: ... +>>> validate('M-1234567-L') +'M1234567L' +>>> validate('O-1234567-L') # invalid first character +Traceback (most recent call last): + ... +InvalidFormat: ... >>> split('A13 585 625') ('A', '13', '58562', '5') """ from stdnum import luhn from stdnum.es import dni +from stdnum.exceptions import * -__all__ = ['compact', 'is_valid', 'split'] +__all__ = ['compact', 'validate', 'is_valid', 'split'] # use the same compact function as DNI @@ -57,28 +64,40 @@ def calc_check_digits(number): return check + 'JABCDEFGHI'[int(check)] -def is_valid(number): +def validate(number): """Checks to see if the number provided is a valid DNI number. This checks the length, formatting and check digit.""" - try: - number = compact(number) - except: - return False - if len(number) != 9 or not number[1:-1].isdigit(): - return False + number = compact(number) + if not number[1:-1].isdigit(): + raise InvalidFormat() + if len(number) != 9: + raise InvalidLength() if number[0] in 'KLM': # K: Spanish younger than 14 year old # L: Spanish living outside Spain without DNI # M: granted the tax to foreigners who have no NIE # these use the old checkdigit algorithm (the DNI one) - return number[-1] == dni.calc_check_digit(number[1:-1]) - # there seems to be conflicting information on which organisation types - # should have which type of check digit (alphabetic or numeric) so - # we support either here - if number[0] in 'ABCDEFGHJNPQRSUVW': - return number[-1] in calc_check_digits(number[:-1]) - # anything else is invalid - return False + if number[-1] != dni.calc_check_digit(number[1:-1]): + raise InvalidChecksum() + elif number[0] in 'ABCDEFGHJNPQRSUVW': + # there seems to be conflicting information on which organisation types + # should have which type of check digit (alphabetic or numeric) so + # we support either here + if number[-1] not in calc_check_digits(number[:-1]): + raise InvalidChecksum() + else: + # anything else is invalid + raise InvalidFormat() + return number + + +def is_valid(number): + """Checks to see if the number provided is a valid DNI number. This + checks the length, formatting and check digit.""" + try: + return bool(validate(number)) + except ValidationError: + return False def split(number): diff --git a/stdnum/es/dni.py b/stdnum/es/dni.py index 3d5c508..18d0954 100644 --- a/stdnum/es/dni.py +++ b/stdnum/es/dni.py @@ -1,7 +1,7 @@ # dni.py - functions for handling Spanish personal identity codes # coding: utf-8 # -# Copyright (C) 2012 Arthur de Jong +# Copyright (C) 2012, 2013 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -26,14 +26,19 @@ digit is a checksum letter. Foreign nationals, since 2010 are issued an NIE (Número de Identificación de Extranjeros, Foreigner's Identity Number) instead. ->>> compact('54362315-K') +>>> validate('54362315-K') '54362315K' ->>> is_valid('54362315-K') -True ->>> is_valid('54362315Z') # invalid check digit -False +>>> validate('54362315Z') # invalid check digit +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> validate('54362315') # digit missing +Traceback (most recent call last): + ... +InvalidLength: ... """ +from stdnum.exceptions import * from stdnum.util import clean @@ -49,12 +54,23 @@ def calc_check_digit(number): return 'TRWAGMYFPDXBNJZSQVHLCKE'[int(number) % 23] +def validate(number): + """Checks to see if the number provided is a valid DNI number. This + checks the length, formatting and check digit.""" + number = compact(number) + if not number[:-1].isdigit(): + raise InvalidFormat() + if len(number) != 9: + raise InvalidLength() + if calc_check_digit(number[:-1]) != number[-1]: + raise InvalidChecksum() + return number + + def is_valid(number): """Checks to see if the number provided is a valid DNI number. This checks the length, formatting and check digit.""" try: - number = compact(number) - except: + return bool(validate(number)) + except ValidationError: return False - return number[:-1].isdigit() and len(number) == 9 and \ - calc_check_digit(number[:-1]) == number[-1] diff --git a/stdnum/es/nie.py b/stdnum/es/nie.py index fde7da0..9e510e6 100644 --- a/stdnum/es/nie.py +++ b/stdnum/es/nie.py @@ -1,7 +1,7 @@ # nie.py - functions for handling Spanish foreigner identity codes # coding: utf-8 # -# Copyright (C) 2012 Arthur de Jong +# Copyright (C) 2012, 2013 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -24,15 +24,20 @@ The NIE is an identification number for foreigners. It is a 9 digit number where the first digit is either X, Y or Z and last digit is a checksum letter. ->>> compact('x-2482300w') +>>> validate('x-2482300w') 'X2482300W' ->>> is_valid('x-2482300w') -True ->>> is_valid('x-2482300a') # invalid check digit -False +>>> validate('x-2482300a') # invalid check digit +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> validate('X2482300') # digit missing +Traceback (most recent call last): + ... +InvalidLength: ... """ from stdnum.es import dni +from stdnum.exceptions import * __all__ = ['compact', 'is_valid'] @@ -50,12 +55,23 @@ def calc_check_digit(number): return dni.calc_check_digit(number) +def validate(number): + """Checks to see if the number provided is a valid NIE. This checks + the length, formatting and check digit.""" + number = compact(number) + if not number[1:-1].isdigit() or number[:1] not in 'XYZ': + raise InvalidFormat() + if len(number) != 9: + raise InvalidLength() + if calc_check_digit(number[:-1]) != number[-1]: + raise InvalidChecksum() + return number + + def is_valid(number): - """Checks to see if the number provided is a valid DNI number. This - checks the length, formatting and check digit.""" + """Checks to see if the number provided is a valid NIE. This checks + the length, formatting and check digit.""" try: - number = compact(number) - except: + return bool(validate(number)) + except ValidationError: return False - return len(number) == 9 and number[1:-1].isdigit() and \ - number[0] in 'XYZ' and calc_check_digit(number[:-1]) == number[-1] diff --git a/stdnum/es/nif.py b/stdnum/es/nif.py index e1bc7df..7cd689e 100644 --- a/stdnum/es/nif.py +++ b/stdnum/es/nif.py @@ -1,7 +1,7 @@ # nif.py - functions for handling Spanish NIF (VAT) numbers # coding: utf-8 # -# Copyright (C) 2012 Arthur de Jong +# Copyright (C) 2012, 2013 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -30,18 +30,21 @@ entities and others). >>> compact('ES B-58378431') 'B58378431' ->>> is_valid('B64717838') -True ->>> is_valid('B64717839') # invalid check digit -False ->>> is_valid('54362315K') # resident -True ->>> is_valid('X-5253868-R') # foreign person -True +>>> validate('B64717838') +'B64717838' +>>> validate('B64717839') # invalid check digit +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> validate('54362315K') # resident +'54362315K' +>>> validate('X-5253868-R') # foreign person +'X5253868R' """ -from stdnum.util import clean from stdnum.es import dni, nie, cif +from stdnum.exceptions import * +from stdnum.util import clean def compact(number): @@ -53,20 +56,30 @@ def compact(number): return number -def is_valid(number): +def validate(number): """Checks to see if the number provided is a valid VAT number. This checks the length, formatting and check digit.""" - try: - number = compact(number) - except: - return False - if len(number) != 9 or not number[1:-1].isdigit(): - return False + number = compact(number) + if not number[1:-1].isdigit(): + raise InvalidFormat() + if len(number) != 9: + raise InvalidLength() if number[0].isdigit(): # natural resident - return dni.is_valid(number) - if number[0] in 'XYZ': + dni.validate(number) + elif number[0] in 'XYZ': # foreign natural person - return nie.is_valid(number) - # otherwise it has to be a valid CIF - return cif.is_valid(number) + nie.validate(number) + else: + # otherwise it has to be a valid CIF + cif.validate(number) + return number + + +def is_valid(number): + """Checks to see if the number provided is a valid VAT number. This checks + the length, formatting and check digit.""" + try: + return bool(validate(number)) + except ValidationError: + return False |