lists.arthurdejong.org
RSS feed

python-stdnum branch master updated. 1.1-28-gec9bcb0

[Date Prev][Date Next] [Thread Prev][Thread Next]

python-stdnum branch master updated. 1.1-28-gec9bcb0



This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-stdnum".

The branch, master has been updated
       via  ec9bcb0f13971b70e40dff7a6de3d4744ee4ea61 (commit)
       via  fd0cfd9f894c7f6750bc9e86700632591d70b0f3 (commit)
       via  38ed9c0beeed897e14c4bcd46ee15e29d81239ed (commit)
       via  d413f953b848bd67e0f5267d3649d26e20d7c04b (commit)
       via  3d1dbbb9c24e377374341e489e62edb1dfc5f360 (commit)
       via  222a87ef324f66baf8113020b41d336c459ab847 (commit)
       via  e045c710ae59d0c74c690c5bfe2111b43738aa45 (commit)
      from  36217ac8d09f0de594b1ba9b17b435329c16548c (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://arthurdejong.org/git/python-stdnum/commit/?id=ec9bcb0f13971b70e40dff7a6de3d4744ee4ea61

commit ec9bcb0f13971b70e40dff7a6de3d4744ee4ea61
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Mon Oct 5 12:11:23 2015 +0200

    Add Mexican RFC number
    
    This adds support for the Mexican tax number RFC (Registro Federal de
    Contribuyentes).
    
    This module includes a number of checks on the number but the validation
    of the last check digit is disabled by default because a large number of
    numbers were found that were otherwise valid but had an invalid check
    digit.

diff --git a/stdnum/mx/__init__.py b/stdnum/mx/__init__.py
new file mode 100644
index 0000000..6c8c183
--- /dev/null
+++ b/stdnum/mx/__init__.py
@@ -0,0 +1,24 @@
+# __init__.py - collection of Mexican numbers
+# coding: utf-8
+#
+# Copyright (C) 2015 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
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+"""Collection of Mexican numbers."""
+
+# provide vat as an alias
+from stdnum.mx import rfc as vat
diff --git a/stdnum/mx/rfc.py b/stdnum/mx/rfc.py
new file mode 100644
index 0000000..72084e6
--- /dev/null
+++ b/stdnum/mx/rfc.py
@@ -0,0 +1,150 @@
+# rfc.py - functions for handling Mexican tax numbers
+# coding: utf-8
+#
+# Copyright (C) 2015 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
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+"""RFC (Registro Federal de Contribuyentes, Mexican tax number).
+
+This number is used to identify individuals and companies for tax purposes.
+
+The company number is 12 digits where the first 3 letters or digits are
+derived from the name of the company, the following 6 contain the date of
+incorporation, followed by 3 check digits.
+
+Personal numbers consist of 13 digits where the first 4 characters from the
+person's name, followed by their birth date and 3 check digits.
+
+The first two check digits are calculated based on the person's or company's
+full name. The last check digit is calculated over all the preceding digits
+in the number. However, it seems a lot of numbers are in use with invalid
+check digits so this test is disabled by default.
+
+More information can be found at:
+  
http://www.sisi.org.mx/jspsi/documentos/2005/seguimiento/06101/0610100162005_065.doc
+  
https://es.wikipedia.org/wiki/Registro_Federal_de_Contribuyentes_(M%C3%A9xico)
+
+>>> validate('GODE 561231 GR8')  # personal number
+'GODE561231GR8'
+>>> validate('MAB-930714-8T4')  # company number
+'MAB9307148T4'
+>>> validate('COMG-600703')  # personal number without serial
+'COMG600703'
+>>> validate('VACE-460910-SX6')
+'VACE460910SX6'
+>>> validate('VACE-460910-SX6', validate_check_digits=True)
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> format('GODE561231GR8')
+'GODE 561231 GR8'
+"""
+
+import datetime
+import re
+
+from stdnum.exceptions import *
+from stdnum.util import clean
+
+
+# regular expression for matching numbers
+_rfc_re = re.compile(r'^[A-Z&Ñ]{3,4}[0-9]{6}[0-9A-Z]{0,5}$')
+
+
+# regular expression for matching the last 3 check digits
+_check_digits_re = re.compile(r'^[1-9A-V][1-9A-Z][0-9A]$')
+
+
+# these values should not appear as first part of a personal number
+_name_blacklist = set([
+    'BUEI', 'BUEY', 'CACA', 'CACO', 'CAGA', 'CAGO', 'CAKA', 'CAKO', 'COGE',
+    'COJA', 'COJE', 'COJI', 'COJO', 'CULO', 'FETO', 'GUEY', 'JOTO', 'KACA',
+    'KACO', 'KAGA', 'KAGO', 'KAKA', 'KOGE', 'KOJO', 'KULO', 'MAME', 'MAMO',
+    'MEAR', 'MEAS', 'MEON', 'MION', 'MOCO', 'MULA', 'PEDA', 'PEDO', 'PENE',
+    'PUTA', 'PUTO', 'QULO', 'RATA', 'RUIN',
+])
+
+
+# characters used for checksum calculation,
+_alphabet = '0123456789ABCDEFGHIJKLMN&OPQRSTUVWXYZ Ñ'
+
+
+def compact(number):
+    """Convert the number to the minimal representation. This strips
+    surrounding whitespace and separation dash."""
+    return clean(number, '-_ ').upper().strip()
+
+
+def _get_date(number):
+    """Convert the part of the number that represents a date into a
+    datetime. Note that the century may be incorrect."""
+    year = int(number[0:2])
+    month = int(number[2:4])
+    day = int(number[4:6])
+    try:
+        return datetime.date(year + 2000, month, day)
+    except ValueError:
+        raise InvalidComponent()
+
+
+def calc_check_digit(number):
+    """Calculate the check digit. The number passed should not have the
+    check digit included."""
+    number = ('   ' + number)[-12:]
+    check = sum(_alphabet.index(n) * (13 - i) for i, n in enumerate(number))
+    return _alphabet[(11 - check) % 11]
+
+
+def validate(number, validate_check_digits=False):
+    """Checks to see if the number provided is a valid number."""
+    number = compact(number)
+    if not _rfc_re.match(number):
+        raise InvalidFormat()
+    if len(number) in (10, 13):
+        # number assigned to person
+        if number[:4] in _name_blacklist:
+            raise InvalidComponent()
+        _get_date(number[4:10])
+    elif len(number) == 12:
+        # number assigned to company
+        _get_date(number[3:9])
+    else:
+        raise InvalidLength()
+    if validate_check_digits and len(number) >= 12:
+        if not _check_digits_re.match(number[-3:]):
+            raise InvalidComponent()
+        if number[-1] != calc_check_digit(number[:-1]):
+            raise InvalidChecksum()
+    return number
+
+
+def is_valid(number, validate_check_digits=False):
+    """Checks to see if the number provided is a valid number."""
+    try:
+        return bool(validate(number, validate_check_digits))
+    except ValidationError:
+        return False
+
+
+def format(number, separator=' '):
+    """Reformat the passed number to the standard format."""
+    number = compact(number)
+    if len(number) == 12:
+        return separator.join((
+            number[:3], number[3:9], number[9:])).strip(separator)
+    return separator.join((
+        number[:4], number[4:10], number[10:])).strip(separator)
diff --git a/tests/test_mx_rfc.doctest b/tests/test_mx_rfc.doctest
new file mode 100644
index 0000000..57cb54b
--- /dev/null
+++ b/tests/test_mx_rfc.doctest
@@ -0,0 +1,531 @@
+test_mx_rfc.doctest - more detailed doctests for the stdnum.mx.rfc module
+
+Copyright (C) 2015 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
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA
+
+
+This file contains more detailed doctests for the stdnum.mx.rfc module.
+
+>>> from stdnum.mx import rfc
+>>> from stdnum.exceptions import *
+
+
+The six digits are supposed to form a valid date.
+
+>>> rfc.validate('ABCD 123456')
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+
+
+The last three digits are in a special alphabet and should only contain
+1-9A-V, 1-9A-Z and 0-9A for the last digits.
+
+>>> rfc.validate('AABN 821103 8Ñ2')
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+
+
+The first four digits of a personal number should not be one of the
+blacklisted words.
+
+>>> rfc.validate('CACA 580710 NF7')
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+
+
+Only personal numbers are allowed to be missing the "homoclave" (check
+digits) part.
+
+>>> rfc.validate('AKJ970902')
+Traceback (most recent call last):
+    ...
+InvalidLength: ...
+
+
+A large number of numbers that are in use appear to have invalid check
+digits. This has been found in about 1.5% of all numbers found. For this
+reason, by default, validation of check digits has been disabled and can be
+enabled explicitly.
+
+>>> rfc.validate('SIN 931116 9P8')
+'SIN9311169P8'
+>>> rfc.validate('SIN 931116 9P8', validate_check_digits=True)
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> rfc.validate('CCM 650122 I06')
+'CCM650122I06'
+>>> rfc.validate('CCM 650122 I06', validate_check_digits=True)
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+
+
+Some extra formatting checks:
+
+>>> rfc.format('VSM140430NQA')
+'VSM 140430 NQA'
+>>> rfc.format('ZUT A770215LK0')
+'ZUTA 770215 LK0'
+
+
+These have been found online and should all be valid numbers. Note that these
+numbers all have valid check digits (also see the list below).
+
+>>> numbers = '''
+...
+... &&&030828PX7
+... &JE040614N51
+... AA&0607148I0
+... AAA390128530
+... AAAA791128D63
+... AAAL730401TE0
+... AACA700913KZ0
+... AACC421231BH1
+... AADS251231CG0
+... AALC680929LH8
+... AAM090224BC2
+... AARR621113SN7
+... ABA130601BD3
+... ABH0507252D9
+... ACA120116TX5
+... ACO071219F51
+... AEAJ390701E82
+... AEL7407151YA
+... AEM100930B11
+... AHO120203E8A
+... ALD950921G27
+... ALE8401268K8
+... AMA990219PF8
+... AME040430UM8
+... AME110909530
+... AMM020222UT3
+... ANI0112176N8
+... AON0210014T5
+... AOX040831A59
+... AP&0305026J9
+... APA371201PQ7
+... AQU920317P4A
+... ARO020221DQ4
+... ASE9112306M9
+... ATB081212MN5
+... AUD000704II1
+... AUHF891016KE4
+... AWI1206064H1
+... AYP110530D73
+... B&D9605298Y3
+... BADY7101185W6
+... BEE070927MH0
+... BER090921FJ6
+... BIHC5111253I7
+... BLN130425JU7
+... BMI880419PR5
+... BNE110914EY0
+... BSP0603203U3
+... BUGA701115I43
+... CAR910506BW8
+... CBC900829152
+... CCS8512024CA
+... CDE110928FR0
+... CEG970917HY3
+... CEI111208UJ8
+... CET790711B43
+... CEX910718C75
+... CFE010608HC8
+... CGB000229SW0
+... CIG120628NQ1
+... CIN831107B41
+... CIT900525168
+... CLO070618EY6
+... CLO110607257
+... CLO850611371
+... CMA7708263Y7
+... CMA970306DZ8
+... CME990423373
+... CMI0507204U8
+... CMO101104D21
+... CNR100325T71
+... COI090127UY5
+... COML8103203QA
+... COP891005HV6
+... CPR0611212K8
+... CSB021029689
+... CSI050527PE4
+... CSI900816E23
+... CSM130516IT5
+... CSU000912EH0
+... CTE870318ANA
+... CTR0501281A7
+... CTS840406DB5
+... CTV080213S16
+... CUAF680927LM6
+... CVI961129D88
+... DAM121219GU4
+... DCA050617BJ7
+... DCF080331IP7
+... DCP1008179J4
+... DHO100211PP9
+... DIN130417NB8
+... DIP0405273R5
+... DIR070208V76
+... DIS9611059T1
+... DIV050625LE1
+... DMM120201G43
+... DMS121114BV6
+... DPU070904692
+... DVS120703FD1
+... ECM080228KF1
+... EDI000229CA3
+... EEM9110114W4
+... EGA060426LW6
+... EIA870112MW6
+... EIE080701SL6
+... EIM861215GH7
+... EIP971118EE0
+... EITM9103155L7
+... EMA001219M72
+... EME950412SS8
+... ENI731210FS2
+... ENP100804LU4
+... EPL031009LA3
+... EPM990712PX9
+... EPR920313DS8
+... ESI920217GY0
+... EUDC730505US6
+... EYA810212AB7
+... EYO121214DD5
+... FAM000229SB8
+... FCM0512093V7
+... FCR930924UP5
+... FDI060505DD8
+... FERL530506LL2
+... FLO9205187K8
+... FME780808PH2
+... FMP110620626
+... FPC960606SS7
+... FQU040210VB6
+... GABA930110DY7
+... GAD8509039E9
+... GAF091006GL7
+... GAGS8602119P9
+... GAI670926SX4
+... GBE910314CY9
+... GBM110523N11
+... GCT0205243T8
+... GEC091113R94
+... GEN060113JT9
+... GGS1306077E2
+... GIAI6703203N6
+... GIN130711BX1
+... GIN9806308G0
+... GLA1001272R3
+... GMA050607UA0
+... GMI920724CP5
+... GMO030628DI0
+... GMX0912018E6
+... GOAJ7101257MA
+... GOBM630601RQ6
+... GOVB6202103B1
+... GTL101217DPA
+... GUI990521N70
+... GURK651124IZ6
+... GYA010601HZ2
+... HAKC800506G89
+... HEA080829QE4
+... HEM881018M63
+... HIAD7004306I3
+... HIM950519AS3
+... HST051115KD6
+... HUM131108DJ7
+... IAG960627I24
+... ICR131219UR2
+... ICV111124GA3
+... ICW020809NG4
+... IEO861107K41
+... IET040122JP4
+... IET1402203U2
+... IJC090327V63
+... ILM130517SJ6
+... IME060217HN7
+... IPA090810Q33
+... ISD9609109M3
+... ITE040705LM7
+... ITM040310AX8
+... ITM7002044W3
+... ITM891121LZ9
+... ITO090804L92
+... IUS9207088R5
+... JET0811207A7
+... JINA4912084Z8
+... JJO021128CS9
+... JOFF550129TD7
+... KCO990630SQ4
+... KUC120227CP8
+... LBN120207CE8
+... LEAJ570610M32
+... LED070424K80
+... LIVR600908A58
+... LMX120112CH1
+... LRE050221F14
+... LTR101108SK5
+... LTS000117Q95
+... LUT0504217B1
+... MAC0501069H5
+... MAC050302QU4
+... MAE100225TF0
+... MALR850723RK4
+... MAOA800509SH5
+... MAPA600915DB4
+... MAR960628QU0
+... MAV890913NY0
+... MBU060512RE7
+... MCA851223JI9
+... MCP100710IH6
+... MCS830224156
+... MDM011001DD7
+... MECJ730513KC7
+... MELF7605095R6
+... MIR9812154E0
+... MIT110829255
+... MKE040510HW9
+... MLM020809894
+... MME120612IJ5
+... MME820427S6A
+... MME9710313Z4
+... MOCC891114BA9
+... MOD9904275G7
+... MRG900406M6A
+... MSI041208CR0
+... MSU121003LR3
+... MTR091125TJ8
+... MUÑ110218LJ6
+... MXS030318BP0
+... NAJ120705J5A
+... NARF561006LT9
+... NFI000511G42
+... NIC120302LE4
+... NOCJ750806BJA
+... OHA0204186H2
+... OIL080603P74
+... OIN970513LM7
+... OOM060208MC5
+... ORO040505KH3
+... ORS0011148U8
+... OVS041008711
+... PAP041025A11
+... PBC910219RI2
+... PCS091030DZA
+... PDI630218N32
+... PEL910625UQ4
+... PGT110128I84
+... PII040123JR9
+... PIN8709103A4
+... PIT1207186S3
+... PLA020617B95
+... PME8308184S4
+... PMI0110161Q4
+... PPM970110676
+... PPT991115IR3
+... PRA071201A18
+... PRA850314FE5
+... PRO060904RR8
+... QVI850529SP8
+... RABT551122827
+... RAO821016K97
+... RCV060828NE3
+... RDI841003QJ4
+... REG070627EF9
+... REI120227C54
+... RIGL6608198W7
+... RME960329V67
+... ROZS700918HL9
+... RRE010202L83
+... RUAA751115C42
+... RUAJ8104018GA
+... RZS9003238P5
+... SAGE661012E96
+... SALM760305JP4
+... SAVA810110EN5
+... SBR811009760
+... SCE000520HU0
+... SCI090109TZ2
+... SCO050124QL2
+... SDA8902091QA
+... SEP051121DU8
+... SES0601271U0
+... SGY100210UL2
+... SIA0803073Z2
+... SIM080104CM6
+... SIN9904064B4
+... SME011012Q43
+... SME020208GXA
+... SME060406U67
+... SME111212CA4
+... SOP0410217V5
+... SOP940502FF5
+... SOR9403107MA
+... SOTG740115G1A
+... SPL910701FD9
+... STP110106D88
+... TCS0104276P5
+... TEC0306066L6
+... TEE060928R87
+... TME930929DE1
+... TQI090928UR4
+... TSP931104UI0
+... UAI010212HW5
+... UEE110902V5A
+... UFA1010116X3
+... VBF951020KT3
+... VCA0903116M7
+... VCO960628NZ0
+... VEFC6503094Q6
+... VEO100223D10
+... VMI820313C9A
+... VMU930407NFA
+... VSM040108TS6
+... VSO090204AF1
+... XCO111215IM0
+... YAT000229588
+... ZEJ060728K11
+... ZENP8101128Y0
+... ZGU920526T43
+... ZZE040708QJ9
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not rfc.is_valid(x, 
validate_check_digits=True)]
+[]
+
+
+The following numbers were also found online, and while they appear to be in
+use and referencing existing persons or organisations, the check digit does
+not validate.
+
+>>> numbers = '''
+...
+... AAC0903183F6
+... AAMM450222AJ1
+... ALC920108P18
+... AMC020204AB7
+... AOM920820BEA
+... ASA971202EB5
+... ASE0804046M8
+... AÑE9902224Z4
+... BABC300126Q66
+... BAÑ930616R66
+... BER060923LW4
+... BFI981221MG0
+... BLM890223FH1
+... BOJR890112DB9
+... BOR071120HE7
+... CAMG590407QSA
+... CAMR620930HG5
+... CAVB360920196
+... CCB080911PV3
+... CCL020604CX0
+... CDO070410V77
+... CLA091217733
+... CLM9407017W4
+... CME030507A29
+... CME9809141L6
+... CME990816951
+... CMS071226LN2
+... COCA8007229UA
+... CPC080624C48
+... CTA071106464
+... CUP820427ID9
+... DBE051005PT3
+... DEKR6305193Q2
+... DES8707223AA
+... DJT031205MG4
+... DRA950811S25
+... EDG000413BF2
+... EME1006143T6
+... EQU810430193
+... FAE8509042W7
+... FIS0008226ZA
+... FISL7809158A0
+... FME9305279N0
+... FSA080813655
+... FSI900505I74
+... GIR940318DF0
+... GJO891005N53
+... GMA080728MJ0
+... GME9606038V6
+... GOC841221BK0
+... GWS860313JA3
+... HHO900507844
+... HME020215QTA
+... ICO990503PG4
+... IDE930601FJ4
+... IME0610197B2
+... ISM0403025G3
+... KAK030512QD7
+... KMN041126K5A
+... KZY041011E20
+... LME9405237U7
+... LMI0811119C5
+... LOCB6410225K0
+... LOMM8110052J4
+... MAEE620525S14
+... MALC721019EV6
+... MDI931014D37
+... MFA840320DX0
+... MGR070820G78
+... MOJO6101239H7
+... MPT000824LH7
+... MSA850111TE1
+... NIÑ7409256U1
+... NSN000704SY3
+... NYL850506BJ8
+... OIC060523UW1
+... OMD100907CJ4
+... OPP010927SA5
+... OTM090818KS6
+... PAC8608084O8
+... PEJE480914ES9
+... PERL640914HY9
+... PPA100118E37
+... PTS091204M83
+... ROCS550714PC0
+... SIG060311PN2
+... SIT060329RA7
+... SME100414QY9
+... SME9502015F6
+... SMP060331P74
+... SMR011108KB9
+... SOMF730101689
+... SSB9512118M1
+... STM000215AG9
+... TFS011012M18
+... TLO020509RK3
+... TME940420LV5
+... TORE4007065V7
+... TPM06111759A
+... TPT0202135S1
+... TPT890516JP5
+... VAME720111AA4
+... WME000218GK3
+... YLO031113IP4
+... YME9610251W6
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not rfc.is_valid(x)]
+[]

http://arthurdejong.org/git/python-stdnum/commit/?id=fd0cfd9f894c7f6750bc9e86700632591d70b0f3

commit fd0cfd9f894c7f6750bc9e86700632591d70b0f3
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Oct 4 22:28:06 2015 +0200

    Move finding VAT module to util
    
    This moves the finding of a VAT module to the util module so that it can
    be more easily re-used for non-EU countries.

diff --git a/stdnum/eu/vat.py b/stdnum/eu/vat.py
index d867e3b..94525d5 100644
--- a/stdnum/eu/vat.py
+++ b/stdnum/eu/vat.py
@@ -40,7 +40,7 @@ that country.
 """
 
 from stdnum.exceptions import *
-from stdnum.util import clean
+from stdnum.util import clean, get_vat_module
 
 
 country_codes = set([
@@ -69,10 +69,7 @@ def _get_cc_module(cc):
     if cc not in country_codes:
         return
     if cc not in _country_modules:
-        # do `from stdnum.CC import vat` instead of `import stdnum.CC.vat`
-        # to handle the case where vat is an alias
-        _country_modules[cc] = __import__(
-            'stdnum.%s' % cc, globals(), locals(), ['vat']).vat
+        _country_modules[cc] = get_vat_module(cc)
     return _country_modules[cc]
 
 
diff --git a/stdnum/util.py b/stdnum/util.py
index 420d363..74bd095 100644
--- a/stdnum/util.py
+++ b/stdnum/util.py
@@ -1,7 +1,7 @@
 # util.py - common utility functions
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012, 2013, 2015 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
@@ -23,6 +23,11 @@
 This module is meant for internal use by stdnum modules and is not
 guaranteed to remain stable and as such not part of the public API of
 stdnum.
+
+>>> get_vat_module('nl').__name__
+'stdnum.nl.btw'
+>>> get_vat_module('is').__name__
+'stdnum.is_.vsk'
 """
 
 import pkgutil
@@ -91,6 +96,13 @@ _char_map = dict(_mk_char_map({
     }))
 
 
+# mapping of country codes to internally used names
+# used in the get_vat_module() function
+_cc_translations = {
+    'el': 'gr', 'is': 'is_',
+}
+
+
 def _clean_chars(number):
     """Replace various Unicode characters with their ASCII counterpart."""
     return ''.join(_char_map.get(x, x) for x in number)
@@ -153,3 +165,10 @@ def get_module_list():
             module.__name__.replace('stdnum.', ''),
             get_module_name(module),
         )
+
+
+def get_vat_module(cc):
+    """Find the VAT number module based on the country code."""
+    cc = cc.lower()
+    cc = _cc_translations.get(cc, cc)
+    return __import__('stdnum.%s' % cc, globals(), locals(), ['vat']).vat

http://arthurdejong.org/git/python-stdnum/commit/?id=38ed9c0beeed897e14c4bcd46ee15e29d81239ed

commit 38ed9c0beeed897e14c4bcd46ee15e29d81239ed
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Oct 4 16:13:13 2015 +0200

    Update Colombian NIT checks
    
    This adds a number of tests for numbers found online. The length check
    has also been revisited because both shorter numbers and longer number
    have been found.
    
    This also updates the format() function to handle arbitrary length
    numbers.

diff --git a/stdnum/co/nit.py b/stdnum/co/nit.py
index 6884ce3..dbc4f1c 100644
--- a/stdnum/co/nit.py
+++ b/stdnum/co/nit.py
@@ -22,27 +22,17 @@
 
 """NIT (Número De Identificación Tributaria, Colombian identity code).
 
-This number, also referred to as RUT (Registro Unico Tributario) is a 10-digit
-code that includes a check digit.
+This number, also referred to as RUT (Registro Unico Tributario) is the
+Colombian business tax number.
 
 >>> validate('213.123.432-1')
 '2131234321'
->>> validate('2131234351')
-'2131234351'
->>> validate('2131234350')
+>>> validate('2131234325')
 Traceback (most recent call last):
     ...
 InvalidChecksum: ...
->>> validate('213123435')
-Traceback (most recent call last):
-    ...
-InvalidLength: ...
->>> validate('213123435A')
-Traceback (most recent call last):
-    ...
-InvalidFormat: ...
->>> format('2131234351')
-'213.123.435-1'
+>>> format('2131234321')
+'213.123.432-1'
 """
 
 from stdnum.exceptions import *
@@ -52,7 +42,7 @@ from stdnum.util import clean
 def compact(number):
     """Convert the number to the minimal representation. This strips
     surrounding whitespace and separation dash."""
-    return clean(number, '.-').upper().strip()
+    return clean(number, '.,- ').upper().strip()
 
 
 def calc_check_digit(number):
@@ -67,7 +57,7 @@ def validate(number):
     """Checks to see if the number provided is a valid number. This checks
     the length, formatting and check digit."""
     number = compact(number)
-    if len(number) != 10:
+    if not 8 <= len(number) <= 16:
         raise InvalidLength()
     if not number.isdigit():
         raise InvalidFormat()
@@ -88,5 +78,6 @@ def is_valid(number):
 def format(number):
     """Reformat the passed number to the standard format."""
     number = compact(number)
-    return (number[:-7] + '.' + number[-7:-4] + '.' +
-            number[-4:-1] + '-' + number[-1])
+    return ('.'.join(
+        number[i - 3:i] for i in reversed(range(-1, -len(number), -3))) +
+        '-' + number[-1])
diff --git a/tests/test_co_nit.doctest b/tests/test_co_nit.doctest
new file mode 100644
index 0000000..5999f9a
--- /dev/null
+++ b/tests/test_co_nit.doctest
@@ -0,0 +1,298 @@
+test_co_nit.doctest - more detailed doctests for the stdnum.co.nit module
+
+Copyright (C) 2015 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
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA
+
+
+This file contains more detailed doctests for the stdnum.co.nit module.
+
+>>> from stdnum.co import nit
+>>> from stdnum.exceptions import *
+
+
+Some more detailed checks. Some of these were previously in the module
+docstring.
+
+>>> nit.validate('213.123.432-1')
+'2131234321'
+>>> nit.validate('2131234351')
+'2131234351'
+>>> nit.validate('2131234351')
+'2131234351'
+>>> nit.validate('2131234')
+Traceback (most recent call last):
+    ...
+InvalidLength: ...
+>>> nit.validate('213123435A')
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> nit.validate('2131234350')
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+
+
+Extra checks for format function to see that it works with all kinds of
+lengths.
+
+>>> nit.format('123.456.789-0')
+'123.456.789-0'
+>>> nit.format('12.345.678.912-0')
+'12.345.678.912-0'
+>>> nit.format('1.234.567-0')
+'1.234.567-0'
+
+
+These have been found online and should all be valid numbers.
+
+>>> numbers = '''
+...
+... 1118534248-0
+... 15.252.525-0
+... 17.343.020-1
+... 35324530-0
+... 37547837-0
+... 375478370
+... 51.922.998-7
+... 52.238.803-1
+... 6.386.949-2
+... 79.308.960-7
+... 79.896.529.6
+... 79626331-8
+... 79627373-1
+... 796273731
+... 800.003.122-6
+... 800.020.672-7
+... 800.026.452-0
+... 800.043.909-6
+... 800.100.532-8
+... 800.184.048-4
+... 800.219.488-4
+... 800.231.969-4
+... 800.242.106-2
+... 800.249.704-9
+... 800088702-2
+... 800112806-2
+... 800130907-4
+... 800140949-6
+... 800216278-0
+... 800224808-8
+... 800224827-8
+... 800226098 - 4
+... 800227940-6
+... 800228175 - 2
+... 800229739-0
+... 800231967-1
+... 800231969-4
+... 800240882-0
+... 800242272-7
+... 800250119-1
+... 800251440-6
+... 800253055-2
+... 800256161 - 9
+... 804001273-5
+... 805.014.583-3
+... 805000427-1
+... 805001157-2
+... 805021984-2
+... 811.014.798-1
+... 811019263-6
+... 812.007.765-3
+... 819.006.966-8
+... 830.015.428-5
+... 830.025.281-2
+... 830.035.734-1
+... 830.036-334-1
+... 830.042.619-1
+... 830.056.202-3
+... 830.061.111-1
+... 830.096.401-3
+... 830.136.779-4
+... 830003564-7
+... 830005997 - 1
+... 830005997-1
+... 830006404-0
+... 830008686-1
+... 830009783-0
+... 830074184-5
+... 830096513-1
+... 830097607-8
+... 830113831-0
+... 830125132-2
+... 830130800-4
+... 844.003.225-6
+... 844.003.392-8
+... 860 001 986-1
+... 860.001.986-1
+... 860.002.134-8
+... 860.002.184-6
+... 860.006.606-0
+... 860.007.331-5
+... 860.007.336-1
+... 860.013.433-2
+... 860.013.570-3
+... 860.013.798-5
+... 860.020.309-6
+... 860.033.941-8
+... 860.045.904-7
+... 860.051.784-4
+... 860.065.795-6
+... 860.066.942-7
+... 860.400.538-7
+... 860.400.602-0
+... 860.402.717-8
+... 860.511.071-6
+... 860.516.636-1
+... 860.527.857-8
+... 860001986-1
+... 8600019861
+... 860002183 - 9
+... 860002183-9
+... 860002503 - 2
+... 860002503-2
+... 860002527-9
+... 860002528 - 6
+... 860002964-4
+... 860006606-0
+... 860007331-5
+... 8600073361
+... 860007379-8
+... 860009174-4
+... 860011153 - 6
+... 860011153-6
+... 860013433-2
+... 860013816 - 1
+... 860013816-1
+... 860022137-5
+... 860027404 - 1
+... 860027404-1
+... 860028415 - 5
+... 860066942-7
+... 860503617 - 3
+... 860512237-6
+... 890 981 268 -— 4
+... 890 981 268 — 4
+... 890.000.062-6
+... 890.000.381-0
+... 890.101.994-9
+... 890.102.002-2
+... 890.102.044-1
+... 890.106.291-2
+... 890.201.213-4
+... 890.201.578-7
+... 890.270.275-5
+... 890.303.093-5
+... 890.304.033-8
+... 890.399.025-6
+... 890.480.023-7
+... 890.480.110-1
+... 890.500.516-3
+... 890.500.675-6
+... 890.680.023-5
+... 890.700.148-4
+... 890.700.679-3
+... 890.806.490-5
+... 890.900.840-1
+... 890.900.841-9
+... 890.907.106-5
+... 890000062-6
+... 890000381-0
+... 890102044-1
+... 890303093-5
+... 890480110-1
+... 890680023-5
+... 890704737-0
+... 890900840-1
+... 890900842-6
+... 8909009431
+... 890904996-1
+... 891.080.005-1
+... 891.180.008-2
+... 891.190.047-2
+... 891.190.346-1
+... 891.200.208-6
+... 891.200.337-8
+... 891.380.056-4
+... 891.400.726-8
+... 891.411.166-0
+... 891.480.000-1
+... 891.480.035-9
+... 891.500.182-0
+... 891.600.091-8
+... 891.780.093-3
+... 891.800.213-8
+... 891.856.077-3
+... 891.900.280-0
+... 891.900.452-0
+... 891280008-1
+... 891380003-4
+... 891480000-1
+... 891500182-0
+... 891900280-0
+... 891900452-0
+... 892.115.006-5
+... 892.200.015-5
+... 892.399.989-8
+... 892.400.320-5
+... 899.999.035-7
+... 899999001-7
+... 899999010-3
+... 899999026-0
+... 899999034-1
+... 899999054-7
+... 899999239-2
+... 899999734-7
+... 900 206 480 - 2
+... 900 206 480-2
+... 900 206 483-4
+... 900,206,480-2
+... 900,206,483-4
+... 900.006.334-7
+... 900.018.436-1
+... 900.086.865-8
+... 900.141.702-1
+... 900.187.401-8
+... 900.206,483-4
+... 900.206.480-2
+... 900.206.483-4
+... 900.274.326-6
+... 900.311.121-2
+... 900.320.056-1
+... 900.323.466—1
+... 900.343.302-6
+... 900.433.479-7
+... 900.465.924-0
+... 900.499.432-5
+... 900074992-3
+... 900112778-7
+... 900156264-2
+... 900206480-2
+... 900206483-4
+... 900219251-9
+... 900227140-3
+... 9002271403
+... 900264507-1
+... 900299795-5
+... 900336004-7
+... 900356846-7
+... 900462447-5
+... 900812264-7
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not nit.is_valid(x)]
+[]

http://arthurdejong.org/git/python-stdnum/commit/?id=d413f953b848bd67e0f5267d3649d26e20d7c04b

commit d413f953b848bd67e0f5267d3649d26e20d7c04b
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Oct 2 21:13:41 2015 +0200

    Fix comment

diff --git a/stdnum/isbn.py b/stdnum/isbn.py
index 2bc2b6e..a49d9d7 100644
--- a/stdnum/isbn.py
+++ b/stdnum/isbn.py
@@ -137,7 +137,7 @@ def to_isbn10(number):
     number = number.strip()
     min_number = compact(number, convert=False)
     if len(min_number) == 10:
-        return number  # nothing to do, already ISBN-13
+        return number  # nothing to do, already ISBN-10
     elif isbn_type(min_number) != 'ISBN13':
         raise InvalidFormat('Not a valid ISBN13.')
     elif not number.startswith('978'):

http://arthurdejong.org/git/python-stdnum/commit/?id=3d1dbbb9c24e377374341e489e62edb1dfc5f360

commit 3d1dbbb9c24e377374341e489e62edb1dfc5f360
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Oct 2 16:41:56 2015 +0200

    Use zip() instead of enumerate()
    
    Makes the code slightly simpler and more compact.

diff --git a/stdnum/ar/cuit.py b/stdnum/ar/cuit.py
index 78e81aa..fb6bf83 100644
--- a/stdnum/ar/cuit.py
+++ b/stdnum/ar/cuit.py
@@ -56,7 +56,7 @@ def compact(number):
 def calc_check_digit(number):
     """Calculate the check digit."""
     weights = (5, 4, 3, 2, 7, 6, 5, 4, 3, 2)
-    check = sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    check = sum(w * int(n) for w, n in zip(weights, number)) % 11
     return '012345678990'[11 - check]
 
 
diff --git a/stdnum/bg/egn.py b/stdnum/bg/egn.py
index 7f94946..5aa007b 100644
--- a/stdnum/bg/egn.py
+++ b/stdnum/bg/egn.py
@@ -1,7 +1,7 @@
 # egn.py - functions for handling Bulgarian national identification numbers
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -57,7 +57,7 @@ def calc_check_digit(number):
     """Calculate the check digit. The number passed should not have the
     check digit included."""
     weights = (2, 4, 8, 5, 10, 9, 7, 3, 6)
-    return str(sum(weights[i] * int(n) for i, n in enumerate(number)) % 11 % 
10)
+    return str(sum(w * int(n) for w, n in zip(weights, number)) % 11 % 10)
 
 
 def get_birth_date(number):
diff --git a/stdnum/bg/pnf.py b/stdnum/bg/pnf.py
index bddfb2b..0f2eb64 100644
--- a/stdnum/bg/pnf.py
+++ b/stdnum/bg/pnf.py
@@ -1,7 +1,7 @@
 # pnf.py - functions for handling Bulgarian personal number of a foreigner
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -49,7 +49,7 @@ def calc_check_digit(number):
     """Calculate the check digit. The number passed should not have the
     check digit included."""
     weights = (21, 19, 17, 13, 11, 9, 7, 3, 1)
-    return str(sum(weights[i] * int(n) for i, n in enumerate(number)) % 10)
+    return str(sum(w * int(n) for w, n in zip(weights, number)) % 10)
 
 
 def validate(number):
diff --git a/stdnum/bg/vat.py b/stdnum/bg/vat.py
index f00e0da..757c48a 100644
--- a/stdnum/bg/vat.py
+++ b/stdnum/bg/vat.py
@@ -1,7 +1,7 @@
 # vat.py - functions for handling Bulgarian VAT numbers
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -61,7 +61,7 @@ def calc_check_digit_other(number):
     """Calculate the check digit for others. The number passed should not
     have the check digit included."""
     weights = (4, 3, 2, 7, 6, 5, 4, 3, 2)
-    return str((11 - sum(weights[i] * int(n) for i, n in enumerate(number))) % 
11)
+    return str((11 - sum(w * int(n) for w, n in zip(weights, number))) % 11)
 
 
 def validate(number):
diff --git a/stdnum/co/nit.py b/stdnum/co/nit.py
index 3b4ec08..6884ce3 100644
--- a/stdnum/co/nit.py
+++ b/stdnum/co/nit.py
@@ -59,8 +59,8 @@ def calc_check_digit(number):
     """Calculate the check digit. The number passed should not have the
     check digit included."""
     weights = (3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67, 71)
-    s = sum(int(n) * weights[i] for i, n in enumerate(number[::-1]))
-    return '01987654321'[s % 11]
+    s = sum(w * int(n) for w, n in zip(weights, reversed(number))) % 11
+    return '01987654321'[s]
 
 
 def validate(number):
diff --git a/stdnum/dk/cpr.py b/stdnum/dk/cpr.py
index 456be21..4bf4a44 100644
--- a/stdnum/dk/cpr.py
+++ b/stdnum/dk/cpr.py
@@ -1,6 +1,6 @@
 # cpr.py - functions for handling Danish CPR numbers
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -59,7 +59,7 @@ def checksum(number):
     """Calculate the checksum. Note that the checksum isn't actually used
     any more. Valid numbers used to have a checksum of 0."""
     weights = (4, 3, 2, 7, 6, 5, 4, 3, 2, 1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    return sum(w * int(n) for w, n in zip(weights, number)) % 11
 
 
 def get_birth_date(number):
diff --git a/stdnum/dk/cvr.py b/stdnum/dk/cvr.py
index 7ded1ac..3088c40 100644
--- a/stdnum/dk/cvr.py
+++ b/stdnum/dk/cvr.py
@@ -1,6 +1,6 @@
 # cvr.py - functions for handling Danish CVR numbers
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -46,7 +46,7 @@ def compact(number):
 def checksum(number):
     """Calculate the checksum."""
     weights = (2, 7, 6, 5, 4, 3, 2, 1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    return sum(w * int(n) for w, n in zip(weights, number)) % 11
 
 
 def validate(number):
diff --git a/stdnum/do/rnc.py b/stdnum/do/rnc.py
index 4134ad5..dce10e6 100644
--- a/stdnum/do/rnc.py
+++ b/stdnum/do/rnc.py
@@ -49,7 +49,7 @@ def compact(number):
 def calc_check_digit(number):
     """Calculate the check digit."""
     weights = (7, 9, 8, 6, 5, 4, 3, 2)
-    check = sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    check = sum(w * int(n) for w, n in zip(weights, number)) % 11
     return str((10 - check) % 9 + 1)
 
 
diff --git a/stdnum/ec/ruc.py b/stdnum/ec/ruc.py
index 8887467..1312f77 100644
--- a/stdnum/ec/ruc.py
+++ b/stdnum/ec/ruc.py
@@ -2,7 +2,7 @@
 # coding: utf-8
 #
 # Copyright (C) 2014 Jonathan Finlay
-# Copyright (C) 2014 Arthur de Jong
+# Copyright (C) 2014-2015 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
@@ -49,7 +49,7 @@ compact = ci.compact
 
 def _checksum(number, weights):
     """Calculate a checksum over the number given the weights."""
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    return sum(w * int(n) for w, n in zip(weights, number)) % 11
 
 
 def validate(number):
diff --git a/stdnum/ee/kmkr.py b/stdnum/ee/kmkr.py
index 7a8dd30..4b098c4 100644
--- a/stdnum/ee/kmkr.py
+++ b/stdnum/ee/kmkr.py
@@ -1,7 +1,7 @@
 # kmkr.py - functions for handling Estonian VAT numbers
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -46,7 +46,7 @@ def compact(number):
 def checksum(number):
     """Calculate the checksum."""
     weights = (3, 7, 1, 3, 7, 1, 3, 7, 1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 10
+    return sum(w * int(n) for w, n in zip(weights, number)) % 10
 
 
 def validate(number):
diff --git a/stdnum/fi/alv.py b/stdnum/fi/alv.py
index ed9457c..832742c 100644
--- a/stdnum/fi/alv.py
+++ b/stdnum/fi/alv.py
@@ -1,7 +1,7 @@
 # vat.py - functions for handling Finnish VAT numbers
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -46,7 +46,7 @@ def compact(number):
 def checksum(number):
     """Calculate the checksum."""
     weights = (7, 9, 10, 5, 8, 4, 2, 1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    return sum(w * int(n) for w, n in zip(weights, number)) % 11
 
 
 def validate(number):
diff --git a/stdnum/gb/vat.py b/stdnum/gb/vat.py
index 1e93cc9..a4f5174 100644
--- a/stdnum/gb/vat.py
+++ b/stdnum/gb/vat.py
@@ -1,6 +1,6 @@
 # vat.py - functions for handling United Kingdom VAT numbers
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -52,7 +52,7 @@ def checksum(number):
     """Calculate the checksum. The checksum is only used for the 9 digits
     of the number and the result can either be 0 or 42."""
     weights = (8, 7, 6, 5, 4, 3, 2, 10, 1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 97
+    return sum(w * int(n) for w, n in zip(weights, number)) % 97
 
 
 def validate(number):
diff --git a/stdnum/hu/anum.py b/stdnum/hu/anum.py
index e6d9315..5504f46 100644
--- a/stdnum/hu/anum.py
+++ b/stdnum/hu/anum.py
@@ -1,7 +1,7 @@
 # anum.py - functions for handling Hungarian VAT numbers
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -47,7 +47,7 @@ def compact(number):
 def checksum(number):
     """Calculate the checksum. Valid numbers should have a checksum of 0."""
     weights = (9, 7, 3, 1, 9, 7, 3, 1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 10
+    return sum(w * int(n) for w, n in zip(weights, number)) % 10
 
 
 def validate(number):
diff --git a/stdnum/is_/kennitala.py b/stdnum/is_/kennitala.py
index 5ffb73f..55647eb 100644
--- a/stdnum/is_/kennitala.py
+++ b/stdnum/is_/kennitala.py
@@ -68,7 +68,7 @@ def compact(number):
 def checksum(number):
     """Calculate the checksum."""
     weights = (3, 2, 7, 6, 5, 4, 3, 2, 1, 0)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    return sum(w * int(n) for w, n in zip(weights, number)) % 11
 
 
 def validate(number):
diff --git a/stdnum/lv/pvn.py b/stdnum/lv/pvn.py
index 595e0b8..dbb3b00 100644
--- a/stdnum/lv/pvn.py
+++ b/stdnum/lv/pvn.py
@@ -1,7 +1,7 @@
 # pvn.py - functions for handling Latvian PVN (VAT) numbers
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -62,7 +62,7 @@ def compact(number):
 def checksum(number):
     """Calculate the checksum for legal entities."""
     weights = (9, 1, 4, 8, 3, 10, 2, 5, 7, 6, 1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    return sum(w * int(n) for w, n in zip(weights, number)) % 11
 
 
 def calc_check_digit_pers(number):
diff --git a/stdnum/mt/vat.py b/stdnum/mt/vat.py
index 197c9ca..357c8f2 100644
--- a/stdnum/mt/vat.py
+++ b/stdnum/mt/vat.py
@@ -1,6 +1,6 @@
 # vat.py - functions for handling Maltese VAT numbers
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -46,7 +46,7 @@ def compact(number):
 def checksum(number):
     """Calculate the checksum."""
     weights = (3, 4, 6, 7, 8, 9, 10, 1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 37
+    return sum(w * int(n) for w, n in zip(weights, number)) % 37
 
 
 def validate(number):
diff --git a/stdnum/no/orgnr.py b/stdnum/no/orgnr.py
index 6448186..993d9da 100644
--- a/stdnum/no/orgnr.py
+++ b/stdnum/no/orgnr.py
@@ -48,7 +48,7 @@ def compact(number):
 def checksum(number):
     """Calculate the checksum."""
     weights = (3, 2, 7, 6, 5, 4, 3, 2, 1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    return sum(w * int(n) for w, n in zip(weights, number)) % 11
 
 
 def validate(number):
diff --git a/stdnum/pl/nip.py b/stdnum/pl/nip.py
index 45e18da..8f8bd0f 100644
--- a/stdnum/pl/nip.py
+++ b/stdnum/pl/nip.py
@@ -1,6 +1,6 @@
 # nip.py - functions for handling Polish VAT numbers
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -48,7 +48,7 @@ def compact(number):
 def checksum(number):
     """Calculate the checksum."""
     weights = (6, 5, 7, 2, 3, 4, 5, 6, 7, -1)
-    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    return sum(w * int(n) for w, n in zip(weights, number)) % 11
 
 
 def validate(number):
diff --git a/stdnum/pl/pesel.py b/stdnum/pl/pesel.py
index 4fcb490..0f5901d 100644
--- a/stdnum/pl/pesel.py
+++ b/stdnum/pl/pesel.py
@@ -92,7 +92,7 @@ def calc_check_digit(number):
     """Calculate the check digit for organisations. The number passed
     should not have the check digit included."""
     weights = (1, 3, 7, 9, 1, 3, 7, 9, 1, 3)
-    check = sum(weights[i] * int(n) for i, n in enumerate(number))
+    check = sum(w * int(n) for w, n in zip(weights, number))
     return str((10 - check) % 10)
 
 
diff --git a/stdnum/pl/regon.py b/stdnum/pl/regon.py
index 5099b55..ac8cffb 100644
--- a/stdnum/pl/regon.py
+++ b/stdnum/pl/regon.py
@@ -67,7 +67,7 @@ def calc_check_digit(number):
         weights = (8, 9, 2, 3, 4, 5, 6, 7)
     else:
         weights = (2, 4, 8, 5, 0, 9, 7, 3, 6, 1, 2, 4, 8)
-    check = sum(weights[i] * int(n) for i, n in enumerate(number))
+    check = sum(w * int(n) for w, n in zip(weights, number))
     return str(check % 11 % 10)
 
 
diff --git a/stdnum/ro/cf.py b/stdnum/ro/cf.py
index a27f980..c953c25 100644
--- a/stdnum/ro/cf.py
+++ b/stdnum/ro/cf.py
@@ -1,7 +1,7 @@
 # cf.py - functions for handling Romanian CF (VAT) numbers
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -51,7 +51,7 @@ def calc_check_digit(number):
     should not have the check digit included."""
     weights = (7, 5, 3, 2, 1, 7, 5, 3, 2)
     number = (9 - len(number)) * '0' + number
-    check = 10 * sum(weights[i] * int(n) for i, n in enumerate(number))
+    check = 10 * sum(w * int(n) for w, n in zip(weights, number))
     return str(check % 11 % 10)
 
 
diff --git a/stdnum/ro/cnp.py b/stdnum/ro/cnp.py
index bb57172..ad27149 100644
--- a/stdnum/ro/cnp.py
+++ b/stdnum/ro/cnp.py
@@ -1,7 +1,7 @@
 # cnp.py - functions for handling Romanian CNP numbers
 # coding: utf-8
 #
-# Copyright (C) 2012, 2013 Arthur de Jong
+# Copyright (C) 2012-2015 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
@@ -56,7 +56,7 @@ def calc_check_digit(number):
     should not have the check digit included."""
     # note that this algorithm has not been confirmed by an independent source
     weights = (2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9)
-    check = sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
+    check = sum(w * int(n) for w, n in zip(weights, number)) % 11
     return '1' if check == 10 else str(check)
 
 

http://arthurdejong.org/git/python-stdnum/commit/?id=222a87ef324f66baf8113020b41d336c459ab847

commit 222a87ef324f66baf8113020b41d336c459ab847
Author: Sergio Isidoro <sergio@holvi.com>
Date:   Thu Oct 1 14:14:49 2015 +0300

    Add alias to hetu in for finnish personal id code

diff --git a/stdnum/fi/__init__.py b/stdnum/fi/__init__.py
index 54f89b9..eab8d0d 100644
--- a/stdnum/fi/__init__.py
+++ b/stdnum/fi/__init__.py
@@ -23,3 +23,4 @@
 # provide vat as an alias
 from stdnum.fi import alv as vat
 from stdnum.fi import ytunnus as businessid
+from stdnum.fi import hetu as personalid

http://arthurdejong.org/git/python-stdnum/commit/?id=e045c710ae59d0c74c690c5bfe2111b43738aa45

commit e045c710ae59d0c74c690c5bfe2111b43738aa45
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Sep 27 12:45:19 2015 +0200

    Add more numbers found online

diff --git a/tests/test_eu_vat.doctest b/tests/test_eu_vat.doctest
index 098dfd1..ce10efd 100644
--- a/tests/test_eu_vat.doctest
+++ b/tests/test_eu_vat.doctest
@@ -1,6 +1,6 @@
 test_eu_vat.doctest - more detailed doctests for the stdnum.eu.vat module
 
-Copyright (C) 2012, 2013 Arthur de Jong
+Copyright (C) 2012-2015 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
@@ -47,6 +47,7 @@ These have been found online and should all be valid numbers.
 ... ATU 65033803
 ... ATU 65034704
 ... ATU 65480455
+... ATU13585627
 ... ATU46080404
 ... ATU61195628
 ...
@@ -66,6 +67,7 @@ These have been found online and should all be valid numbers.
 ... BE 444.503.092
 ... BE 456.973.433
 ... BE 464 401 356
+... BE0428759497
 ... BE413562567
 ... BE697449992
 ...
@@ -80,6 +82,11 @@ These have been found online and should all be valid numbers.
 ... BG 200182590
 ... BG 200950556
 ... BG130544585
+... BG175074752
+... BG7111042925
+... BG7523169263
+... BG7542011030
+... BG8032056031
 ... Bg 200442771
 ...
 ... CY 10246672X
@@ -107,6 +114,10 @@ These have been found online and should all be valid 
numbers.
 ... CZ49620819
 ... CZ6306150004
 ...
+... DE - 113866163
+... DE - 231969187
+... DE - 265265318
+... DE - 267297673
 ... DE 118619592
 ... DE 125014955
 ... DE 129304291
@@ -122,10 +133,6 @@ These have been found online and should all be valid 
numbers.
 ... DE 811305931
 ... DE 813 11 38 75
 ... DE 813 184868
-... DE - 113866163
-... DE - 231969187
-... DE - 265265318
-... DE - 267297673
 ... DE119263782
 ... DE129390950
 ... DE136308783
@@ -384,11 +391,11 @@ These have been found online and should all be valid 
numbers.
 ... IE 9741812E
 ... IE 9742129V
 ... IE-9696131F
+... IE6433435IH
+... IE6433435OA
 ... IE6599001W
 ... IE8D79739I
 ... IE9Y71814N
-... IE6433435OA
-... IE6433435IH
 ...
 ... IT - 01404480202
 ... IT 0 0 6 1 8 2 8 0 4 9 9
@@ -541,18 +548,54 @@ These have been found online and should all be valid 
numbers.
 ... NL811705262B01
 ... NL813411786B01
 ...
+... PL 5211355116
 ... PL 5211754253
-... PL 5262987091
+... PL 5220205853
+... PL 5342152448
+... PL 5423074698
 ... PL 584-030-44-72
 ... PL 5840154038
 ... PL 5840304472
 ... PL 5860224115
 ... PL 6330005110
+... PL 645-000-67-50
+... PL 6651344956
 ... PL 6661913137
+... PL 6772320831
+... PL 6792831859
+... PL 6831810615
+... PL 6842599822
 ... PL 687-16-26-585
+... PL 7010098470
+... PL 7271676569
+... PL 764-23-05-489
+... PL 764-23-05-495
+... PL 764-23-05-503
+... PL 764-23-05-526
+... PL 764-23-05-549
+... PL 764-23-05-555
+... PL 764-23-05-578
+... PL 767-000-06-78
+... PL 767-13-25-342
+... PL 767-14-25-718
+... PL 767-14-47-329
+... PL 768-000-24-66
+... PL 7711598811
 ... PL 777 26 68 285
 ... PL 7780104605
 ... PL 7881154591
+... PL 7961373674
+... PL 8393173893
+... PL 851-020-66-96
+... PL 867-16-19-297
+... PL 8722342429
+... PL 8771130532
+... PL 8971772896
+... PL 8992708633
+... PL 9241826918
+... PL 9452174677
+... PL 9462485048
+... PL 9542705026
 ... PL 9562197426
 ... PL-7532365958
 ... PL-951-157-77-68

-----------------------------------------------------------------------

Summary of changes:
 stdnum/ar/cuit.py             |    2 +-
 stdnum/bg/egn.py              |    4 +-
 stdnum/bg/pnf.py              |    4 +-
 stdnum/bg/vat.py              |    4 +-
 stdnum/co/nit.py              |   33 +--
 stdnum/dk/cpr.py              |    4 +-
 stdnum/dk/cvr.py              |    4 +-
 stdnum/do/rnc.py              |    2 +-
 stdnum/ec/ruc.py              |    4 +-
 stdnum/ee/kmkr.py             |    4 +-
 stdnum/eu/vat.py              |    7 +-
 stdnum/fi/__init__.py         |    1 +
 stdnum/fi/alv.py              |    4 +-
 stdnum/gb/vat.py              |    4 +-
 stdnum/hu/anum.py             |    4 +-
 stdnum/is_/kennitala.py       |    2 +-
 stdnum/isbn.py                |    2 +-
 stdnum/lv/pvn.py              |    4 +-
 stdnum/mt/vat.py              |    4 +-
 stdnum/{al => mx}/__init__.py |    6 +-
 stdnum/mx/rfc.py              |  150 ++++++++++++
 stdnum/no/orgnr.py            |    2 +-
 stdnum/pl/nip.py              |    4 +-
 stdnum/pl/pesel.py            |    2 +-
 stdnum/pl/regon.py            |    2 +-
 stdnum/ro/cf.py               |    4 +-
 stdnum/ro/cnp.py              |    4 +-
 stdnum/util.py                |   21 +-
 tests/test_co_nit.doctest     |  298 +++++++++++++++++++++++
 tests/test_eu_vat.doctest     |   59 ++++-
 tests/test_mx_rfc.doctest     |  531 +++++++++++++++++++++++++++++++++++++++++
 31 files changed, 1105 insertions(+), 75 deletions(-)
 copy stdnum/{al => mx}/__init__.py (87%)
 create mode 100644 stdnum/mx/rfc.py
 create mode 100644 tests/test_co_nit.doctest
 create mode 100644 tests/test_mx_rfc.doctest


hooks/post-receive
-- 
python-stdnum
-- 
To unsubscribe send an email to
python-stdnum-commits-unsubscribe@lists.arthurdejong.org or see
http://lists.arthurdejong.org/python-stdnum-commits/